diff options
Diffstat (limited to 'editor')
38 files changed, 724 insertions, 338 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index a163490cfb..285cea7d0a 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -2466,6 +2466,7 @@ void AnimationTrackEdit::update_play_position() { void AnimationTrackEdit::set_root(Node *p_root) { root = p_root; } + void AnimationTrackEdit::_zoom_changed() { update(); play_position->update(); @@ -3305,6 +3306,7 @@ Ref<Animation> AnimationTrackEditor::get_current_animation() const { return animation; } + void AnimationTrackEditor::_root_removed(Node *p_root) { root = NULL; } @@ -3400,15 +3402,14 @@ void AnimationTrackEditor::_track_remove_request(int p_track) { int idx = p_track; if (idx >= 0 && idx < animation->get_track_count()) { - selection.clear(); - _clear_key_edit(); - //all will be updated after remove anyway, and triggering update here raises error on tracks already removed undo_redo->create_action(TTR("Remove Anim Track")); + undo_redo->add_do_method(this, "_clear_selection", false); undo_redo->add_do_method(animation.ptr(), "remove_track", idx); undo_redo->add_undo_method(animation.ptr(), "add_track", animation->track_get_type(idx), idx); undo_redo->add_undo_method(animation.ptr(), "track_set_path", idx, animation->track_get_path(idx)); - //todo interpolation + + // TODO interpolation. for (int i = 0; i < animation->track_get_key_count(idx); i++) { Variant v = animation->track_get_key_value(idx, i); @@ -3491,7 +3492,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { case Variant::QUAT: case Variant::PLANE: case Variant::COLOR: { - //good + // Valid. } break; default: { all_bezier = false; @@ -3954,7 +3955,9 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo bool created = false; if (p_id.track_idx < 0) { - if (p_create_beziers && (p_id.value.get_type() == Variant::VECTOR2 || + if (p_create_beziers && (p_id.value.get_type() == Variant::INT || + p_id.value.get_type() == Variant::REAL || + p_id.value.get_type() == Variant::VECTOR2 || p_id.value.get_type() == Variant::VECTOR3 || p_id.value.get_type() == Variant::QUAT || p_id.value.get_type() == Variant::COLOR || @@ -3977,10 +3980,10 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE; if (p_id.type == Animation::TYPE_VALUE || p_id.type == Animation::TYPE_BEZIER) { - //wants a new tack + // Wants a new track. { - //hack + // Hack. NodePath np; animation->add_track(p_id.type); animation->track_set_path(animation->get_track_count() - 1, p_id.path); @@ -4034,7 +4037,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo Dictionary d; d["location"] = tr.origin; d["scale"] = tr.basis.get_scale(); - d["rotation"] = Quat(tr.basis); //.orthonormalized(); + d["rotation"] = Quat(tr.basis); value = d; } break; case Animation::TYPE_BEZIER: { @@ -4059,7 +4062,8 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo if (created) { - //just remove the track + // Just remove the track. + undo_redo->add_undo_method(this, "_clear_selection", false); undo_redo->add_undo_method(animation.ptr(), "remove_track", p_last_track); p_last_track++; } else { @@ -4079,6 +4083,8 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo } void AnimationTrackEditor::show_select_node_warning(bool p_show) { + + info_message->set_visible(p_show); } bool AnimationTrackEditor::is_key_selected(int p_track, int p_key) const { @@ -4661,6 +4667,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { undo_redo->create_action(TTR("Add Track Key")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, value); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs); undo_redo->commit_action(); @@ -4868,11 +4875,16 @@ void AnimationTrackEditor::_clear_key_edit() { } } -void AnimationTrackEditor::_clear_selection() { +void AnimationTrackEditor::_clear_selection(bool p_update) { + selection.clear(); - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); + + if (p_update) { + for (int i = 0; i < track_edits.size(); i++) { + track_edits[i]->update(); + } } + _clear_key_edit(); } @@ -5543,7 +5555,6 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->commit_action(); - //selection.clear(); _update_key_edit(); } } break; @@ -5794,6 +5805,14 @@ AnimationTrackEditor::AnimationTrackEditor() { timeline_vbox->set_h_size_flags(SIZE_EXPAND_FILL); timeline_vbox->add_constant_override("separation", 0); + info_message = memnew(Label); + info_message->set_text(TTR("Select an AnimationPlayer node to create and edit animations.")); + info_message->set_valign(Label::VALIGN_CENTER); + info_message->set_align(Label::ALIGN_CENTER); + info_message->set_autowrap(true); + info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + main_panel->add_child(info_message); + timeline = memnew(AnimationTimelineEdit); timeline->set_undo_redo(undo_redo); timeline_vbox->add_child(timeline); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 96fd10effd..830d5b52d3 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -304,6 +304,8 @@ class AnimationTrackEditor : public VBoxContainer { VBoxContainer *track_vbox; AnimationBezierTrackEdit *bezier_edit; + Label *info_message; + AnimationTimelineEdit *timeline; HSlider *zoom; EditorSpinSlider *step; @@ -385,7 +387,7 @@ class AnimationTrackEditor : public VBoxContainer { void _insert_key_from_track(float p_ofs, int p_track); void _add_method_key(const String &p_method); - void _clear_selection(); + void _clear_selection(bool p_update = false); void _clear_selection_for_anim(const Ref<Animation> &p_anim); void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos); diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp index 1bb49a4167..e38171eef9 100644 --- a/editor/collada/collada.cpp +++ b/editor/collada/collada.cpp @@ -616,7 +616,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String & if (colorarr.size() >= 3) { - // alpha strangely not allright? maybe it needs to be multiplied by value as a channel intensity + // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity Color color(colorarr[0], colorarr[1], colorarr[2], 1.0); if (what == "diffuse") effect.diffuse.color = color; @@ -854,7 +854,7 @@ void Collada::_parse_light(XMLParser &parser) { COLLADA_PRINT("colorarr size: " + rtos(colorarr.size())); if (colorarr.size() >= 4) { - // alpha strangely not allright? maybe it needs to be multiplied by value as a channel intensity + // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity Color color(colorarr[0], colorarr[1], colorarr[2], 1.0); light.color = color; } @@ -2297,7 +2297,7 @@ bool Collada::_optimize_skeletons(VisualScene *p_vscene, Node *p_node) { //replace parent by this... Node *parent = node->parent; - //i wonder if this is allright.. i think it is since created skeleton (first joint) is already animated by bone.. + //i wonder if this is alright.. i think it is since created skeleton (first joint) is already animated by bone.. node->id = parent->id; node->name = parent->name; node->xform_list = parent->xform_list; diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index c5b81c4685..cfc2ec11cf 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -529,7 +529,7 @@ void ConnectionsDock::_make_or_edit_connection() { // Pick up args here before "it" is deleted by update_tree. script_function_args = it->get_metadata(0).operator Dictionary()["args"]; for (int i = 0; i < cToMake.binds.size(); i++) { - script_function_args.append("extra_arg_" + itos(i)); + script_function_args.append("extra_arg_" + itos(i) + ":" + Variant::get_type_name(cToMake.binds[i].get_type())); } } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index a76d34e122..8d5858a10d 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1046,9 +1046,9 @@ void EditorInspectorSection::_notification(int p_what) { if (foldable) { if (object->editor_is_section_unfolded(section)) { - arrow = get_icon("arrow_up", "Tree"); - } else { arrow = get_icon("arrow", "Tree"); + } else { + arrow = get_icon("arrow_collapsed", "Tree"); } } @@ -1087,9 +1087,9 @@ void EditorInspectorSection::_notification(int p_what) { if (foldable) { if (object->editor_is_section_unfolded(section)) { - arrow = get_icon("arrow_up", "Tree"); - } else { arrow = get_icon("arrow", "Tree"); + } else { + arrow = get_icon("arrow_collapsed", "Tree"); } } @@ -1103,13 +1103,12 @@ void EditorInspectorSection::_notification(int p_what) { draw_rect(Rect2(Vector2(), Vector2(get_size().width, h)), bg_color); - int hs = get_constant("hseparation", "Tree"); - + const int arrow_margin = 3; Color color = get_color("font_color", "Tree"); - draw_string(font, Point2(hs, font->get_ascent() + (h - font->get_height()) / 2).floor(), label, color, get_size().width); + draw_string(font, Point2(Math::round((16 + arrow_margin) * EDSCALE), font->get_ascent() + (h - font->get_height()) / 2).floor(), label, color, get_size().width); if (arrow.is_valid()) { - draw_texture(arrow, Point2(get_size().width - arrow->get_width(), (h - arrow->get_height()) / 2).floor()); + draw_texture(arrow, Point2(Math::round(arrow_margin * EDSCALE), (h - arrow->get_height()) / 2).floor()); } } } diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index b5cdc76115..5474f86c74 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -113,6 +113,10 @@ void EditorLog::add_message(const String &p_msg, MessageType p_type) { log->add_text(" "); tool_button->set_icon(icon); } break; + case MSG_TYPE_EDITOR: { + // Distinguish editor messages from messages printed by the project + log->push_color(get_color("font_color", "Editor") * Color(1, 1, 1, 0.6)); + } break; } log->add_text(p_msg); @@ -128,7 +132,7 @@ void EditorLog::set_tool_button(ToolButton *p_tool_button) { void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) { EditorLog *self = (EditorLog *)p_self; - self->add_message(p_name); + self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR); } void EditorLog::_bind_methods() { diff --git a/editor/editor_log.h b/editor/editor_log.h index bb56bd34fe..10561b9c83 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -74,7 +74,8 @@ public: enum MessageType { MSG_TYPE_STD, MSG_TYPE_ERROR, - MSG_TYPE_WARNING + MSG_TYPE_WARNING, + MSG_TYPE_EDITOR }; void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD); diff --git a/editor/editor_network_profiler.cpp b/editor/editor_network_profiler.cpp new file mode 100644 index 0000000000..8482c4e38a --- /dev/null +++ b/editor/editor_network_profiler.cpp @@ -0,0 +1,211 @@ +/*************************************************************************/ +/* editor_network_profiler.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_network_profiler.h" + +#include "core/os/os.h" +#include "editor_scale.h" +#include "editor_settings.h" + +void EditorNetworkProfiler::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_frame"), &EditorNetworkProfiler::_update_frame); + ClassDB::bind_method(D_METHOD("_activate_pressed"), &EditorNetworkProfiler::_activate_pressed); + ClassDB::bind_method(D_METHOD("_clear_pressed"), &EditorNetworkProfiler::_clear_pressed); + ADD_SIGNAL(MethodInfo("enable_profiling", PropertyInfo(Variant::BOOL, "enable"))); +} + +void EditorNetworkProfiler::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + activate->set_icon(get_icon("Play", "EditorIcons")); + clear_button->set_icon(get_icon("Clear", "EditorIcons")); + incoming_bandwidth_text->set_right_icon(get_icon("ArrowDown", "EditorIcons")); + outgoing_bandwidth_text->set_right_icon(get_icon("ArrowUp", "EditorIcons")); + + // This needs to be done here to set the faded color when the profiler is first opened + incoming_bandwidth_text->add_color_override("font_color_uneditable", get_color("font_color", "Editor") * Color(1, 1, 1, 0.5)); + outgoing_bandwidth_text->add_color_override("font_color_uneditable", get_color("font_color", "Editor") * Color(1, 1, 1, 0.5)); + } +} + +void EditorNetworkProfiler::_update_frame() { + + counters_display->clear(); + + TreeItem *root = counters_display->create_item(); + + for (Map<ObjectID, MultiplayerAPI::ProfilingInfo>::Element *E = nodes_data.front(); E; E = E->next()) { + + TreeItem *node = counters_display->create_item(root); + + for (int j = 0; j < counters_display->get_columns(); ++j) { + node->set_text_align(j, j > 0 ? TreeItem::ALIGN_RIGHT : TreeItem::ALIGN_LEFT); + } + + node->set_text(0, E->get().node_path); + node->set_text(1, E->get().incoming_rpc == 0 ? "-" : itos(E->get().incoming_rpc)); + node->set_text(2, E->get().incoming_rset == 0 ? "-" : itos(E->get().incoming_rset)); + node->set_text(3, E->get().outgoing_rpc == 0 ? "-" : itos(E->get().outgoing_rpc)); + node->set_text(4, E->get().outgoing_rset == 0 ? "-" : itos(E->get().outgoing_rset)); + } +} + +void EditorNetworkProfiler::_activate_pressed() { + + if (activate->is_pressed()) { + activate->set_icon(get_icon("Stop", "EditorIcons")); + activate->set_text(TTR("Stop")); + } else { + activate->set_icon(get_icon("Play", "EditorIcons")); + activate->set_text(TTR("Start")); + } + emit_signal("enable_profiling", activate->is_pressed()); +} + +void EditorNetworkProfiler::_clear_pressed() { + nodes_data.clear(); + set_bandwidth(0, 0); + if (frame_delay->is_stopped()) { + frame_delay->set_wait_time(0.1); + frame_delay->start(); + } +} + +void EditorNetworkProfiler::add_node_frame_data(const MultiplayerAPI::ProfilingInfo p_frame) { + + if (!nodes_data.has(p_frame.node)) { + nodes_data.insert(p_frame.node, p_frame); + } else { + nodes_data[p_frame.node].incoming_rpc += p_frame.incoming_rpc; + nodes_data[p_frame.node].incoming_rset += p_frame.incoming_rset; + nodes_data[p_frame.node].outgoing_rpc += p_frame.outgoing_rpc; + nodes_data[p_frame.node].outgoing_rset += p_frame.outgoing_rset; + } + + if (frame_delay->is_stopped()) { + frame_delay->set_wait_time(0.1); + frame_delay->start(); + } +} + +void EditorNetworkProfiler::set_bandwidth(int p_incoming, int p_outgoing) { + + incoming_bandwidth_text->set_text(vformat(TTR("%s/s"), String::humanize_size(p_incoming))); + outgoing_bandwidth_text->set_text(vformat(TTR("%s/s"), String::humanize_size(p_outgoing))); + + // Make labels more prominent when the bandwidth is greater than 0 to attract user attention + incoming_bandwidth_text->add_color_override( + "font_color_uneditable", + get_color("font_color", "Editor") * Color(1, 1, 1, p_incoming > 0 ? 1 : 0.5)); + outgoing_bandwidth_text->add_color_override( + "font_color_uneditable", + get_color("font_color", "Editor") * Color(1, 1, 1, p_outgoing > 0 ? 1 : 0.5)); +} + +bool EditorNetworkProfiler::is_profiling() { + return activate->is_pressed(); +} + +EditorNetworkProfiler::EditorNetworkProfiler() { + + HBoxContainer *hb = memnew(HBoxContainer); + hb->add_constant_override("separation", 8 * EDSCALE); + add_child(hb); + + activate = memnew(Button); + activate->set_toggle_mode(true); + activate->set_text(TTR("Start")); + activate->connect("pressed", this, "_activate_pressed"); + hb->add_child(activate); + + clear_button = memnew(Button); + clear_button->set_text(TTR("Clear")); + clear_button->connect("pressed", this, "_clear_pressed"); + hb->add_child(clear_button); + + hb->add_spacer(); + + Label *lb = memnew(Label); + lb->set_text(TTR("Down")); + hb->add_child(lb); + + incoming_bandwidth_text = memnew(LineEdit); + incoming_bandwidth_text->set_editable(false); + incoming_bandwidth_text->set_custom_minimum_size(Size2(120, 0) * EDSCALE); + incoming_bandwidth_text->set_align(LineEdit::Align::ALIGN_RIGHT); + hb->add_child(incoming_bandwidth_text); + + Control *down_up_spacer = memnew(Control); + down_up_spacer->set_custom_minimum_size(Size2(30, 0) * EDSCALE); + hb->add_child(down_up_spacer); + + lb = memnew(Label); + lb->set_text(TTR("Up")); + hb->add_child(lb); + + outgoing_bandwidth_text = memnew(LineEdit); + outgoing_bandwidth_text->set_editable(false); + outgoing_bandwidth_text->set_custom_minimum_size(Size2(120, 0) * EDSCALE); + outgoing_bandwidth_text->set_align(LineEdit::Align::ALIGN_RIGHT); + hb->add_child(outgoing_bandwidth_text); + + // Set initial texts in the incoming/outgoing bandwidth labels + set_bandwidth(0, 0); + + counters_display = memnew(Tree); + counters_display->set_custom_minimum_size(Size2(300, 0) * EDSCALE); + counters_display->set_v_size_flags(SIZE_EXPAND_FILL); + counters_display->set_hide_folding(true); + counters_display->set_hide_root(true); + counters_display->set_columns(5); + counters_display->set_column_titles_visible(true); + counters_display->set_column_title(0, TTR("Node")); + counters_display->set_column_expand(0, true); + counters_display->set_column_min_width(0, 60 * EDSCALE); + counters_display->set_column_title(1, TTR("Incoming RPC")); + counters_display->set_column_expand(1, false); + counters_display->set_column_min_width(1, 120 * EDSCALE); + counters_display->set_column_title(2, TTR("Incoming RSET")); + counters_display->set_column_expand(2, false); + counters_display->set_column_min_width(2, 120 * EDSCALE); + counters_display->set_column_title(3, TTR("Outgoing RPC")); + counters_display->set_column_expand(3, false); + counters_display->set_column_min_width(3, 120 * EDSCALE); + counters_display->set_column_title(4, TTR("Outgoing RSET")); + counters_display->set_column_expand(4, false); + counters_display->set_column_min_width(4, 120 * EDSCALE); + add_child(counters_display); + + frame_delay = memnew(Timer); + frame_delay->set_wait_time(0.1); + frame_delay->set_one_shot(true); + add_child(frame_delay); + frame_delay->connect("timeout", this, "_update_frame"); +} diff --git a/editor/editor_network_profiler.h b/editor/editor_network_profiler.h new file mode 100644 index 0000000000..85fec340fd --- /dev/null +++ b/editor/editor_network_profiler.h @@ -0,0 +1,72 @@ +/*************************************************************************/ +/* editor_network_profiler.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITORNETWORKPROFILER_H +#define EDITORNETWORKPROFILER_H + +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/split_container.h" +#include "scene/gui/tree.h" + +class EditorNetworkProfiler : public VBoxContainer { + + GDCLASS(EditorNetworkProfiler, VBoxContainer) + +private: + Button *activate; + Button *clear_button; + Tree *counters_display; + LineEdit *incoming_bandwidth_text; + LineEdit *outgoing_bandwidth_text; + + Timer *frame_delay; + + Map<ObjectID, MultiplayerAPI::ProfilingInfo> nodes_data; + + void _update_frame(); + + void _activate_pressed(); + void _clear_pressed(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void add_node_frame_data(const MultiplayerAPI::ProfilingInfo p_frame); + void set_bandwidth(int p_incoming, int p_outgoing); + bool is_profiling(); + + EditorNetworkProfiler(); +}; + +#endif //EDITORNETWORKPROFILER_H diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index a1998a1d7c..1d22de7679 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2212,27 +2212,27 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case EDIT_UNDO: { if (Input::get_singleton()->get_mouse_button_mask() & 0x7) { - log->add_message("Can't UNDO while mouse buttons are pressed."); + log->add_message("Can't undo while mouse buttons are pressed.", EditorLog::MSG_TYPE_EDITOR); } else { String action = editor_data.get_undo_redo().get_current_action_name(); if (!editor_data.get_undo_redo().undo()) { - log->add_message("There is nothing to UNDO."); + log->add_message("Nothing to undo.", EditorLog::MSG_TYPE_EDITOR); } else if (action != "") { - log->add_message("UNDO: " + action); + log->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR); } } } break; case EDIT_REDO: { if (Input::get_singleton()->get_mouse_button_mask() & 0x7) { - log->add_message("Can't REDO while mouse buttons are pressed."); + log->add_message("Can't redo while mouse buttons are pressed.", EditorLog::MSG_TYPE_EDITOR); } else { if (!editor_data.get_undo_redo().redo()) { - log->add_message("There is nothing to REDO."); + log->add_message("Nothing to redo.", EditorLog::MSG_TYPE_EDITOR); } else { String action = editor_data.get_undo_redo().get_current_action_name(); - log->add_message("REDO: " + action); + log->add_message("Redo: " + action, EditorLog::MSG_TYPE_EDITOR); } } } break; diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index 23d28261d1..12510e27de 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -78,9 +78,6 @@ void EditorPath::_about_to_show() { } void EditorPath::update_path() { - set_text(""); - set_tooltip(""); - set_icon(NULL); for (int i = 0; i < history->get_path_size(); i++) { diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 5c15ebb1eb..77e9220b6d 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -116,7 +116,7 @@ void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Textur uint64_t modified_time = 0; if (p_str.begins_with("ID:")) { - hash = p_str.get_slicec(':', 2).to_int(); + hash = uint32_t(p_str.get_slicec(':', 2).to_int64()); path = "ID:" + p_str.get_slicec(':', 1); } else { modified_time = FileAccess::get_modified_time(path); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index e29e44caa2..42c55681ae 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -685,12 +685,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Tree theme->set_icon("checked", "Tree", theme->get_icon("GuiChecked", "EditorIcons")); theme->set_icon("unchecked", "Tree", theme->get_icon("GuiUnchecked", "EditorIcons")); - theme->set_icon("arrow_up", "Tree", theme->get_icon("GuiTreeArrowUp", "EditorIcons")); theme->set_icon("arrow", "Tree", theme->get_icon("GuiTreeArrowDown", "EditorIcons")); theme->set_icon("arrow_collapsed", "Tree", theme->get_icon("GuiTreeArrowRight", "EditorIcons")); theme->set_icon("updown", "Tree", theme->get_icon("GuiTreeUpdown", "EditorIcons")); theme->set_icon("select_arrow", "Tree", theme->get_icon("GuiDropdown", "EditorIcons")); - theme->set_icon("select_option", "Tree", theme->get_icon("GuiTreeOption", "EditorIcons")); theme->set_stylebox("bg_focus", "Tree", style_focus); theme->set_stylebox("custom_button", "Tree", make_empty_stylebox()); theme->set_stylebox("custom_button_pressed", "Tree", make_empty_stylebox()); @@ -704,7 +702,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("drop_position_color", "Tree", accent_color); theme->set_constant("vseparation", "Tree", (extra_spacing + default_margin_size) * EDSCALE); theme->set_constant("hseparation", "Tree", (extra_spacing + default_margin_size) * EDSCALE); - theme->set_constant("guide_width", "Tree", border_width); theme->set_constant("item_margin", "Tree", 3 * default_margin_size * EDSCALE); theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE); theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01); @@ -717,6 +714,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_tree_btn->set_border_width_all(0); theme->set_stylebox("button_pressed", "Tree", style_tree_btn); + Ref<StyleBoxFlat> style_tree_hover = style_default->duplicate(); + style_tree_hover->set_bg_color(highlight_color * Color(1, 1, 1, 0.4)); + style_tree_hover->set_border_width_all(0); + theme->set_stylebox("hover", "Tree", style_tree_hover); + Ref<StyleBoxFlat> style_tree_focus = style_default->duplicate(); style_tree_focus->set_bg_color(highlight_color); style_tree_focus->set_border_width_all(0); diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 536cfaa1dd..202b554be4 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -562,10 +562,8 @@ bool ExportTemplateManager::can_install_android_template() { Error ExportTemplateManager::install_android_template() { - // To support custom Android builds, we install various things to the project's res://android folder. - // First is the Java source code and buildsystem from android_source.zip. - // Then we extract the Godot Android libraries from pre-build android_release.apk - // and android_debug.apk, to place them in the libs folder. + // To support custom Android builds, we install the Java source code and buildsystem + // from android_source.zip to the project's res://android folder. DirAccessRef da = DirAccess::open("res://"); ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); @@ -661,89 +659,6 @@ Error ExportTemplateManager::install_android_template() { ProgressDialog::get_singleton()->end_task("uncompress_src"); unzClose(pkg); - // Extract libs from pre-built APKs. - err = _extract_libs_from_apk("release"); - ERR_FAIL_COND_V_MSG(err != OK, err, "Can't extract Android libs from android_release.apk."); - err = _extract_libs_from_apk("debug"); - ERR_FAIL_COND_V_MSG(err != OK, err, "Can't extract Android libs from android_debug.apk."); - - return OK; -} - -Error ExportTemplateManager::_extract_libs_from_apk(const String &p_target_name) { - - const String &templates_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); - const String &apk_file = templates_path.plus_file("android_" + p_target_name + ".apk"); - ERR_FAIL_COND_V(!FileAccess::exists(apk_file), ERR_CANT_OPEN); - - FileAccess *src_f = NULL; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - - unzFile pkg = unzOpen2(apk_file.utf8().get_data(), &io); - ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android APK can't be extracted."); - - DirAccessRef da = DirAccess::open("res://"); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); - - // 8 steps because 4 arches, 2 libs per arch. - ProgressDialog::get_singleton()->add_task("extract_libs_from_apk", TTR("Extracting Android Libraries From APKs"), 8); - - int ret = unzGoToFirstFile(pkg); - Set<String> dirs_tested; - int idx = 0; - while (ret == UNZ_OK) { - // Get file path. - unz_file_info info; - char fpath[16384]; - ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, NULL, 0, NULL, 0); - - String path = fpath; - String base_dir = path.get_base_dir(); - String file = path.get_file(); - - if (!base_dir.begins_with("lib") || path.ends_with("/")) { - ret = unzGoToNextFile(pkg); - continue; - } - - Vector<uint8_t> data; - data.resize(info.uncompressed_size); - - // Read. - unzOpenCurrentFile(pkg); - unzReadCurrentFile(pkg, data.ptrw(), data.size()); - unzCloseCurrentFile(pkg); - - // We have a "lib" folder in the APK, but it should be "libs/{release,debug}" in the source dir. - String target_base_dir = base_dir.replace_first("lib", String("libs").plus_file(p_target_name)); - - if (!dirs_tested.has(base_dir)) { - da->make_dir_recursive(String("android/build").plus_file(target_base_dir)); - dirs_tested.insert(base_dir); - } - - String to_write = String("res://android/build").plus_file(target_base_dir.plus_file(path.get_file())); - FileAccess *f = FileAccess::open(to_write, FileAccess::WRITE); - if (f) { - f->store_buffer(data.ptr(), data.size()); - memdelete(f); -#ifndef WINDOWS_ENABLED - // We can't retrieve Unix permissions from the APK it seems, so simply set 0755 as should be. - FileAccess::set_unix_permissions(to_write, 0755); -#endif - } else { - ERR_PRINTS("Can't uncompress file: " + to_write); - } - - ProgressDialog::get_singleton()->task_step("extract_libs_from_apk", path, idx); - - idx++; - ret = unzGoToNextFile(pkg); - } - - ProgressDialog::get_singleton()->end_task("extract_libs_from_apk"); - unzClose(pkg); - return OK; } diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h index ecb8e85b21..ad3ab507b3 100644 --- a/editor/export_template_manager.h +++ b/editor/export_template_manager.h @@ -72,8 +72,6 @@ class ExportTemplateManager : public ConfirmationDialog { virtual void ok_pressed(); bool _install_from_file(const String &p_file, bool p_use_progress = true); - Error _extract_libs_from_apk(const String &p_target_name); - void _http_download_mirror_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); void _http_download_templates_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); diff --git a/editor/icons/icon_GUI_tree_option.svg b/editor/icons/icon_GUI_tree_option.svg deleted file mode 100644 index 4200745a78..0000000000 --- a/editor/icons/icon_GUI_tree_option.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="14" height="14" version="1.1" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1038.4)"> -<path transform="translate(0 1038.4)" d="m7.5 1a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5 -1.5 1.5 1.5 0 0 0 -1.5 -1.5zm0 5a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5 -1.5 1.5 1.5 0 0 0 -1.5 -1.5zm0 5a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5 -1.5 1.5 1.5 0 0 0 -1.5 -1.5z" fill="#fff" fill-opacity=".58824" stroke-linejoin="round" stroke-opacity=".39216" stroke-width="2"/> -</g> -</svg> diff --git a/editor/icons/icon_arrow_down.svg b/editor/icons/icon_arrow_down.svg new file mode 100644 index 0000000000..49a93e6e28 --- /dev/null +++ b/editor/icons/icon_arrow_down.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3.002a1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l2.293 2.293h-4.5859c-.55228 0-1 .4477-1 1s.44772 1 1 1h4.5859l-2.293 2.293a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l4-4a1.0001 1.0001 0 0 0 0-1.4141l-4-4a1 1 0 0 0 -.7207-.29102z" fill="#e0e0e0" fill-opacity=".99608" transform="matrix(0 1 -1 0 16.0021 -.00004)"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_arrow_up.svg b/editor/icons/icon_arrow_up.svg index 77a20e8c50..9bf19a6a12 100644 --- a/editor/icons/icon_arrow_up.svg +++ b/editor/icons/icon_arrow_up.svg @@ -1,5 +1 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path d="m2.9875 1044.4a1.0001 1.0001 0 0 0 1.7168 0.6972l2.293-2.2929v4.5859a1.0001 1.0001 0 1 0 2 0v-4.5859l2.293 2.2929a1.0001 1.0001 0 1 0 1.4141 -1.414l-3.9141-3.9141a1.0001 1.0001 0 0 0 -1.5859 0 1.0001 1.0001 0 0 0 -0.00391 0.01l-3.9102 3.9102a1.0001 1.0001 0 0 0 -0.30273 0.7168z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#e0e0e0" fill-opacity=".99608" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> -</g> -</svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.00008 1049.4022a1 1 0 0 0 .69336-.291 1 1 0 0 0 0-1.4141l-2.293-2.293h4.5859c.55228 0 1-.4477 1-1s-.44772-1-1-1h-4.5859l2.293-2.293a1 1 0 0 0 0-1.4141 1 1 0 0 0 -1.4141 0l-4 4a1.0001 1.0001 0 0 0 0 1.4141l4 4a1 1 0 0 0 .7207.291z" fill="#e0e0e0" fill-opacity=".99608" transform="matrix(0 1 -1 0 1052.4021 -.00004)"/></svg>
\ No newline at end of file diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 6918fe7977..1d72e370b3 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -132,6 +132,7 @@ void ImportDock::set_edit_path(const String &p_path) { params->paths.push_back(p_path); import->set_disabled(false); import_as->set_disabled(false); + preset->set_disabled(false); imported->set_text(p_path.get_file()); } @@ -287,6 +288,7 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) { params->paths = p_paths; import->set_disabled(false); import_as->set_disabled(false); + preset->set_disabled(false); imported->set_text(itos(p_paths.size()) + TTR(" Files")); } @@ -367,6 +369,7 @@ void ImportDock::clear() { import->set_disabled(true); import_as->clear(); import_as->set_disabled(true); + preset->set_disabled(true); params->values.clear(); params->properties.clear(); params->update(); @@ -528,11 +531,13 @@ ImportDock::ImportDock() { HBoxContainer *hb = memnew(HBoxContainer); add_margin_child(TTR("Import As:"), hb); import_as = memnew(OptionButton); + import_as->set_disabled(true); import_as->connect("item_selected", this, "_importer_selected"); hb->add_child(import_as); import_as->set_h_size_flags(SIZE_EXPAND_FILL); preset = memnew(MenuButton); - preset->set_text(TTR("Preset...")); + preset->set_text(TTR("Preset")); + preset->set_disabled(true); preset->get_popup()->connect("index_pressed", this, "_preset_selected"); hb->add_child(preset); @@ -545,6 +550,7 @@ ImportDock::ImportDock() { add_child(hb); import = memnew(Button); import->set_text(TTR("Reimport")); + import->set_disabled(true); import->connect("pressed", this, "_reimport_attempt"); hb->add_spacer(); hb->add_child(import); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 173079b6de..d7451849a1 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -38,7 +38,7 @@ #include "editor/animation_track_editor.h" #include "editor/editor_settings.h" -// For onion skinning +// For onion skinning. #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/spatial_editor_plugin.h" #include "scene/main/viewport.h" @@ -690,8 +690,10 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { if (p_state.has("animation")) { String anim = p_state["animation"]; - _select_anim_by_name(anim); - _animation_edit(); + if (!anim.empty() && player->has_animation(anim)) { + _select_anim_by_name(anim); + _animation_edit(); + } } } } @@ -1088,20 +1090,6 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) EditorNode::get_singleton()->get_inspector()->refresh(); } -void AnimationPlayerEditor::_hide_anim_editors() { - - player = NULL; - hide(); - set_process(false); - - track_editor->set_animation(Ref<Animation>()); - track_editor->set_root(NULL); - track_editor->show_select_node_warning(true); -} - -void AnimationPlayerEditor::_animation_about_to_show_menu() { -} - void AnimationPlayerEditor::_animation_tool_menu(int p_option) { String current; @@ -1489,7 +1477,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { player->seek(cpos, false); player->restore_animated_values(values_backup); - // Restor state of main editors. + // Restore state of main editors. if (SpatialEditor::get_singleton()->is_visible()) { // 3D SpatialEditor::get_singleton()->set_state(spatial_edit_state); @@ -1519,7 +1507,7 @@ void AnimationPlayerEditor::_stop_onion_skinning() { _free_onion_layers(); - // Clean up the overlay + // Clean up the overlay. onion.can_overlay = false; plugin->update_overlays(); } @@ -1557,7 +1545,6 @@ void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_list_changed"), &AnimationPlayerEditor::_list_changed); ClassDB::bind_method(D_METHOD("_animation_key_editor_seek"), &AnimationPlayerEditor::_animation_key_editor_seek); ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_len_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_len_changed); - ClassDB::bind_method(D_METHOD("_hide_anim_editors"), &AnimationPlayerEditor::_hide_anim_editors); ClassDB::bind_method(D_METHOD("_animation_duplicate"), &AnimationPlayerEditor::_animation_duplicate); ClassDB::bind_method(D_METHOD("_blend_editor_next_changed"), &AnimationPlayerEditor::_blend_editor_next_changed); ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &AnimationPlayerEditor::_unhandled_key_input); @@ -1776,7 +1763,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay _update_player(); - // Onion skinning + // Onion skinning. track_editor->connect("visibility_changed", this, "_editor_visibility_changed"); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 4ad30675ec..eed7344395 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -130,9 +130,9 @@ class AnimationPlayerEditor : public VBoxContainer { AnimationTrackEditor *track_editor; - // Onion skinning + // Onion skinning. struct { - // Settings + // Settings. bool enabled; bool past; bool future; @@ -142,11 +142,11 @@ class AnimationPlayerEditor : public VBoxContainer { bool include_gizmos; int get_needed_capture_count() const { - // 'Differences only' needs a capture of the present + // 'Differences only' needs a capture of the present. return (past && future ? 2 * steps : steps) + (differences_only ? 1 : 0); } - // Rendering + // Rendering. int64_t last_frame; int can_overlay; Size2 capture_size; @@ -195,8 +195,6 @@ class AnimationPlayerEditor : public VBoxContainer { void _update_player(); void _blend_edited(); - void _hide_anim_editors(); - void _animation_player_changed(Object *p_pl); void _animation_key_editor_seek(float p_pos, bool p_drag); @@ -205,7 +203,6 @@ class AnimationPlayerEditor : public VBoxContainer { void _unhandled_key_input(const Ref<InputEvent> &p_ev); void _animation_tool_menu(int p_option); void _onion_skinning_menu(int p_option); - void _animation_about_to_show_menu(); void _editor_visibility_changed(); bool _are_onion_layers_valid(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index e4cd71fec0..6f612b5c79 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3678,7 +3678,6 @@ void CanvasItemEditor::_notification(int p_what) { key_auto_insert_button->set_icon(get_icon("AutoKey", "EditorIcons")); zoom_minus->set_icon(get_icon("ZoomLess", "EditorIcons")); - zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); zoom_plus->set_icon(get_icon("ZoomMore", "EditorIcons")); presets_menu->set_icon(get_icon("ControlLayout", "EditorIcons")); @@ -4036,9 +4035,22 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) { view_offset.x = Math::round(view_offset.x + ofs.x); view_offset.y = Math::round(view_offset.y + ofs.y); + _update_zoom_label(); update_viewport(); } +void CanvasItemEditor::_update_zoom_label() { + String zoom_text; + if (zoom >= 10) { + // Don't show a decimal when the zoom level is higher than 1000 % + zoom_text = rtos(Math::round(zoom * 100)) + " %"; + } else { + zoom_text = rtos(Math::stepify(zoom * 100, 0.1)) + " %"; + } + + zoom_reset->set_text(zoom_text); +} + void CanvasItemEditor::_button_zoom_minus() { _zoom_on_position(zoom / Math_SQRT2, viewport_scrollable->get_size() / 2.0); } @@ -4811,6 +4823,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { Dictionary state = p_state; if (state.has("zoom")) { zoom = p_state["zoom"]; + _update_zoom_label(); } if (state.has("ofs")) { @@ -5128,6 +5141,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { zoom_hb = memnew(HBoxContainer); viewport->add_child(zoom_hb); zoom_hb->set_begin(Point2(5, 5)); + // Bring the zoom percentage closer to the zoom buttons + zoom_hb->add_constant_override("separation", Math::round(-8 * EDSCALE)); zoom_minus = memnew(ToolButton); zoom_hb->add_child(zoom_minus); @@ -5140,6 +5155,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { zoom_reset->connect("pressed", this, "_button_zoom_reset"); zoom_reset->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", TTR("Zoom Reset"), KEY_MASK_CMD | KEY_0)); zoom_reset->set_focus_mode(FOCUS_NONE); + zoom_reset->set_text_align(Button::TextAlign::ALIGN_CENTER); + // Prevent the button's size from changing when the text size changes + zoom_reset->set_custom_minimum_size(Size2(75 * EDSCALE, 0)); zoom_plus = memnew(ToolButton); zoom_hb->add_child(zoom_plus); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 4e030c63da..6cce1ca10e 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -525,6 +525,7 @@ private: HBoxContainer *zoom_hb; void _zoom_on_position(float p_zoom, Point2 p_position = Point2()); + void _update_zoom_label(); void _button_zoom_minus(); void _button_zoom_reset(); void _button_zoom_plus(); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 8b6bab374c..f79c9d5062 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -538,9 +538,13 @@ void ScriptEditor::_open_recent_script(int p_idx) { // if it's a path then it's most likely a deleted file not help } else if (path.find("::") != -1) { // built-in script - String scene_path = path.get_slice("::", 0); - if (!EditorNode::get_singleton()->is_scene_open(scene_path)) { - EditorNode::get_singleton()->load_scene(scene_path); + String res_path = path.get_slice("::", 0); + if (ResourceLoader::get_resource_type(res_path) == "PackedScene") { + if (!EditorNode::get_singleton()->is_scene_open(res_path)) { + EditorNode::get_singleton()->load_scene(res_path); + } + } else { + EditorNode::get_singleton()->load_resource(res_path); } Ref<Script> script = ResourceLoader::load(path); if (script.is_valid()) { @@ -1028,12 +1032,16 @@ void ScriptEditor::_menu_option(int p_option) { if (extensions.find(path.get_extension()) || built_in) { if (built_in) { - String scene_path = path.get_slice("::", 0); - if (!EditorNode::get_singleton()->is_scene_open(scene_path)) { - EditorNode::get_singleton()->load_scene(scene_path); - script_editor->call_deferred("_menu_option", p_option); - previous_scripts.push_back(path); //repeat the operation - return; + String res_path = path.get_slice("::", 0); + if (ResourceLoader::get_resource_type(res_path) == "PackedScene") { + if (!EditorNode::get_singleton()->is_scene_open(res_path)) { + EditorNode::get_singleton()->load_scene(res_path); + script_editor->call_deferred("_menu_option", p_option); + previous_scripts.push_back(path); //repeat the operation + return; + } + } else { + EditorNode::get_singleton()->load_resource(res_path); } } @@ -3463,15 +3471,18 @@ void ScriptEditorPlugin::edit(Object *p_object) { if (Object::cast_to<Script>(p_object)) { Script *p_script = Object::cast_to<Script>(p_object); - String scene_path = p_script->get_path().get_slice("::", 0); - - if (_is_built_in_script(p_script) && !EditorNode::get_singleton()->is_scene_open(scene_path)) { - EditorNode::get_singleton()->load_scene(scene_path); + String res_path = p_script->get_path().get_slice("::", 0); - script_editor->call_deferred("edit", p_script); - } else { - script_editor->edit(p_script); + if (_is_built_in_script(p_script)) { + if (ResourceLoader::get_resource_type(res_path) == "PackedScene") { + if (!EditorNode::get_singleton()->is_scene_open(res_path)) { + EditorNode::get_singleton()->load_scene(res_path); + } + } else { + EditorNode::get_singleton()->load_resource(res_path); + } } + script_editor->edit(p_script); } else if (Object::cast_to<TextFile>(p_object)) { script_editor->edit(Object::cast_to<TextFile>(p_object)); } diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index ecc631d045..18049e62b4 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -5186,7 +5186,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() { // The maximum height an object can travel to be snapped const float max_snap_height = 20.0; - // Will be set to `true` if at least one node from the selection was sucessfully snapped + // Will be set to `true` if at least one node from the selection was successfully snapped bool snapped_to_floor = false; if (keys.size()) { diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 4d349f06b7..21eebf9ca2 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -625,9 +625,12 @@ void TextureRegionEditor::_update_rect() { rect = node_sprite->get_region_rect(); else if (node_sprite_3d) rect = node_sprite_3d->get_region_rect(); - else if (node_ninepatch) + else if (node_ninepatch) { rect = node_ninepatch->get_region_rect(); - else if (obj_styleBox.is_valid()) + if (rect == Rect2()) { + rect = Rect2(Vector2(), node_ninepatch->get_texture()->get_size()); + } + } else if (obj_styleBox.is_valid()) rect = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) rect = atlas_tex->get_region(); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 26fae96025..90276041a8 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -376,7 +376,7 @@ void TileMapEditor::_sbox_input(const Ref<InputEvent> &p_ie) { } // Implementation detail of TileMapEditor::_update_palette(); -// in modern C++ this could have been inside its body +// In modern C++ this could have been inside its body. namespace { struct _PaletteEntry { int id; @@ -393,10 +393,10 @@ void TileMapEditor::_update_palette() { if (!node) return; - // Update the clear button + // Update the clear button. clear_transform_button->set_disabled(!flip_h && !flip_v && !transpose); - // Update the palette + // Update the palette. Vector<int> selected = get_selected_tiles(); int selected_single = palette->get_current(); int selected_manual = manual_palette->get_current(); @@ -405,8 +405,15 @@ void TileMapEditor::_update_palette() { manual_palette->hide(); Ref<TileSet> tileset = node->get_tileset(); - if (tileset.is_null()) + if (tileset.is_null()) { + search_box->set_text(""); + search_box->set_editable(false); + info_message->show(); return; + } + + search_box->set_editable(true); + info_message->hide(); List<int> tiles; tileset->get_tile_list(&tiles); @@ -421,7 +428,6 @@ void TileMapEditor::_update_palette() { bool sort_by_name = bool(EDITOR_DEF("editors/tile_map/sort_tiles_by_name", true)); palette->add_constant_override("hseparation", hseparation * EDSCALE); - palette->add_constant_override("vseparation", 8 * EDSCALE); palette->set_fixed_icon_size(Size2(min_size, min_size)); palette->set_fixed_column_width(min_size * MAX(size_slider->get_value(), 1)); @@ -479,7 +485,7 @@ void TileMapEditor::_update_palette() { region.position += (region.size + Vector2(spacing, spacing)) * tileset->autotile_get_icon_coordinate(entries[i].id); } - // Transpose and flip + // Transpose and flip. palette->set_item_icon_transposed(palette->get_item_count() - 1, transpose); if (flip_h) { region.size.x = -region.size.x; @@ -488,14 +494,14 @@ void TileMapEditor::_update_palette() { region.size.y = -region.size.y; } - // Set region + // Set region. if (region.size != Size2()) palette->set_item_icon_region(palette->get_item_count() - 1, region); - // Set icon + // Set icon. palette->set_item_icon(palette->get_item_count() - 1, tex); - // Modulation + // Modulation. Color color = tileset->tile_get_modulate(entries[i].id); palette->set_item_icon_modulate(palette->get_item_count() - 1, color); } @@ -511,50 +517,47 @@ void TileMapEditor::_update_palette() { palette->select(0); } - if (sel_tile != TileMap::INVALID_CELL) { - if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || - (!priority_atlastile && tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE)) { + if (sel_tile != TileMap::INVALID_CELL && ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || (!priority_atlastile && tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE))) { - const Map<Vector2, uint32_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile); + const Map<Vector2, uint32_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile); - Vector<Vector2> entries2; - for (const Map<Vector2, uint32_t>::Element *E = tiles2.front(); E; E = E->next()) { - entries2.push_back(E->key()); + Vector<Vector2> entries2; + for (const Map<Vector2, uint32_t>::Element *E = tiles2.front(); E; E = E->next()) { + entries2.push_back(E->key()); + } + // Sort tiles in row-major order. + struct SwapComparator { + _FORCE_INLINE_ bool operator()(const Vector2 &v_l, const Vector2 &v_r) const { + return v_l.y != v_r.y ? v_l.y < v_r.y : v_l.x < v_r.x; } - // Sort tiles in row-major order - struct SwapComparator { - _FORCE_INLINE_ bool operator()(const Vector2 &v_l, const Vector2 &v_r) const { - return v_l.y != v_r.y ? v_l.y < v_r.y : v_l.x < v_r.x; - } - }; - entries2.sort_custom<SwapComparator>(); - - Ref<Texture> tex = tileset->tile_get_texture(sel_tile); + }; + entries2.sort_custom<SwapComparator>(); - for (int i = 0; i < entries2.size(); i++) { + Ref<Texture> tex = tileset->tile_get_texture(sel_tile); - manual_palette->add_item(String()); + for (int i = 0; i < entries2.size(); i++) { - if (tex.is_valid()) { + manual_palette->add_item(String()); - Rect2 region = tileset->tile_get_region(sel_tile); - int spacing = tileset->autotile_get_spacing(sel_tile); - region.size = tileset->autotile_get_size(sel_tile); // !! - region.position += (region.size + Vector2(spacing, spacing)) * entries2[i]; + if (tex.is_valid()) { - if (!region.has_no_area()) - manual_palette->set_item_icon_region(manual_palette->get_item_count() - 1, region); + Rect2 region = tileset->tile_get_region(sel_tile); + int spacing = tileset->autotile_get_spacing(sel_tile); + region.size = tileset->autotile_get_size(sel_tile); // !! + region.position += (region.size + Vector2(spacing, spacing)) * entries2[i]; - manual_palette->set_item_icon(manual_palette->get_item_count() - 1, tex); - } + if (!region.has_no_area()) + manual_palette->set_item_icon_region(manual_palette->get_item_count() - 1, region); - manual_palette->set_item_metadata(manual_palette->get_item_count() - 1, entries2[i]); + manual_palette->set_item_icon(manual_palette->get_item_count() - 1, tex); } + + manual_palette->set_item_metadata(manual_palette->get_item_count() - 1, entries2[i]); } } if (manual_palette->get_item_count() > 0) { - // Only show the manual palette if at least tile exists in it + // Only show the manual palette if at least tile exists in it. if (selected_manual == -1 || selected_single != palette->get_current()) selected_manual = 0; if (selected_manual < manual_palette->get_item_count()) @@ -1951,6 +1954,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { add_child(priority_button); search_box = memnew(LineEdit); + search_box->set_placeholder(TTR("Filter tiles")); search_box->set_h_size_flags(SIZE_EXPAND_FILL); search_box->connect("text_entered", this, "_text_entered"); search_box->connect("text_changed", this, "_text_changed"); @@ -1973,7 +1977,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { palette_container->set_custom_minimum_size(Size2(mw, 0)); add_child(palette_container); - // Add tile palette + // Add tile palette. palette = memnew(ItemList); palette->set_h_size_flags(SIZE_EXPAND_FILL); palette->set_v_size_flags(SIZE_EXPAND_FILL); @@ -1981,11 +1985,21 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { palette->set_icon_mode(ItemList::ICON_MODE_TOP); palette->set_max_text_lines(2); palette->set_select_mode(ItemList::SELECT_MULTI); + palette->add_constant_override("vseparation", 8 * EDSCALE); palette->connect("item_selected", this, "_palette_selected"); palette->connect("multi_selected", this, "_palette_multi_selected"); palette_container->add_child(palette); - // Add autotile override palette + // Add message for when no texture is selected. + info_message = memnew(Label); + info_message->set_text(TTR("Give a TileSet resource to this TileMap to use its tiles.")); + info_message->set_valign(Label::VALIGN_CENTER); + info_message->set_align(Label::ALIGN_CENTER); + info_message->set_autowrap(true); + info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + palette->add_child(info_message); + + // Add autotile override palette. manual_palette = memnew(ItemList); manual_palette->set_h_size_flags(SIZE_EXPAND_FILL); manual_palette->set_v_size_flags(SIZE_EXPAND_FILL); @@ -1995,15 +2009,14 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { manual_palette->hide(); palette_container->add_child(manual_palette); - // Add menu items + // Add menu items. toolbar = memnew(HBoxContainer); toolbar->hide(); CanvasItemEditor::get_singleton()->add_control_to_menu_panel(toolbar); - // Separator toolbar->add_child(memnew(VSeparator)); - // Tools + // Tools. paint_button = memnew(ToolButton); paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P)); paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Ctrl+LMB: Rectangle Paint")); @@ -2031,18 +2044,18 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { _update_button_tool(); - // Container to the right of the toolbar + // Container to the right of the toolbar. toolbar_right = memnew(HBoxContainer); toolbar_right->hide(); toolbar_right->set_h_size_flags(SIZE_EXPAND_FILL); toolbar_right->set_alignment(BoxContainer::ALIGN_END); CanvasItemEditor::get_singleton()->add_control_to_menu_panel(toolbar_right); - // Tile position + // Tile position. tile_info = memnew(Label); toolbar_right->add_child(tile_info); - // Menu + // Menu. options = memnew(MenuButton); options->set_text("TileMap"); options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("TileMap", "EditorIcons")); @@ -2136,7 +2149,8 @@ void TileMapEditorPlugin::make_visible(bool p_visible) { tile_map_editor->show(); tile_map_editor->get_toolbar()->show(); tile_map_editor->get_toolbar_right()->show(); - CanvasItemEditor::get_singleton()->set_current_tool(CanvasItemEditor::TOOL_SELECT); //Change to TOOL_SELECT when TileMap node is selected, to prevent accidental movement. + // Change to TOOL_SELECT when TileMap node is selected, to prevent accidental movement. + CanvasItemEditor::get_singleton()->set_current_tool(CanvasItemEditor::TOOL_SELECT); } else { tile_map_editor->hide(); diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index c841eb1f98..e3d678c2fd 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -82,6 +82,8 @@ class TileMapEditor : public VBoxContainer { ItemList *palette; ItemList *manual_palette; + Label *info_message; + HBoxContainer *toolbar; HBoxContainer *toolbar_right; diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 9096a0e0be..e0bf8dfdb2 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -579,6 +579,14 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { scroll->set_v_size_flags(SIZE_EXPAND_FILL); scroll->set_clip_contents(true); + empty_message = memnew(Label); + empty_message->set_text(TTR("Add or select a texture on the left panel to edit the tiles bound to it.")); + empty_message->set_valign(Label::VALIGN_CENTER); + empty_message->set_align(Label::ALIGN_CENTER); + empty_message->set_autowrap(true); + empty_message->set_v_size_flags(SIZE_EXPAND_FILL); + main_vb->add_child(empty_message); + workspace_container = memnew(Control); scroll->add_child(workspace_container); @@ -627,7 +635,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { helper = memnew(TilesetEditorContext(this)); tile_names_visible = false; - // config scale + // Config scale. max_scale = 10.0f; min_scale = 0.1f; scale_ratio = 1.2f; @@ -3123,12 +3131,28 @@ void TileSetEditor::update_workspace_tile_mode() { } tools[SELECT_NEXT]->set_disabled(true); tools[SELECT_PREVIOUS]->set_disabled(true); + + tools[ZOOM_OUT]->hide(); + tools[ZOOM_1]->hide(); + tools[ZOOM_IN]->hide(); + tools[VISIBLE_INFO]->hide(); + + scroll->hide(); + empty_message->show(); } else { for (int i = 1; i < WORKSPACE_MODE_MAX; i++) { tool_workspacemode[i]->set_disabled(false); } tools[SELECT_NEXT]->set_disabled(false); tools[SELECT_PREVIOUS]->set_disabled(false); + + tools[ZOOM_OUT]->show(); + tools[ZOOM_1]->show(); + tools[ZOOM_IN]->show(); + tools[VISIBLE_INFO]->show(); + + scroll->show(); + empty_message->hide(); } if (workspace_mode != WORKSPACE_EDIT) { diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index fff9ef7731..944dc04e4e 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -138,6 +138,7 @@ class TileSetEditor : public HSplitContainer { int current_item_index; Sprite *preview; ScrollContainer *scroll; + Label *empty_message; Control *workspace_container; bool draw_handles; Control *workspace_overlay; diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index c059977487..e8cd7692b6 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -59,14 +59,6 @@ void VersionControlEditorPlugin::_selected_a_vcs(int p_id) { List<StringName> available_addons = get_available_vcs_names(); const StringName selected_vcs = set_up_choice->get_item_text(p_id); - - if (available_addons.find(selected_vcs) != NULL) { - - set_up_init_button->set_disabled(false); - } else { - - set_up_init_button->set_disabled(true); - } } void VersionControlEditorPlugin::_populate_available_vcs_names() { @@ -75,9 +67,6 @@ void VersionControlEditorPlugin::_populate_available_vcs_names() { if (!called) { - set_up_choice->add_item("Select an available VCS"); - - fetch_available_vcs_addon_names(); List<StringName> available_addons = get_available_vcs_names(); for (int i = 0; i < available_addons.size(); i++) { @@ -95,19 +84,22 @@ VersionControlEditorPlugin *VersionControlEditorPlugin::get_singleton() { void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) { - Size2 popup_size = Size2(400, 100); - Size2 window_size = p_gui_base->get_viewport_rect().size; - popup_size.x = MIN(window_size.x * 0.5, popup_size.x); - popup_size.y = MIN(window_size.y * 0.5, popup_size.y); + fetch_available_vcs_addon_names(); + List<StringName> available_addons = get_available_vcs_names(); + if (available_addons.size() >= 1) { - if (get_is_vcs_intialized()) { + Size2 popup_size = Size2(400, 100); + Size2 window_size = p_gui_base->get_viewport_rect().size; + popup_size.x = MIN(window_size.x * 0.5, popup_size.x); + popup_size.y = MIN(window_size.y * 0.5, popup_size.y); - set_up_init_button->set_disabled(true); - } + _populate_available_vcs_names(); - _populate_available_vcs_names(); + set_up_dialog->popup_centered_clamped(popup_size * EDSCALE); + } else { - set_up_dialog->popup_centered_clamped(popup_size * EDSCALE); + EditorNode::get_singleton()->show_warning(TTR("No VCS addons are available."), TTR("Error")); + } } void VersionControlEditorPlugin::_initialize_vcs() { @@ -120,7 +112,7 @@ void VersionControlEditorPlugin::_initialize_vcs() { return; } - int id = set_up_choice->get_selected_id(); + const int id = set_up_choice->get_selected_id(); String selected_addon = set_up_choice->get_item_text(id); String path = ScriptServer::get_global_class_path(selected_addon); @@ -381,7 +373,19 @@ void VersionControlEditorPlugin::register_editor() { void VersionControlEditorPlugin::fetch_available_vcs_addon_names() { - ScriptServer::get_global_class_list(&available_addons); + List<StringName> global_classes; + ScriptServer::get_global_class_list(&global_classes); + + for (int i = 0; i != global_classes.size(); i++) { + + String path = ScriptServer::get_global_class_path(global_classes[i]); + Ref<Script> script = ResourceLoader::load(path); + + if (script->get_instance_base_type() == "EditorVCSInterface") { + + available_addons.push_back(global_classes[i]); + } + } } void VersionControlEditorPlugin::clear_stage_area() { @@ -427,7 +431,6 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { version_control_actions->add_child(set_up_dialog); set_up_ok_button = set_up_dialog->get_ok(); - set_up_ok_button->set_disabled(false); set_up_ok_button->set_text(TTR("Close")); set_up_vbc = memnew(VBoxContainer); @@ -454,7 +457,6 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { set_up_init_settings = NULL; set_up_init_button = memnew(Button); - set_up_init_button->set_disabled(true); set_up_init_button->set_text(TTR("Initialize")); set_up_init_button->connect("pressed", this, "_initialize_vcs"); set_up_vbc->add_child(set_up_init_button); @@ -564,7 +566,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { diff_heading = memnew(Label); diff_heading->set_text(TTR("Status")); - diff_heading->set_tooltip(TTR("View file diffs before commiting them to the latest version")); + diff_heading->set_tooltip(TTR("View file diffs before committing them to the latest version")); diff_hbc->add_child(diff_heading); diff_file_name = memnew(Label); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index c6e3dc1e32..701676a7f8 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -928,16 +928,36 @@ public: TextureButton *favorite_button; TextureRect *icon; bool icon_needs_reload; + bool hover; ProjectListItemControl() { favorite_button = NULL; icon = NULL; icon_needs_reload = true; + hover = false; } void set_is_favorite(bool fav) { favorite_button->set_modulate(fav ? Color(1, 1, 1, 1) : Color(1, 1, 1, 0.2)); } + + void _notification(int p_what) { + switch (p_what) { + case NOTIFICATION_MOUSE_ENTER: { + hover = true; + update(); + } break; + case NOTIFICATION_MOUSE_EXIT: { + hover = false; + update(); + } break; + case NOTIFICATION_DRAW: { + if (hover) { + draw_style_box(get_stylebox("hover", "Tree"), Rect2(Point2(), get_size() - Size2(10, 0) * EDSCALE)); + } + } break; + } + } }; class ProjectList : public ScrollContainer { @@ -1260,6 +1280,8 @@ void ProjectList::create_project_item_control(int p_index) { TextureButton *favorite = memnew(TextureButton); favorite->set_name("FavoriteButton"); favorite->set_normal_texture(favorite_icon); + // This makes the project's "hover" style display correctly when hovering the favorite icon + favorite->set_mouse_filter(MOUSE_FILTER_PASS); favorite->connect("pressed", this, "_favorite_pressed", varray(hb)); favorite_box->add_child(favorite); favorite_box->set_alignment(BoxContainer::ALIGN_CENTER); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index a0d2332ffc..f1e9420799 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -1310,7 +1310,7 @@ void ProjectSettingsEditor::_translation_res_option_delete(Object *p_item, int p void ProjectSettingsEditor::_translation_filter_option_changed() { int sel_id = translation_locale_filter_mode->get_selected_id(); - TreeItem *t = translation_filter->get_selected(); + TreeItem *t = translation_filter->get_edited(); String locale = t->get_tooltip(0); bool checked = t->is_checked(0); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 16f1575757..2ddf1f7056 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -759,8 +759,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { _delete_confirm(); } else { - if (remove_list.size() > 1) { + if (remove_list.size() >= 2) { delete_dialog->set_text(vformat(TTR("Delete %d nodes?"), remove_list.size())); + } else if (remove_list.size() == 1 && remove_list[0] == editor_data->get_edited_scene_root()) { + delete_dialog->set_text(vformat(TTR("Delete the root node \"%s\"?"), remove_list[0]->get_name())); + } else if (remove_list.size() == 1 && remove_list[0]->get_filename() == "" && remove_list[0]->get_child_count() >= 1) { + // Display this message only for non-instanced scenes + delete_dialog->set_text(vformat(TTR("Delete node \"%s\" and its children?"), remove_list[0]->get_name())); } else { delete_dialog->set_text(vformat(TTR("Delete node \"%s\"?"), remove_list[0]->get_name())); } @@ -1504,7 +1509,7 @@ bool SceneTreeDock::_validate_no_foreign() { // When edited_scene inherits from another one the root Node will be the parent Scene, // we don't want to consider that Node a foreign one otherwise we would not be able to - // delete it + // delete it. if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene == E->get()) { continue; } @@ -1528,7 +1533,7 @@ void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.empty()) - return; //nothing to reparent + return; // Nothing to reparent. Vector<Node *> nodes; @@ -1544,18 +1549,32 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V Node *new_parent = p_new_parent; ERR_FAIL_COND(!new_parent); + if (p_nodes.size() == 0) + return; // Nothing to reparent. + + p_nodes.sort_custom<Node::Comparator>(); //Makes result reliable. + + bool no_change = true; + for (int ni = 0; ni < p_nodes.size(); ni++) { + + if (p_nodes[ni] == p_new_parent) + return; // Attempt to reparent to itself. + + if (p_nodes[ni]->get_parent() != p_new_parent || p_position_in_parent + ni != p_nodes[ni]->get_position_in_parent()) + no_change = false; + } + + if (no_change) + return; // Position and parent didn't change. + Node *validate = new_parent; while (validate) { - ERR_FAIL_COND_MSG(p_nodes.find(validate) != -1, "Selection changed at some point.. can't reparent."); + ERR_FAIL_COND_MSG(p_nodes.find(validate) != -1, "Selection changed at some point. Can't reparent."); validate = validate->get_parent(); } - //ok all valid - - if (p_nodes.size() == 0) - return; //nothing to reparent - //sort by tree order, so re-adding is easy + // Sort by tree order, so re-adding is easy. p_nodes.sort_custom<Node::Comparator>(); editor_data->get_undo_redo().create_action(TTR("Reparent Node")); @@ -1567,7 +1586,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V for (int ni = 0; ni < p_nodes.size(); ni++) { - //no undo for now, sorry + // No undo implemented for this yet. Node *node = p_nodes[ni]; fill_path_renames(node, new_parent, &path_renames); @@ -1577,14 +1596,11 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V node->get_owned_by(node->get_owner(), &owned); Array owners; for (List<Node *>::Element *E = owned.front(); E; E = E->next()) { - owners.push_back(E->get()); } - if (new_parent == node->get_parent() && node->get_index() < p_position_in_parent + ni) { - //if child will generate a gap when moved, adjust - inc--; - } + if (new_parent == node->get_parent() && node->get_index() < p_position_in_parent + ni) + inc--; // If the child will generate a gap when moved, adjust. editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node); editor_data->get_undo_redo().add_do_method(new_parent, "add_child", node); @@ -1596,17 +1612,17 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V String old_name = former_names[ni]; String new_name = new_parent->validate_child_name(node); - // name was modified, fix the path renames + // Name was modified, fix the path renames. if (old_name.casecmp_to(new_name) != 0) { - // Fix the to name to have the new name + // Fix the to name to have the new name. NodePath old_new_name = path_renames[ni].second; NodePath new_path; Vector<StringName> unfixed_new_names = old_new_name.get_names(); Vector<StringName> fixed_new_names; - // Get last name and replace with fixed new name + // Get last name and replace with fixed new name. for (int a = 0; a < (unfixed_new_names.size() - 1); a++) { fixed_new_names.push_back(unfixed_new_names[a]); } @@ -1640,8 +1656,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V inc++; } - //add and move in a second step.. (so old order is preserved) - + // Add and move in a second step (so old order is preserved). for (int ni = 0; ni < p_nodes.size(); ni++) { Node *node = p_nodes[ni]; diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index a4270786c1..26ca3726f5 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -33,6 +33,7 @@ #include "core/io/marshalls.h" #include "core/project_settings.h" #include "core/ustring.h" +#include "editor_network_profiler.h" #include "editor_node.h" #include "editor_profiler.h" #include "editor_settings.h" @@ -992,7 +993,20 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da profiler->add_frame_metric(metric, false); else profiler->add_frame_metric(metric, true); - + } else if (p_msg == "network_profile") { + int frame_size = 6; + for (int i = 0; i < p_data.size(); i += frame_size) { + MultiplayerAPI::ProfilingInfo pi; + pi.node = p_data[i + 0]; + pi.node_path = p_data[i + 1]; + pi.incoming_rpc = p_data[i + 2]; + pi.incoming_rset = p_data[i + 3]; + pi.outgoing_rpc = p_data[i + 4]; + pi.outgoing_rset = p_data[i + 5]; + network_profiler->add_node_frame_data(pi); + } + } else if (p_msg == "network_bandwidth") { + network_profiler->set_bandwidth(p_data[0], p_data[1]); } else if (p_msg == "kill_me") { editor->call_deferred("stop_child_process"); @@ -1028,17 +1042,15 @@ void ScriptEditorDebugger::_performance_draw() { which.push_back(i); } - Ref<Font> graph_font = get_font("font", "TextEdit"); - if (which.empty()) { - String text = TTR("Pick one or more items from the list to display the graph."); - - perf_draw->draw_string(graph_font, Point2i(MAX(0, perf_draw->get_size().x - graph_font->get_string_size(text).x), perf_draw->get_size().y + graph_font->get_ascent()) / 2, text, get_color("font_color", "Label"), perf_draw->get_size().x); - + info_message->show(); return; } + info_message->hide(); + Ref<StyleBox> graph_sb = get_stylebox("normal", "TextEdit"); + Ref<Font> graph_font = get_font("font", "TextEdit"); int cols = Math::ceil(Math::sqrt((float)which.size())); int rows = Math::ceil((float)which.size() / cols); @@ -1107,7 +1119,6 @@ void ScriptEditorDebugger::_notification(int p_what) { forward->set_icon(get_icon("Forward", "EditorIcons")); dobreak->set_icon(get_icon("Pause", "EditorIcons")); docontinue->set_icon(get_icon("DebugContinue", "EditorIcons")); - //scene_tree_refresh->set_icon( get_icon("Reload","EditorIcons")); le_set->connect("pressed", this, "_live_edit_set"); le_clear->connect("pressed", this, "_live_edit_clear"); error_tree->connect("item_selected", this, "_error_selected"); @@ -1179,7 +1190,7 @@ void ScriptEditorDebugger::_notification(int p_what) { if (connection.is_null()) break; - EditorNode::get_log()->add_message("** Debug Process Started **"); + EditorNode::get_log()->add_message("--- Debugging process started ---", EditorLog::MSG_TYPE_EDITOR); ppeer->set_stream_peer(connection); @@ -1189,7 +1200,7 @@ void ScriptEditorDebugger::_notification(int p_what) { dobreak->set_disabled(false); tabs->set_current_tab(0); - _set_reason_text(TTR("Child Process Connected"), MESSAGE_SUCCESS); + _set_reason_text(TTR("Child process connected."), MESSAGE_SUCCESS); profiler->clear(); inspect_scene_tree->clear(); @@ -1208,6 +1219,10 @@ void ScriptEditorDebugger::_notification(int p_what) { if (profiler->is_profiling()) { _profiler_activate(true); } + + if (network_profiler->is_profiling()) { + _network_profiler_activate(true); + } } } @@ -1373,7 +1388,7 @@ void ScriptEditorDebugger::stop() { ppeer->set_stream_peer(Ref<StreamPeer>()); if (connection.is_valid()) { - EditorNode::get_log()->add_message("** Debug Process Stopped **"); + EditorNode::get_log()->add_message("--- Debugging process stopped ---", EditorLog::MSG_TYPE_EDITOR); connection.unref(); reason->set_text(""); @@ -1391,7 +1406,7 @@ void ScriptEditorDebugger::stop() { profiler->set_enabled(true); inspect_scene_tree->clear(); - EditorNode::get_singleton()->edit_current(); + inspector->edit(NULL); EditorNode::get_singleton()->get_pause_button()->set_pressed(false); EditorNode::get_singleton()->get_pause_button()->set_disabled(true); EditorNode::get_singleton()->get_scene_tree_dock()->hide_remote_tree(); @@ -1427,6 +1442,25 @@ void ScriptEditorDebugger::_profiler_activate(bool p_enable) { } } +void ScriptEditorDebugger::_network_profiler_activate(bool p_enable) { + + if (!connection.is_valid()) + return; + + if (p_enable) { + Array msg; + msg.push_back("start_network_profiling"); + ppeer->put_var(msg); + print_verbose("Starting network profiling."); + + } else { + Array msg; + msg.push_back("stop_network_profiling"); + ppeer->put_var(msg); + print_verbose("Ending network profiling."); + } +} + void ScriptEditorDebugger::_profiler_seeked() { if (!connection.is_valid() || !connection->is_connected_to_host()) @@ -2020,6 +2054,7 @@ void ScriptEditorDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("_expand_errors_list"), &ScriptEditorDebugger::_expand_errors_list); ClassDB::bind_method(D_METHOD("_collapse_errors_list"), &ScriptEditorDebugger::_collapse_errors_list); ClassDB::bind_method(D_METHOD("_profiler_activate"), &ScriptEditorDebugger::_profiler_activate); + ClassDB::bind_method(D_METHOD("_network_profiler_activate"), &ScriptEditorDebugger::_network_profiler_activate); ClassDB::bind_method(D_METHOD("_profiler_seeked"), &ScriptEditorDebugger::_profiler_seeked); ClassDB::bind_method(D_METHOD("_clear_errors_list"), &ScriptEditorDebugger::_clear_errors_list); @@ -2245,6 +2280,13 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { profiler->connect("break_request", this, "_profiler_seeked"); } + { //network profiler + network_profiler = memnew(EditorNetworkProfiler); + network_profiler->set_name(TTR("Network Profiler")); + tabs->add_child(network_profiler); + network_profiler->connect("enable_profiling", this, "_network_profiler_activate"); + } + { //monitors HSplitContainer *hsp = memnew(HSplitContainer); @@ -2254,11 +2296,14 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { perf_monitors->set_column_title(0, TTR("Monitor")); perf_monitors->set_column_title(1, TTR("Value")); perf_monitors->set_column_titles_visible(true); - hsp->add_child(perf_monitors); perf_monitors->connect("item_edited", this, "_performance_select"); + hsp->add_child(perf_monitors); + perf_draw = memnew(Control); + perf_draw->set_clip_contents(true); perf_draw->connect("draw", this, "_performance_draw"); hsp->add_child(perf_draw); + hsp->set_name(TTR("Monitors")); hsp->set_split_offset(340 * EDSCALE); tabs->add_child(hsp); @@ -2292,6 +2337,14 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { perf_items.push_back(it); perf_max.write[i] = 0; } + + info_message = memnew(Label); + info_message->set_text(TTR("Pick one or more items from the list to display the graph.")); + info_message->set_valign(Label::VALIGN_CENTER); + info_message->set_align(Label::ALIGN_CENTER); + info_message->set_autowrap(true); + info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + perf_draw->add_child(info_message); } { //vmem inspect @@ -2303,7 +2356,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { vmem_hb->add_child(memnew(Label(TTR("Total:") + " "))); vmem_total = memnew(LineEdit); vmem_total->set_editable(false); - vmem_total->set_custom_minimum_size(Size2(100, 1) * EDSCALE); + vmem_total->set_custom_minimum_size(Size2(100, 0) * EDSCALE); vmem_hb->add_child(vmem_total); vmem_refresh = memnew(ToolButton); vmem_hb->add_child(vmem_refresh); diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index dc9c99591d..cc284476c0 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -50,6 +50,7 @@ class TreeItem; class HSplitContainer; class ItemList; class EditorProfiler; +class EditorNetworkProfiler; class ScriptEditorDebuggerInspectedObject; @@ -134,6 +135,7 @@ class ScriptEditorDebugger : public Control { Tree *perf_monitors; Control *perf_draw; + Label *info_message; Tree *vmem_tree; Button *vmem_refresh; @@ -155,6 +157,7 @@ class ScriptEditorDebugger : public Control { Map<String, int> res_path_cache; EditorProfiler *profiler; + EditorNetworkProfiler *network_profiler; EditorNode *editor; @@ -199,6 +202,8 @@ class ScriptEditorDebugger : public Control { void _profiler_activate(bool p_enable); void _profiler_seeked(); + void _network_profiler_activate(bool p_enable); + void _paused(); void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj); diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index b4643231d7..c9c1f9c3e0 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -110,7 +110,7 @@ void EditorSettingsDialog::_filter_shortcuts(const String &p_filter) { } void EditorSettingsDialog::_undo_redo_callback(void *p_self, const String &p_name) { - EditorNode::get_log()->add_message(p_name); + EditorNode::get_log()->add_message(p_name, EditorLog::MSG_TYPE_EDITOR); } void EditorSettingsDialog::_notification(int p_what) { @@ -151,7 +151,7 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) { if (ED_IS_SHORTCUT("editor/undo", p_event)) { String action = undo_redo->get_current_action_name(); if (action != "") - EditorNode::get_log()->add_message("UNDO: " + action); + EditorNode::get_log()->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR); undo_redo->undo(); handled = true; } @@ -159,7 +159,7 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) { undo_redo->redo(); String action = undo_redo->get_current_action_name(); if (action != "") - EditorNode::get_log()->add_message("REDO: " + action); + EditorNode::get_log()->add_message("Redo: " + action, EditorLog::MSG_TYPE_EDITOR); handled = true; } diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 4c5371769f..27f3b28b49 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -783,9 +783,10 @@ Vector3 EditorSpatialGizmo::get_handle_pos(int p_idx) const { LightSpatialGizmoPlugin::LightSpatialGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/light", Color(1, 1, 0.2)); + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/light", Color(1, 1, 0.7)); - create_material("lines", gizmo_color); + create_material("lines_primary", gizmo_color); + create_material("lines_secondary", gizmo_color * Color(1, 1, 1, 0.35)); create_material("lines_billboard", gizmo_color, true); create_icon_material("light_directional_icon", SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons")); @@ -937,7 +938,7 @@ void LightSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { if (Object::cast_to<DirectionalLight>(light)) { - Ref<Material> material = get_material("lines", p_gizmo); + Ref<Material> material = get_material("lines_primary", p_gizmo); Ref<Material> icon = get_material("light_directional_icon", p_gizmo); const int arrow_points = 7; @@ -975,31 +976,39 @@ void LightSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { if (Object::cast_to<OmniLight>(light)) { - Ref<Material> material = get_material("lines_billboard", p_gizmo); - Ref<Material> icon = get_material("light_omni_icon", p_gizmo); + // Use both a billboard circle and 3 non-billboard circles for a better sphere-like representation + const Ref<Material> lines_material = get_material("lines_secondary", p_gizmo); + const Ref<Material> lines_billboard_material = get_material("lines_billboard", p_gizmo); + const Ref<Material> icon = get_material("light_omni_icon", p_gizmo); OmniLight *on = Object::cast_to<OmniLight>(light); - - float r = on->get_param(Light::PARAM_RANGE); - + const float r = on->get_param(Light::PARAM_RANGE); Vector<Vector3> points; + Vector<Vector3> points_billboard; - for (int i = 0; i <= 360; i++) { + for (int i = 0; i < 120; i++) { - float ra = Math::deg2rad((float)i); - float rb = Math::deg2rad((float)i + 1); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; + // Create a circle + const float ra = Math::deg2rad((float)(i * 3)); + const float rb = Math::deg2rad((float)((i + 1) * 3)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; - /*points.push_back(Vector3(a.x,0,a.y)); - points.push_back(Vector3(b.x,0,b.y)); - points.push_back(Vector3(0,a.x,a.y)); - points.push_back(Vector3(0,b.x,b.y));*/ + // Draw axis-aligned circles + points.push_back(Vector3(a.x, 0, a.y)); + points.push_back(Vector3(b.x, 0, b.y)); + points.push_back(Vector3(0, a.x, a.y)); + points.push_back(Vector3(0, b.x, b.y)); points.push_back(Vector3(a.x, a.y, 0)); points.push_back(Vector3(b.x, b.y, 0)); + + // Draw a billboarded circle + points_billboard.push_back(Vector3(a.x, a.y, 0)); + points_billboard.push_back(Vector3(b.x, b.y, 0)); } - p_gizmo->add_lines(points, material, true); + p_gizmo->add_lines(points, lines_material, true); + p_gizmo->add_lines(points_billboard, lines_billboard_material, true); p_gizmo->add_unscaled_billboard(icon, 0.05); Vector<Vector3> handles; @@ -1009,40 +1018,44 @@ void LightSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { if (Object::cast_to<SpotLight>(light)) { - Ref<Material> material = get_material("lines", p_gizmo); - Ref<Material> icon = get_material("light_spot_icon", p_gizmo); + const Ref<Material> material_primary = get_material("lines_primary", p_gizmo); + const Ref<Material> material_secondary = get_material("lines_secondary", p_gizmo); + const Ref<Material> icon = get_material("light_spot_icon", p_gizmo); - Vector<Vector3> points; + Vector<Vector3> points_primary; + Vector<Vector3> points_secondary; SpotLight *sl = Object::cast_to<SpotLight>(light); float r = sl->get_param(Light::PARAM_RANGE); float w = r * Math::sin(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE))); float d = r * Math::cos(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE))); - for (int i = 0; i < 360; i++) { - - float ra = Math::deg2rad((float)i); - float rb = Math::deg2rad((float)i + 1); - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; - Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w; + for (int i = 0; i < 120; i++) { - points.push_back(Vector3(a.x, a.y, -d)); - points.push_back(Vector3(b.x, b.y, -d)); + // Draw a circle + const float ra = Math::deg2rad((float)(i * 3)); + const float rb = Math::deg2rad((float)((i + 1) * 3)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w; - if (i % 90 == 0) { + points_primary.push_back(Vector3(a.x, a.y, -d)); + points_primary.push_back(Vector3(b.x, b.y, -d)); - points.push_back(Vector3(a.x, a.y, -d)); - points.push_back(Vector3()); + if (i % 15 == 0) { + // Draw 8 lines from the cone origin to the sides of the circle + points_secondary.push_back(Vector3(a.x, a.y, -d)); + points_secondary.push_back(Vector3()); } } - points.push_back(Vector3(0, 0, -r)); - points.push_back(Vector3()); + points_primary.push_back(Vector3(0, 0, -r)); + points_primary.push_back(Vector3()); - p_gizmo->add_lines(points, material); + p_gizmo->add_lines(points_primary, material_primary); + p_gizmo->add_lines(points_secondary, material_secondary); - float ra = 16 * Math_PI * 2.0 / 64.0; - Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; + const float ra = 16 * Math_PI * 2.0 / 64.0; + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; Vector<Vector3> handles; handles.push_back(Vector3(0, 0, -r)); |