diff options
Diffstat (limited to 'editor')
103 files changed, 1548 insertions, 4881 deletions
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 25ff7f884a..6530e27dcd 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -1164,7 +1164,7 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() { play_position = memnew(Control); play_position->set_mouse_filter(MOUSE_FILTER_PASS); add_child(play_position); - play_position->set_anchors_and_margins_preset(PRESET_WIDE); + play_position->set_anchors_and_offsets_preset(PRESET_WIDE); play_position->connect("draw", callable_mp(this, &AnimationBezierTrackEdit::_play_position_draw)); set_focus_mode(FOCUS_CLICK); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 492a9f2a2f..9a2d7b1e6d 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -37,6 +37,7 @@ #include "editor/plugins/animation_player_editor_plugin.h" #include "editor_node.h" #include "editor_scale.h" +#include "scene/animation/animation_player.h" #include "scene/main/window.h" #include "servers/audio/audio_stream.h" @@ -1744,7 +1745,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() { play_position = memnew(Control); play_position->set_mouse_filter(MOUSE_FILTER_PASS); add_child(play_position); - play_position->set_anchors_and_margins_preset(PRESET_WIDE); + play_position->set_anchors_and_offsets_preset(PRESET_WIDE); play_position->connect("draw", callable_mp(this, &AnimationTimelineEdit::_play_position_draw)); add_track = memnew(MenuButton); @@ -2719,7 +2720,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) { add_child(path_popup); path = memnew(LineEdit); path_popup->add_child(path); - path->set_anchors_and_margins_preset(PRESET_WIDE); + path->set_anchors_and_offsets_preset(PRESET_WIDE); path->connect("text_entered", callable_mp(this, &AnimationTrackEdit::_path_entered)); } @@ -2972,7 +2973,7 @@ AnimationTrackEdit::AnimationTrackEdit() { play_position = memnew(Control); play_position->set_mouse_filter(MOUSE_FILTER_PASS); add_child(play_position); - play_position->set_anchors_and_margins_preset(PRESET_WIDE); + play_position->set_anchors_and_offsets_preset(PRESET_WIDE); play_position->connect("draw", callable_mp(this, &AnimationTrackEdit::_play_position_draw)); set_focus_mode(FOCUS_CLICK); set_mouse_filter(MOUSE_FILTER_PASS); //scroll has to work too for selection @@ -3299,6 +3300,19 @@ void AnimationTrackEditor::set_anim_pos(float p_pos) { bezier_edit->set_play_position(p_pos); } +static bool track_type_is_resettable(Animation::TrackType p_type) { + switch (p_type) { + case Animation::TYPE_VALUE: + [[fallthrough]]; + case Animation::TYPE_BEZIER: + [[fallthrough]]; + case Animation::TYPE_TRANSFORM: + return true; + default: + return false; + } +} + void AnimationTrackEditor::_query_insert(const InsertData &p_id) { if (insert_frame != Engine::get_singleton()->get_frames_drawn()) { //clear insert list for the frame if frame changed @@ -3319,40 +3333,58 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { insert_data.push_back(p_id); + bool reset_allowed = true; + AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + if (player->has_animation("RESET") && player->get_animation("RESET") == animation) { + // Avoid messing with the reset animation itself + reset_allowed = false; + } else { + bool some_resettable = false; + for (int i = 0; i < insert_data.size(); i++) { + if (track_type_is_resettable(insert_data[i].type)) { + some_resettable = true; + break; + } + } + if (!some_resettable) { + reset_allowed = false; + } + } + if (p_id.track_idx == -1) { - if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) { - //potential new key, does not exist - int num_tracks = 0; - bool all_bezier = true; - for (int i = 0; i < insert_data.size(); i++) { - if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) { - all_bezier = false; - } + int num_tracks = 0; + bool all_bezier = true; + for (int i = 0; i < insert_data.size(); i++) { + if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) { + all_bezier = false; + } - if (insert_data[i].track_idx == -1) { - ++num_tracks; - } + if (insert_data[i].track_idx == -1) { + ++num_tracks; + } - if (insert_data[i].type != Animation::TYPE_VALUE) { - continue; - } + if (insert_data[i].type != Animation::TYPE_VALUE) { + continue; + } - switch (insert_data[i].value.get_type()) { - case Variant::INT: - case Variant::FLOAT: - case Variant::VECTOR2: - case Variant::VECTOR3: - case Variant::QUAT: - case Variant::PLANE: - case Variant::COLOR: { - // Valid. - } break; - default: { - all_bezier = false; - } + switch (insert_data[i].value.get_type()) { + case Variant::INT: + case Variant::FLOAT: + case Variant::VECTOR2: + case Variant::VECTOR3: + case Variant::QUAT: + case Variant::PLANE: + case Variant::COLOR: { + // Valid. + } break; + default: { + all_bezier = false; } } + } + if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) { + //potential new key, does not exist if (num_tracks == 1) { insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), p_id.query)); } else { @@ -3360,23 +3392,26 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { } insert_confirm_bezier->set_visible(all_bezier); + insert_confirm_reset->set_visible(reset_allowed); + insert_confirm->get_ok_button()->set_text(TTR("Create")); insert_confirm->popup_centered(); insert_query = true; } else { - call_deferred("_insert_delay"); + call_deferred("_insert_delay", reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), all_bezier && EDITOR_GET("editors/animation/default_create_bezier_tracks")); insert_queue = true; } } else { if (!insert_query && !insert_queue) { - call_deferred("_insert_delay"); + // Create Beziers wouldn't make sense in this case, where no tracks are being created + call_deferred("_insert_delay", reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), false); insert_queue = true; } } } -void AnimationTrackEditor::_insert_delay() { +void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_beziers) { if (insert_query) { //discard since it's entered into query mode insert_queue = false; @@ -3385,13 +3420,18 @@ void AnimationTrackEditor::_insert_delay() { undo_redo->create_action(TTR("Anim Insert")); - int last_track = animation->get_track_count(); + Ref<Animation> reset_anim; + if (p_create_reset) { + reset_anim = _create_and_get_reset_animation(); + } + + TrackIndices next_tracks(animation.ptr(), reset_anim.ptr()); bool advance = false; while (insert_data.size()) { if (insert_data.front()->get().advance) { advance = true; } - last_track = _confirm_insert(insert_data.front()->get(), last_track); + next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, p_create_reset, p_create_beziers); insert_data.pop_front(); } @@ -3682,12 +3722,34 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari } } +Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() { + AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + if (player->has_animation("RESET")) { + return player->get_animation("RESET"); + } else { + Ref<Animation> reset_anim; + reset_anim.instance(); + reset_anim->set_length(ANIM_MIN_LENGTH); + undo_redo->add_do_method(player, "add_animation", "RESET", reset_anim); + undo_redo->add_do_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player); + undo_redo->add_undo_method(player, "remove_animation", "RESET"); + undo_redo->add_undo_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player); + return reset_anim; + } +} + void AnimationTrackEditor::_confirm_insert_list() { undo_redo->create_action(TTR("Anim Create & Insert")); - int last_track = animation->get_track_count(); + bool create_reset = insert_confirm_reset->is_visible() && insert_confirm_reset->is_pressed(); + Ref<Animation> reset_anim; + if (create_reset) { + reset_anim = _create_and_get_reset_animation(); + } + + TrackIndices next_tracks(animation.ptr(), reset_anim.ptr()); while (insert_data.size()) { - last_track = _confirm_insert(insert_data.front()->get(), last_track, insert_confirm_bezier->is_pressed()); + next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, create_reset, insert_confirm_bezier->is_pressed()); insert_data.pop_front(); } @@ -3717,7 +3779,7 @@ PropertyInfo AnimationTrackEditor::_find_hint_for_track(int p_idx, NodePath &r_b r_base_path = node->get_path(); } - if (leftover_path.empty()) { + if (leftover_path.is_empty()) { if (r_current_val) { if (res.is_valid()) { *r_current_val = res; @@ -3807,11 +3869,7 @@ static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool return subindices; } -int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, bool p_create_beziers) { - if (p_last_track == -1) { - p_last_track = animation->get_track_count(); - } - +AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, bool p_create_beziers) { bool created = false; if (p_id.track_idx < 0) { if (p_create_beziers) { @@ -3823,10 +3881,10 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo id.type = Animation::TYPE_BEZIER; id.value = p_id.value.get(subindices[i].substr(1, subindices[i].length())); id.path = String(p_id.path) + subindices[i]; - _confirm_insert(id, p_last_track + i); + p_next_tracks = _confirm_insert(id, p_next_tracks, p_create_reset, false); } - return p_last_track + subindices.size(); + return p_next_tracks; } } created = true; @@ -3863,7 +3921,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo } } - p_id.track_idx = p_last_track; + p_id.track_idx = p_next_tracks.normal; undo_redo->add_do_method(animation.ptr(), "add_track", p_id.type); undo_redo->add_do_method(animation.ptr(), "track_set_path", p_id.track_idx, p_id.path); @@ -3915,7 +3973,7 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo // Just remove the track. undo_redo->add_undo_method(this, "_clear_selection", false); undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count()); - p_last_track++; + p_next_tracks.normal++; } else { undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_id.track_idx, time); int existing = animation->track_find_key(p_id.track_idx, time, true); @@ -3926,9 +3984,27 @@ int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, boo } } + if (p_create_reset && track_type_is_resettable(p_id.type)) { + bool create_reset_track = true; + Animation *reset_anim = AnimationPlayerEditor::singleton->get_player()->get_animation("RESET").ptr(); + for (int i = 0; i < reset_anim->get_track_count(); i++) { + if (reset_anim->track_get_path(i) == p_id.path) { + create_reset_track = false; + break; + } + } + if (create_reset_track) { + undo_redo->add_do_method(reset_anim, "add_track", p_id.type); + undo_redo->add_do_method(reset_anim, "track_set_path", p_next_tracks.reset, p_id.path); + undo_redo->add_do_method(reset_anim, "track_insert_key", p_next_tracks.reset, 0.0f, value); + undo_redo->add_undo_method(reset_anim, "remove_track", reset_anim->get_track_count()); + p_next_tracks.reset++; + } + } + undo_redo->commit_action(); - return p_last_track; + return p_next_tracks; } void AnimationTrackEditor::show_select_node_warning(bool p_show) { @@ -4004,8 +4080,8 @@ void AnimationTrackEditor::_update_tracks() { object = res.ptr(); } - if (object && !leftover_path.empty()) { - if (pinfo.name.empty()) { + if (object && !leftover_path.is_empty()) { + if (pinfo.name.is_empty()) { pinfo.name = leftover_path[leftover_path.size() - 1]; } @@ -4224,6 +4300,7 @@ void AnimationTrackEditor::_notification(int p_what) { selected_filter->set_icon(get_theme_icon("AnimationFilter", "EditorIcons")); imported_anim_warning->set_icon(get_theme_icon("NodeWarning", "EditorIcons")); main_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_theme_icon("Reload", "EditorIcons")); } if (p_what == NOTIFICATION_READY) { @@ -5056,6 +5133,11 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { } } +void AnimationTrackEditor::_edit_menu_about_to_popup() { + AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player(); + edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset()); +} + void AnimationTrackEditor::_edit_menu_pressed(int p_option) { last_menu_track_opt = p_option; switch (p_option) { @@ -5203,7 +5285,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { scale_dialog->popup_centered(Size2(200, 100) * EDSCALE); } break; case EDIT_SCALE_CONFIRM: { - if (selection.empty()) { + if (selection.is_empty()) { return; } @@ -5378,6 +5460,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { emit_signal("timeline_changed", pos, true); } break; + case EDIT_APPLY_RESET: { + AnimationPlayerEditor::singleton->get_player()->apply_reset(true); + + } break; case EDIT_OPTIMIZE_ANIMATION: { optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE); @@ -5575,7 +5661,7 @@ AnimationTrackEditor::AnimationTrackEditor() { info_message->set_align(Label::ALIGN_CENTER); info_message->set_autowrap(true); info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); main_panel->add_child(info_message); timeline = memnew(AnimationTimelineEdit); @@ -5710,10 +5796,13 @@ AnimationTrackEditor::AnimationTrackEditor() { edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KEY_MASK_CMD | KEY_RIGHT), EDIT_GOTO_NEXT_STEP); edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KEY_MASK_CMD | KEY_LEFT), EDIT_GOTO_PREV_STEP); edit->get_popup()->add_separator(); + edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET); + edit->get_popup()->add_separator(); edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION); edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION); edit->get_popup()->connect("id_pressed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed)); + edit->get_popup()->connect("about_to_popup", callable_mp(this, &AnimationTrackEditor::_edit_menu_about_to_popup)); pick_track = memnew(SceneTreeDialog); add_child(pick_track); @@ -5739,9 +5828,16 @@ AnimationTrackEditor::AnimationTrackEditor() { insert_confirm->add_child(icvb); insert_confirm_text = memnew(Label); icvb->add_child(insert_confirm_text); + HBoxContainer *ichb = memnew(HBoxContainer); + icvb->add_child(ichb); insert_confirm_bezier = memnew(CheckBox); insert_confirm_bezier->set_text(TTR("Use Bezier Curves")); - icvb->add_child(insert_confirm_bezier); + insert_confirm_bezier->set_pressed(EDITOR_GET("editors/animation/default_create_bezier_tracks")); + ichb->add_child(insert_confirm_bezier); + insert_confirm_reset = memnew(CheckBox); + insert_confirm_reset->set_text(TTR("Create RESET Track(s)", "")); + insert_confirm_reset->set_pressed(EDITOR_GET("editors/animation/default_create_reset_tracks")); + ichb->add_child(insert_confirm_reset); keying = false; moving_selection = false; key_edit = nullptr; diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 3cb31fe21e..7006959187 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -47,6 +47,8 @@ #include "scene/resources/animation.h" #include "scene_tree_editor.h" +class AnimationPlayer; + class AnimationTimelineEdit : public Range { GDCLASS(AnimationTimelineEdit, Range); @@ -285,6 +287,7 @@ class AnimationTrackEditor : public VBoxContainer { EDIT_DELETE_SELECTION, EDIT_GOTO_NEXT_STEP, EDIT_GOTO_PREV_STEP, + EDIT_APPLY_RESET, EDIT_OPTIMIZE_ANIMATION, EDIT_OPTIMIZE_ANIMATION_CONFIRM, EDIT_CLEAN_UP_ANIMATION, @@ -361,6 +364,7 @@ class AnimationTrackEditor : public VBoxContainer { Label *insert_confirm_text; CheckBox *insert_confirm_bezier; + CheckBox *insert_confirm_reset; ConfirmationDialog *insert_confirm; bool insert_queue; bool inserting; @@ -369,9 +373,19 @@ class AnimationTrackEditor : public VBoxContainer { uint64_t insert_frame; void _query_insert(const InsertData &p_id); + Ref<Animation> _create_and_get_reset_animation(); void _confirm_insert_list(); - int _confirm_insert(InsertData p_id, int p_last_track, bool p_create_beziers = false); - void _insert_delay(); + struct TrackIndices { + int normal; + int reset; + + TrackIndices(const Animation *p_anim = nullptr, const Animation *p_reset_anim = nullptr) { + normal = p_anim ? p_anim->get_track_count() : 0; + reset = p_reset_anim ? p_reset_anim->get_track_count() : 0; + } + }; + TrackIndices _confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, bool p_create_beziers); + void _insert_delay(bool p_create_reset, bool p_create_beziers); void _root_removed(Node *p_root); @@ -447,6 +461,7 @@ class AnimationTrackEditor : public VBoxContainer { void _select_all_tracks_for_copy(); + void _edit_menu_about_to_popup(); void _edit_menu_pressed(int p_option); int last_menu_track_opt; diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp index 0b6b1ef6a7..25a67d0041 100644 --- a/editor/array_property_edit.cpp +++ b/editor/array_property_edit.cpp @@ -259,7 +259,7 @@ void ArrayPropertyEdit::edit(Object *p_obj, const StringName &p_prop, const Stri obj = p_obj->get_instance_id(); default_type = p_deftype; - if (!p_hint_string.empty()) { + if (!p_hint_string.is_empty()) { int hint_subtype_separator = p_hint_string.find(":"); if (hint_subtype_separator >= 0) { String subtype_string = p_hint_string.substr(0, hint_subtype_separator); diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 3dd0977478..a634b87366 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -66,10 +66,10 @@ GotoLineDialog::GotoLineDialog() { set_title(TTR("Go to Line")); VBoxContainer *vbc = memnew(VBoxContainer); - vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE); add_child(vbc); Label *l = memnew(Label); @@ -325,7 +325,7 @@ void FindReplaceBar::_update_results_count() { results_count = 0; String searched = get_search_text(); - if (searched.empty()) { + if (searched.is_empty()) { return; } @@ -356,7 +356,7 @@ void FindReplaceBar::_update_results_count() { } void FindReplaceBar::_update_matches_label() { - if (search_text->get_text().empty() || results_count == -1) { + if (search_text->get_text().is_empty() || results_count == -1) { matches_label->hide(); } else { matches_label->show(); @@ -483,7 +483,7 @@ void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) { search_text->set_text(text_editor->get_selection_text()); } - if (!get_search_text().empty()) { + if (!get_search_text().is_empty()) { if (p_focus_replace) { replace_text->select_all(); replace_text->set_cursor_position(replace_text->get_text().length()); @@ -1309,7 +1309,7 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) { for (int i = begin; i <= end; i++) { String line_text = text_editor->get_line(i); - if (line_text.strip_edges().empty()) { + if (line_text.strip_edges().is_empty()) { line_text = delimiter; } else { if (is_commented) { diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 473597b9b3..c4ab226b28 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -1008,7 +1008,7 @@ void ConnectionsDock::update_tree() { break; } } - if (!F->get().inherits.empty()) { + if (!F->get().inherits.is_empty()) { F = dd->class_list.find(F->get().inherits); } else { break; diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 75d57b040f..b28fe400e6 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -492,7 +492,7 @@ void CreateDialog::_favorite_selected() { } search_box->set_text(item->get_text(0).get_slicec(' ', 0)); - recent->unselect_all(); + recent->deselect_all(); _update_search(); } diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 276df45972..5b2dc3fc32 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -55,8 +55,8 @@ EditorDebuggerNode::EditorDebuggerNode() { singleton = this; } - add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT)); - add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT)); + add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(SIDE_LEFT)); + add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(SIDE_RIGHT)); tabs = memnew(TabContainer); tabs->set_tab_align(TabContainer::ALIGN_LEFT); @@ -115,7 +115,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() { tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("DebuggerPanel", "EditorStyles")); } - if (!debugger_plugins.empty()) { + if (!debugger_plugins.is_empty()) { for (Set<Ref<Script>>::Element *i = debugger_plugins.front(); i; i = i->next()) { node->add_debugger_plugin(i->get()); } @@ -140,7 +140,7 @@ void EditorDebuggerNode::_error_selected(const String &p_file, int p_line, int p void EditorDebuggerNode::_text_editor_stack_goto(const ScriptEditorDebugger *p_debugger) { const String file = p_debugger->get_stack_script_file(); - if (file.empty()) { + if (file.is_empty()) { return; } stack_script = ResourceLoader::load(file); @@ -226,8 +226,8 @@ void EditorDebuggerNode::_notification(int p_what) { switch (p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { if (tabs->get_tab_count() > 1) { - add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT)); - add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT)); + add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(SIDE_LEFT)); + add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(SIDE_RIGHT)); tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("DebuggerPanel", "EditorStyles")); } diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index ebac9b3482..e36f11ae1d 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -242,7 +242,7 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) { } break; case ITEM_MENU_COPY_NODE_PATH: { String text = get_selected_path(); - if (text.empty()) { + if (text.is_empty()) { return; } else if (text == "/root") { text = "."; diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index 44c5f83e9a..f73165881c 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -102,7 +102,7 @@ void EditorPerformanceProfiler::_monitor_draw() { } } - if (active.empty()) { + if (active.is_empty()) { info_message->show(); return; } @@ -217,7 +217,7 @@ void EditorPerformanceProfiler::_build_monitor_tree() { TreeItem *item = _create_monitor_item(i.value().name, base); item->set_checked(0, monitor_checked.has(i.key())); i.value().item = item; - if (!i.value().history.empty()) { + if (!i.value().history.is_empty()) { i.value().update_value(i.value().history.front()->get()); } } @@ -382,7 +382,7 @@ EditorPerformanceProfiler::EditorPerformanceProfiler() { info_message->set_align(Label::ALIGN_CENTER); info_message->set_autowrap(true); info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); monitor_draw->add_child(info_message); for (int i = 0; i < Performance::MONITOR_MAX; i++) { diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index 930aca6e5a..4871c35ea4 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -596,7 +596,7 @@ bool EditorProfiler::is_profiling() { Vector<Vector<String>> EditorProfiler::get_data_as_csv() const { Vector<Vector<String>> res; - if (frame_metrics.empty()) { + if (frame_metrics.is_empty()) { return res; } diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 45b9d68158..6f0d537fa2 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -490,17 +490,17 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da if (oe.callstack.size() > 0) { // If available, use the script's stack in the error title. error_title = oe.callstack[oe.callstack.size() - 1].func + ": "; - } else if (!oe.source_func.empty()) { + } else if (!oe.source_func.is_empty()) { // Otherwise try to use the C++ source function. error_title += oe.source_func + ": "; } // If we have a (custom) error message, use it as title, and add a C++ Error // item with the original error condition. - error_title += oe.error_descr.empty() ? oe.error : oe.error_descr; + error_title += oe.error_descr.is_empty() ? oe.error : oe.error_descr; error->set_text(1, error_title); tooltip += " " + error_title + "\n"; - if (!oe.error_descr.empty()) { + if (!oe.error_descr.is_empty()) { // Add item for C++ error condition. TreeItem *cpp_cond = error_tree->create_item(error); cpp_cond->set_text(0, "<" + TTR("C++ Error") + ">"); @@ -516,7 +516,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da // Source of the error. String source_txt = (source_is_project_file ? oe.source_file.get_file() : oe.source_file) + ":" + itos(oe.source_line); - if (!oe.source_func.empty()) { + if (!oe.source_func.is_empty()) { source_txt += " @ " + oe.source_func + "()"; } diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index a27f196d49..208d390134 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -448,7 +448,7 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector< Vector<RemovedDependency> removed_deps; _find_all_removed_dependencies(EditorFileSystem::get_singleton()->get_filesystem(), removed_deps); removed_deps.sort(); - if (removed_deps.empty()) { + if (removed_deps.is_empty()) { owners->hide(); text->set_text(TTR("Remove selected files from the project? (no undo)\nYou can find the removed files in the system trash to restore them.")); set_size(Size2()); @@ -639,7 +639,7 @@ void OrphanResourcesDialog::ok_pressed() { paths.clear(); _find_to_delete(files->get_root(), paths); - if (paths.empty()) { + if (paths.is_empty()) { return; } diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h index 5d2ae582e6..008194bbd6 100644 --- a/editor/dependency_editor.h +++ b/editor/dependency_editor.h @@ -111,8 +111,8 @@ class DependencyRemoveDialog : public ConfirmationDialog { String dependency_folder; bool operator<(const RemovedDependency &p_other) const { - if (dependency_folder.empty() != p_other.dependency_folder.empty()) { - return p_other.dependency_folder.empty(); + if (dependency_folder.is_empty() != p_other.dependency_folder.is_empty()) { + return p_other.dependency_folder.is_empty(); } else { return dependency < p_other.dependency; } diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 5ee9abb183..c21c957799 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -813,7 +813,7 @@ void DocTools::generate(bool p_basic_types) { } // Skip adding the lang if it doesn't expose anything (e.g. C#). - if (c.methods.empty() && c.constants.empty()) { + if (c.methods.is_empty() && c.constants.is_empty()) { continue; } @@ -1165,7 +1165,7 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str _write_string(f, 1, "<tutorials>"); for (int i = 0; i < c.tutorials.size(); i++) { DocData::TutorialDoc tutorial = c.tutorials.get(i); - String title_attribute = (!tutorial.title.empty()) ? " title=\"" + tutorial.title.xml_escape() + "\"" : ""; + String title_attribute = (!tutorial.title.is_empty()) ? " title=\"" + tutorial.title.xml_escape() + "\"" : ""; _write_string(f, 2, "<link" + title_attribute + ">" + tutorial.link.xml_escape() + "</link>"); } _write_string(f, 1, "</tutorials>"); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index d81dc05a75..d768f00c3b 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -922,7 +922,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { bus_options = memnew(MenuButton); bus_options->set_shortcut_context(this); bus_options->set_h_size_flags(SIZE_SHRINK_END); - bus_options->set_anchor(MARGIN_RIGHT, 0.0); + bus_options->set_anchor(SIDE_RIGHT, 0.0); bus_options->set_tooltip(TTR("Bus options")); hbc->add_child(bus_options); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 2251440544..5f429e7034 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -402,7 +402,7 @@ void EditorAutoloadSettings::update_autoload() { String name = pi.name.get_slice("/", 1); String path = ProjectSettings::get_singleton()->get(pi.name); - if (name.empty()) { + if (name.is_empty()) { continue; } @@ -774,7 +774,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() { String name = pi.name.get_slice("/", 1); String path = ProjectSettings::get_singleton()->get(pi.name); - if (name.empty()) { + if (name.is_empty()) { continue; } diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index eab1ecf373..05c7b58c72 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -331,7 +331,7 @@ Dictionary EditorData::get_editor_states() const { Dictionary metadata; for (int i = 0; i < editor_plugins.size(); i++) { Dictionary state = editor_plugins[i]->get_state(); - if (state.empty()) { + if (state.is_empty()) { continue; } metadata[editor_plugins[i]->get_name()] = state; @@ -493,7 +493,7 @@ void EditorData::remove_custom_type(const String &p_type) { for (int i = 0; i < E->get().size(); i++) { if (E->get()[i].name == p_type) { E->get().remove(i); - if (E->get().empty()) { + if (E->get().is_empty()) { custom_types.erase(E->key()); } return; @@ -901,7 +901,7 @@ String EditorData::script_class_get_icon_path(const String &p_class) const { String current = p_class; String ret = _script_class_icon_paths[current]; - while (ret.empty()) { + while (ret.is_empty()) { current = script_class_get_base(current); if (!ScriptServer::is_global_class(current)) { return String(); @@ -931,7 +931,7 @@ void EditorData::script_class_save_icon_paths() { } } - if (d.empty()) { + if (d.is_empty()) { if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) { ProjectSettings::get_singleton()->clear("_global_script_class_icons"); } @@ -1125,7 +1125,7 @@ List<Node *> EditorSelection::get_full_selected_node_list() { } void EditorSelection::clear() { - while (!selection.empty()) { + while (!selection.is_empty()) { remove_node(selection.front()->key()); } diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 07318c14bc..231c143c05 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -398,7 +398,7 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const { Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); ERR_FAIL_COND_V(theme.is_null(), Ref<ImageTexture>()); - if (EditorNode::get_singleton()->get_viewport()->is_layout_rtl()) { + if (EditorNode::get_singleton()->get_main_control()->is_layout_rtl()) { return theme->get_icon("PlayBackwards", "EditorIcons"); } else { return theme->get_icon("Play", "EditorIcons"); @@ -521,7 +521,7 @@ void EditorExportPlatform::_edit_filter_list(Set<String> &r_list, const String & Vector<String> filters; for (int i = 0; i < split.size(); i++) { String f = split[i].strip_edges(); - if (f.empty()) { + if (f.is_empty()) { continue; } filters.push_back(f); @@ -754,7 +754,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & Vector<String> enc_in_split = p_preset->get_enc_in_filter().split(","); for (int i = 0; i < enc_in_split.size(); i++) { String f = enc_in_split[i].strip_edges(); - if (f.empty()) { + if (f.is_empty()) { continue; } enc_in_filters.push_back(f); @@ -763,7 +763,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & Vector<String> enc_ex_split = p_preset->get_enc_ex_filter().split(","); for (int i = 0; i < enc_ex_split.size(); i++) { String f = enc_ex_split[i].strip_edges(); - if (f.empty()) { + if (f.is_empty()) { continue; } enc_ex_filters.push_back(f); @@ -1696,7 +1696,7 @@ bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset, valid = dvalid || rvalid; r_missing_templates = !valid; - if (!err.empty()) { + if (!err.is_empty()) { r_error = err; } return valid; @@ -1783,7 +1783,7 @@ Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_pr } } - if (err == OK && !so_files.empty()) { + if (err == OK && !so_files.is_empty()) { //if shared object files, copy them da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < so_files.size() && err == OK; i++) { diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 05bc2edefb..280c13ec9d 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -96,7 +96,7 @@ void EditorFeatureProfile::set_disable_class_property(const StringName &p_class, } else { ERR_FAIL_COND(!disabled_properties.has(p_class)); disabled_properties[p_class].erase(p_property); - if (disabled_properties[p_class].empty()) { + if (disabled_properties[p_class].is_empty()) { disabled_properties.erase(p_class); } } @@ -876,7 +876,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { no_profile_selected_help = memnew(Label(TTR("Create or import a profile to edit available classes and properties."))); // Add some spacing above the help label. Ref<StyleBoxEmpty> sb = memnew(StyleBoxEmpty); - sb->set_default_margin(MARGIN_TOP, 20 * EDSCALE); + sb->set_default_margin(SIDE_TOP, 20 * EDSCALE); no_profile_selected_help->add_theme_style_override("normal", sb); no_profile_selected_help->set_align(Label::ALIGN_CENTER); no_profile_selected_help->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 8ded47605c..55373c47a4 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -499,7 +499,7 @@ void EditorFileDialog::_multi_selected(int p_item, bool p_selected) { } void EditorFileDialog::_items_clear_selection() { - item_list->unselect_all(); + item_list->deselect_all(); // If nothing is selected, then block Open button. switch (mode) { @@ -595,7 +595,7 @@ void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) { // Right click on folder background. Deselect all files so that actions are applied on the current folder. for (int i = 0; i < item_list->get_item_count(); i++) { - item_list->unselect(i); + item_list->deselect(i); } item_menu->clear(); @@ -758,7 +758,7 @@ void EditorFileDialog::update_file_list() { dirs.sort_custom<NaturalNoCaseComparator>(); files.sort_custom<NaturalNoCaseComparator>(); - while (!dirs.empty()) { + while (!dirs.is_empty()) { const String &dir_name = dirs.front()->get(); item_list->add_item(dir_name); @@ -806,8 +806,8 @@ void EditorFileDialog::update_file_list() { } } - while (!files.empty()) { - bool match = patterns.empty(); + while (!files.is_empty()) { + bool match = patterns.is_empty(); for (List<String>::Element *E = patterns.front(); E; E = E->next()) { if (files.front()->get().matchn(E->get())) { @@ -849,7 +849,7 @@ void EditorFileDialog::update_file_list() { } if (favorites->get_current() >= 0) { - favorites->unselect(favorites->get_current()); + favorites->deselect(favorites->get_current()); } favorite->set_pressed(false); @@ -1226,7 +1226,7 @@ void EditorFileDialog::_update_favorites() { if (setthis) { favorite->set_pressed(true); favorites->set_current(favorites->get_item_count() - 1); - recent->unselect_all(); + recent->deselect_all(); } } } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 41010b6a86..5eff0f2e4a 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -160,19 +160,19 @@ void EditorHelp::_class_desc_resized() { const int display_margin = MAX(30 * EDSCALE, get_parent_anchorable_rect().size.width - char_width * 120 * EDSCALE) * 0.5; Ref<StyleBox> class_desc_stylebox = EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox("normal", "RichTextLabel")->duplicate(); - class_desc_stylebox->set_default_margin(MARGIN_LEFT, display_margin); - class_desc_stylebox->set_default_margin(MARGIN_RIGHT, display_margin); + class_desc_stylebox->set_default_margin(SIDE_LEFT, display_margin); + class_desc_stylebox->set_default_margin(SIDE_RIGHT, display_margin); class_desc->add_theme_style_override("normal", class_desc_stylebox); } void EditorHelp::_add_type(const String &p_type, const String &p_enum) { String t = p_type; - if (t.empty()) { + if (t.is_empty()) { t = "void"; } - bool can_ref = (t != "void") || !p_enum.empty(); + bool can_ref = (t != "void") || !p_enum.is_empty(); - if (!p_enum.empty()) { + if (!p_enum.is_empty()) { if (p_enum.get_slice_count(".") > 1) { t = p_enum.get_slice(".", 1); } else { @@ -188,7 +188,7 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) { add_array = true; t = t.replace("[]", ""); } - if (p_enum.empty()) { + if (p_enum.is_empty()) { class_desc->push_meta("#" + t); //class } else { class_desc->push_meta("$" + p_enum); //class @@ -472,7 +472,7 @@ void EditorHelp::_update_doc() { for (int i = 0; i < cd.tutorials.size(); i++) { const String link = DTR(cd.tutorials[i].link); - String linktxt = (cd.tutorials[i].title.empty()) ? link : DTR(cd.tutorials[i].title); + String linktxt = (cd.tutorials[i].title.is_empty()) ? link : DTR(cd.tutorials[i].title); const int seppos = linktxt.find("//"); if (seppos != -1) { linktxt = link.right(seppos + 2); @@ -498,7 +498,7 @@ void EditorHelp::_update_doc() { if (cd.is_script_doc) { has_properties = false; for (int i = 0; i < cd.properties.size(); i++) { - if (cd.properties[i].name.begins_with("_") && cd.properties[i].description.empty()) { + if (cd.properties[i].name.begins_with("_") && cd.properties[i].description.is_empty()) { continue; } has_properties = true; @@ -522,7 +522,7 @@ void EditorHelp::_update_doc() { for (int i = 0; i < cd.properties.size(); i++) { // Ignore undocumented private. - if (cd.properties[i].name.begins_with("_") && cd.properties[i].description.empty()) { + if (cd.properties[i].name.begins_with("_") && cd.properties[i].description.is_empty()) { continue; } property_line[cd.properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description @@ -633,7 +633,7 @@ void EditorHelp::_update_doc() { } } // Ignore undocumented private. - if (cd.methods[i].name.begins_with("_") && cd.methods[i].description.empty()) { + if (cd.methods[i].name.begins_with("_") && cd.methods[i].description.is_empty()) { continue; } methods.push_back(cd.methods[i]); @@ -668,7 +668,7 @@ void EditorHelp::_update_doc() { } } - if (any_previous && !m.empty()) { + if (any_previous && !m.is_empty()) { class_desc->push_cell(); class_desc->pop(); //cell class_desc->push_cell(); @@ -702,7 +702,7 @@ void EditorHelp::_update_doc() { _add_method(m[i], true); } - any_previous = !m.empty(); + any_previous = !m.is_empty(); } class_desc->pop(); //table @@ -848,7 +848,7 @@ void EditorHelp::_update_doc() { Vector<DocData::ConstantDoc> constants; for (int i = 0; i < cd.constants.size(); i++) { - if (!cd.constants[i].enumeration.empty()) { + if (!cd.constants[i].enumeration.is_empty()) { if (!enums.has(cd.constants[i].enumeration)) { enums[cd.constants[i].enumeration] = Vector<DocData::ConstantDoc>(); } @@ -856,7 +856,7 @@ void EditorHelp::_update_doc() { enums[cd.constants[i].enumeration].push_back(cd.constants[i]); } else { // Ignore undocumented private. - if (cd.constants[i].name.begins_with("_") && cd.constants[i].description.empty()) { + if (cd.constants[i].name.begins_with("_") && cd.constants[i].description.is_empty()) { continue; } constants.push_back(cd.constants[i]); @@ -1174,7 +1174,7 @@ void EditorHelp::_update_doc() { class_desc->push_color(text_color); class_desc->push_font(doc_font); class_desc->push_indent(1); - if (!cd.properties[i].description.strip_edges().empty()) { + if (!cd.properties[i].description.strip_edges().is_empty()) { _add_text(DTR(cd.properties[i].description)); } else { class_desc->add_image(get_theme_icon("Error", "EditorIcons")); @@ -1229,7 +1229,7 @@ void EditorHelp::_update_doc() { class_desc->push_color(text_color); class_desc->push_font(doc_font); class_desc->push_indent(1); - if (!methods_filtered[i].description.strip_edges().empty()) { + if (!methods_filtered[i].description.strip_edges().is_empty()) { _add_text(DTR(methods_filtered[i].description)); } else { class_desc->add_image(get_theme_icon("Error", "EditorIcons")); @@ -1838,7 +1838,7 @@ void FindBar::popup_search() { grabbed_focus = true; } - if (!search_text->get_text().empty()) { + if (!search_text->get_text().is_empty()) { search_text->select_all(); search_text->set_cursor_position(search_text->get_text().length()); if (grabbed_focus) { @@ -1908,7 +1908,7 @@ void FindBar::_update_results_count() { results_count = 0; String searched = search_text->get_text(); - if (searched.empty()) { + if (searched.is_empty()) { return; } @@ -1928,7 +1928,7 @@ void FindBar::_update_results_count() { } void FindBar::_update_matches_label() { - if (search_text->get_text().empty() || results_count == -1) { + if (search_text->get_text().is_empty() || results_count == -1) { matches_label->hide(); } else { matches_label->show(); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index dd136c046f..4d975512d4 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -220,7 +220,7 @@ void EditorProperty::_notification(int p_what) { Size2 size = get_size(); if (bottom_editor) { - size.height = bottom_editor->get_margin(MARGIN_TOP); + size.height = bottom_editor->get_offset(SIDE_TOP); } else if (label_reference) { size.height = label_reference->get_size().height; } @@ -865,7 +865,7 @@ Control *EditorProperty::make_custom_tooltip(const String &p_text) const { String text; PackedStringArray slices = p_text.split("::", false); - if (!slices.empty()) { + if (!slices.is_empty()) { String property_name = slices[0].strip_edges(); text = TTR("Property:") + " [u][b]" + property_name + "[/b][/u]"; @@ -1098,7 +1098,7 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE); PackedStringArray slices = p_text.split("::", false); - if (!slices.empty()) { + if (!slices.is_empty()) { String property_name = slices[0].strip_edges(); String text = "[u][b]" + property_name + "[/b][/u]"; @@ -1901,7 +1901,7 @@ void EditorInspector::update_tree() { } } - if (!F->get().inherits.empty()) { + if (!F->get().inherits.is_empty()) { F = dd->class_list.find(F->get().inherits); } else { break; @@ -2525,7 +2525,7 @@ void EditorInspector::_update_script_class_properties(const Object &p_object, Li script = script->get_base_script(); } - if (classes.empty()) { + if (classes.is_empty()) { return; } diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp index c50fe81217..71d369be1f 100644 --- a/editor/editor_layouts_dialog.cpp +++ b/editor/editor_layouts_dialog.cpp @@ -100,26 +100,26 @@ void EditorLayoutsDialog::_post_popup() { EditorLayoutsDialog::EditorLayoutsDialog() { makevb = memnew(VBoxContainer); add_child(makevb); - makevb->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 5); - makevb->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -5); + makevb->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5); + makevb->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5); layout_names = memnew(ItemList); makevb->add_child(layout_names); layout_names->set_visible(true); - layout_names->set_margin(MARGIN_TOP, 5); - layout_names->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 5); - layout_names->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -5); + layout_names->set_offset(SIDE_TOP, 5); + layout_names->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5); + layout_names->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5); layout_names->set_v_size_flags(Control::SIZE_EXPAND_FILL); layout_names->set_select_mode(ItemList::SELECT_MULTI); layout_names->set_allow_rmb_select(true); name = memnew(LineEdit); makevb->add_child(name); - name->set_margin(MARGIN_TOP, 5); - name->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 5); - name->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -5); + name->set_offset(SIDE_TOP, 5); + name->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5); + name->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5); name->connect("gui_input", callable_mp(this, &EditorLayoutsDialog::_line_gui_input)); - name->connect("focus_entered", callable_mp(layout_names, &ItemList::unselect_all)); + name->connect("focus_entered", callable_mp(layout_names, &ItemList::deselect_all)); } void EditorLayoutsDialog::set_name_line_enabled(bool p_enabled) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index dfe5d64784..4fb34f58bf 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -91,7 +91,6 @@ #include "editor/export_template_manager.h" #include "editor/filesystem_dock.h" #include "editor/import/editor_import_collada.h" -#include "editor/import/editor_scene_importer_gltf.h" #include "editor/import/resource_importer_bitmask.h" #include "editor/import/resource_importer_csv.h" #include "editor/import/resource_importer_csv_translation.h" @@ -103,6 +102,7 @@ #include "editor/import/resource_importer_texture.h" #include "editor/import/resource_importer_texture_atlas.h" #include "editor/import/resource_importer_wav.h" +#include "editor/import/scene_importer_mesh_node_3d.h" #include "editor/import_dock.h" #include "editor/multi_node_edit.h" #include "editor/node_dock.h" @@ -377,9 +377,9 @@ void EditorNode::_version_control_menu_option(int p_idx) { void EditorNode::_update_title() { String appname = ProjectSettings::get_singleton()->get("application/config/name"); - String title = appname.empty() ? String(VERSION_FULL_NAME) : String(VERSION_NAME + String(" - ") + appname); + String title = appname.is_empty() ? String(VERSION_FULL_NAME) : String(VERSION_NAME + String(" - ") + appname); String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_filename() : String(); - if (!edited.empty()) { + if (!edited.is_empty()) { title += " - " + String(edited.get_file()); } if (unsaved_cache) { @@ -485,7 +485,7 @@ void EditorNode::_notification(int p_what) { RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))); bool dof_jitter = GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter"); RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter); - RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size")); + RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"), GLOBAL_GET("rendering/quality/ssao/adaptive_target"), GLOBAL_GET("rendering/quality/ssao/blur_passes"), GLOBAL_GET("rendering/quality/ssao/fadeout_from"), GLOBAL_GET("rendering/quality/ssao/fadeout_to")); RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit")); bool glow_bicubic = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0; RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic); @@ -782,8 +782,8 @@ void EditorNode::_fs_changed() { preset_name); } else { Ref<EditorExportPlatform> platform = preset->get_platform(); - const String export_path = export_defer.path.empty() ? preset->get_export_path() : export_defer.path; - if (export_path.empty()) { + const String export_path = export_defer.path.is_empty() ? preset->get_export_path() : export_defer.path; + if (export_path.is_empty()) { export_error = vformat("Export preset '%s' doesn't have a default export path, and none was specified.", preset_name); } else if (platform.is_null()) { export_error = vformat("Export preset '%s' doesn't have a matching platform.", preset_name); @@ -821,7 +821,7 @@ void EditorNode::_fs_changed() { } } - if (!export_error.empty()) { + if (!export_error.is_empty()) { ERR_PRINT(export_error); OS::get_singleton()->set_exit_code(EXIT_FAILURE); } @@ -1419,6 +1419,17 @@ int EditorNode::_save_external_resources() { return saved; } +static void _reset_animation_players(Node *p_node, List<Ref<AnimatedValuesBackup>> *r_anim_backups) { + for (int i = 0; i < p_node->get_child_count(); i++) { + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(p_node->get_child(i)); + if (player && player->is_reset_on_save_enabled() && player->can_apply_reset()) { + Ref<AnimatedValuesBackup> old_values = player->apply_reset(); + r_anim_backups->push_back(old_values); + } + _reset_animation_players(p_node->get_child(i), r_anim_backups); + } +} + void EditorNode::_save_scene(String p_file, int idx) { Node *scene = editor_data.get_edited_scene_root(idx); @@ -1433,6 +1444,8 @@ void EditorNode::_save_scene(String p_file, int idx) { } editor_data.apply_changes_in_editors(); + List<Ref<AnimatedValuesBackup>> anim_backups; + _reset_animation_players(scene, &anim_backups); _save_default_environment(); _set_scene_metadata(p_file, idx); @@ -1480,6 +1493,11 @@ void EditorNode::_save_scene(String p_file, int idx) { _save_external_resources(); editor_data.save_editor_external_data(); + + for (List<Ref<AnimatedValuesBackup>>::Element *E = anim_backups.front(); E; E = E->next()) { + E->get()->restore(); + } + if (err == OK) { scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_file)); if (idx < 0 || idx == editor_data.get_edited_scene()) { @@ -1693,7 +1711,7 @@ void EditorNode::_dialog_action(String p_file) { current_obj->_change_notify(); } break; case SETTINGS_LAYOUT_SAVE: { - if (p_file.empty()) { + if (p_file.is_empty()) { return; } @@ -1721,7 +1739,7 @@ void EditorNode::_dialog_action(String p_file) { } break; case SETTINGS_LAYOUT_DELETE: { - if (p_file.empty()) { + if (p_file.is_empty()) { return; } @@ -1804,7 +1822,7 @@ void EditorNode::edit_item(Object *p_object) { sub_plugins = editor_data.get_subeditors(p_object); } - if (!sub_plugins.empty()) { + if (!sub_plugins.is_empty()) { bool same = true; if (sub_plugins.size() == editor_plugins_over->get_plugins_list().size()) { for (int i = 0; i < sub_plugins.size(); i++) { @@ -1980,7 +1998,7 @@ void EditorNode::_edit_current() { multi_nodes.push_back(node); } } - if (!multi_nodes.empty()) { + if (!multi_nodes.is_empty()) { // Pick the top-most node multi_nodes.sort_custom<Node::Comparator>(); selected_node = multi_nodes.front()->get(); @@ -2062,13 +2080,13 @@ void EditorNode::_edit_current() { sub_plugins = editor_data.get_subeditors(current_obj); } - if (!sub_plugins.empty()) { + if (!sub_plugins.is_empty()) { _display_top_editors(false); _set_top_editors(sub_plugins); _set_editing_top_editors(current_obj); _display_top_editors(true); - } else if (!editor_plugins_over->get_plugins_list().empty()) { + } else if (!editor_plugins_over->get_plugins_list().is_empty()) { hide_top_editors(); } } @@ -2238,7 +2256,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case FILE_OPEN_PREV: { - if (previous_scenes.empty()) { + if (previous_scenes.is_empty()) { break; } opening_prev = true; @@ -2509,7 +2527,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case RUN_PLAY_CUSTOM_SCENE: { - if (run_custom_filename.empty() || editor_run.get_status() == EditorRun::STATUS_STOP) { + if (run_custom_filename.is_empty() || editor_run.get_status() == EditorRun::STATUS_STOP) { _menu_option_confirm(RUN_STOP, true); quick_run->popup_dialog("PackedScene", true); quick_run->set_title(TTR("Quick Run Scene...")); @@ -2727,14 +2745,14 @@ void EditorNode::_screenshot(bool p_use_utc) { } void EditorNode::_save_screenshot(NodePath p_path) { - Control *editor_viewport = EditorInterface::get_singleton()->get_editor_viewport(); - ERR_FAIL_COND_MSG(!editor_viewport, "Cannot get editor viewport."); - Viewport *viewport = editor_viewport->get_viewport(); - ERR_FAIL_COND_MSG(!viewport, "Cannot get editor viewport."); + Control *editor_main_control = EditorInterface::get_singleton()->get_editor_main_control(); + ERR_FAIL_COND_MSG(!editor_main_control, "Cannot get editor main control."); + Viewport *viewport = editor_main_control->get_viewport(); + ERR_FAIL_COND_MSG(!viewport, "Cannot get editor main control viewport."); Ref<ViewportTexture> texture = viewport->get_texture(); - ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get editor viewport texture."); + ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get editor main control viewport texture."); Ref<Image> img = texture->get_data(); - ERR_FAIL_COND_MSG(img.is_null(), "Cannot get editor viewport texture image."); + ERR_FAIL_COND_MSG(img.is_null(), "Cannot get editor main control viewport texture image."); Error error = img->save_png(p_path); ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'."); } @@ -2858,7 +2876,7 @@ void EditorNode::_update_file_menu_opened() { Ref<Shortcut> reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene"); reopen_closed_scene_sc->set_name(TTR("Reopen Closed Scene")); PopupMenu *pop = file_menu->get_popup(); - pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.empty()); + pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty()); } void EditorNode::_update_file_menu_closed() { @@ -2866,8 +2884,8 @@ void EditorNode::_update_file_menu_closed() { pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), false); } -Control *EditorNode::get_viewport() { - return viewport; +Control *EditorNode::get_main_control() { + return main_control; } void EditorNode::_editor_select(int p_which) { @@ -3655,7 +3673,7 @@ void EditorNode::register_editor_types() { ClassDB::register_class<EditorFeatureProfile>(); ClassDB::register_class<EditorSpinSlider>(); ClassDB::register_class<EditorSceneImporterMesh>(); - ClassDB::register_class<EditorSceneImporterMeshNode>(); + ClassDB::register_class<EditorSceneImporterMeshNode3D>(); ClassDB::register_virtual_class<FileSystemDock>(); @@ -3805,7 +3823,7 @@ Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String } Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p_fallback) const { - ERR_FAIL_COND_V_MSG(p_class.empty(), nullptr, "Class name cannot be empty."); + ERR_FAIL_COND_V_MSG(p_class.is_empty(), nullptr, "Class name cannot be empty."); if (ScriptServer::is_global_class(p_class)) { Ref<ImageTexture> icon; @@ -4000,16 +4018,16 @@ void EditorNode::_dock_make_float() { window->set_title(dock->get_name()); Panel *p = memnew(Panel); p->set_mode(Panel::MODE_FOREGROUND); - p->set_anchors_and_margins_preset(Control::PRESET_WIDE); + p->set_anchors_and_offsets_preset(Control::PRESET_WIDE); window->add_child(p); MarginContainer *margin = memnew(MarginContainer); - margin->set_anchors_and_margins_preset(Control::PRESET_WIDE); + margin->set_anchors_and_offsets_preset(Control::PRESET_WIDE); margin->add_theme_constant_override("margin_right", borders.width); margin->add_theme_constant_override("margin_top", borders.height); margin->add_theme_constant_override("margin_left", borders.width); margin->add_theme_constant_override("margin_bottom", borders.height); window->add_child(margin); - dock->set_anchors_and_margins_preset(Control::PRESET_WIDE); + dock->set_anchors_and_offsets_preset(Control::PRESET_WIDE); margin->add_child(dock); window->set_wrap_controls(true); window->set_size(dock_size); @@ -4537,7 +4555,7 @@ bool EditorNode::has_scenes_in_session() { return false; } Array scenes = config->get_value("EditorNode", "open_scenes"); - return !scenes.empty(); + return !scenes.is_empty(); } bool EditorNode::ensure_main_scene(bool p_from_native) { @@ -4763,7 +4781,7 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) { Ref<Shortcut> undo_close_tab_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene"); undo_close_tab_sc->set_name(TTR("Undo Close Tab")); scene_tabs_context_menu->add_shortcut(undo_close_tab_sc, FILE_OPEN_PREV); - if (previous_scenes.empty()) { + if (previous_scenes.is_empty()) { scene_tabs_context_menu->set_item_disabled(scene_tabs_context_menu->get_item_index(FILE_OPEN_PREV), true); } scene_tabs_context_menu->add_item(TTR("Close Other Tabs"), FILE_CLOSE_OTHERS); @@ -5167,7 +5185,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str next_file = sub_dir->get_next(); } - if (!sub_files.empty()) { + if (!sub_files.is_empty()) { dir->make_dir(to); _add_dropped_files_recursive(sub_files, to); } @@ -5694,10 +5712,6 @@ EditorNode::EditorNode() { import_obj2.instance(); import_scene->add_importer(import_obj2); - Ref<EditorSceneImporterGLTF> import_gltf; - import_gltf.instance(); - import_scene->add_importer(import_gltf); - Ref<EditorSceneImporterESCN> import_escn; import_escn.instance(); import_scene->add_importer(import_escn); @@ -5777,11 +5791,11 @@ EditorNode::EditorNode() { theme_base = memnew(Control); add_child(theme_base); - theme_base->set_anchors_and_margins_preset(Control::PRESET_WIDE); + theme_base->set_anchors_and_offsets_preset(Control::PRESET_WIDE); gui_base = memnew(Panel); theme_base->add_child(gui_base); - gui_base->set_anchors_and_margins_preset(Control::PRESET_WIDE); + gui_base->set_anchors_and_offsets_preset(Control::PRESET_WIDE); theme_base->set_theme(theme); gui_base->set_theme(theme); @@ -5793,13 +5807,13 @@ EditorNode::EditorNode() { gui_base->add_child(progress_dialog); // take up all screen - gui_base->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END); - gui_base->set_anchor(MARGIN_BOTTOM, Control::ANCHOR_END); + gui_base->set_anchor(SIDE_RIGHT, Control::ANCHOR_END); + gui_base->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END); gui_base->set_end(Point2(0, 0)); main_vbox = memnew(VBoxContainer); gui_base->add_child(main_vbox); - main_vbox->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8); + main_vbox->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8); main_vbox->add_theme_constant_override("separation", 8 * EDSCALE); menu_hb = memnew(HBoxContainer); @@ -6027,10 +6041,10 @@ EditorNode::EditorNode() { scene_root->set_disable_input(true); scene_root->set_as_audio_listener_2d(true); - viewport = memnew(VBoxContainer); - viewport->set_v_size_flags(Control::SIZE_EXPAND_FILL); - viewport->add_theme_constant_override("separation", 0); - scene_root_parent->add_child(viewport); + main_control = memnew(VBoxContainer); + main_control->set_v_size_flags(Control::SIZE_EXPAND_FILL); + main_control->add_theme_constant_override("separation", 0); + scene_root_parent->add_child(main_control); HBoxContainer *left_menu_hb = memnew(HBoxContainer); menu_hb->add_child(left_menu_hb); @@ -6936,8 +6950,8 @@ void EditorPluginList::remove_plugin(EditorPlugin *p_plugin) { plugins_list.erase(p_plugin); } -bool EditorPluginList::empty() { - return plugins_list.empty(); +bool EditorPluginList::is_empty() { + return plugins_list.is_empty(); } void EditorPluginList::clear() { diff --git a/editor/editor_node.h b/editor/editor_node.h index ab8d268801..9ebc0f522c 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -255,7 +255,7 @@ private: Control *vp_base; HBoxContainer *menu_hb; - Control *viewport; + Control *main_control; MenuButton *file_menu; MenuButton *project_menu; MenuButton *debug_menu; @@ -728,7 +728,7 @@ public: bool is_changing_scene() const; static EditorLog *get_log() { return singleton->log; } - Control *get_viewport(); + Control *get_main_control(); void set_edited_scene(Node *p_scene); @@ -903,7 +903,7 @@ public: void add_plugin(EditorPlugin *p_plugin); void remove_plugin(EditorPlugin *p_plugin); void clear(); - bool empty(); + bool is_empty(); EditorPluginList(); ~EditorPluginList(); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index f974ba9998..76912c8925 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -128,7 +128,7 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh Main::iteration(); Main::iteration(); Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); - ERR_CONTINUE(!img.is_valid() || img->empty()); + ERR_CONTINUE(!img.is_valid() || img->is_empty()); Ref<ImageTexture> it(memnew(ImageTexture)); it->create_from_image(img); @@ -152,8 +152,8 @@ void EditorInterface::set_main_screen_editor(const String &p_name) { EditorNode::get_singleton()->select_editor_by_name(p_name); } -Control *EditorInterface::get_editor_viewport() { - return EditorNode::get_singleton()->get_viewport(); +Control *EditorInterface::get_editor_main_control() { + return EditorNode::get_singleton()->get_main_control(); } void EditorInterface::edit_resource(const Ref<Resource> &p_resource) { @@ -319,7 +319,7 @@ void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &EditorInterface::get_edited_scene_root); ClassDB::bind_method(D_METHOD("get_resource_previewer"), &EditorInterface::get_resource_previewer); ClassDB::bind_method(D_METHOD("get_resource_filesystem"), &EditorInterface::get_resource_file_system); - ClassDB::bind_method(D_METHOD("get_editor_viewport"), &EditorInterface::get_editor_viewport); + ClassDB::bind_method(D_METHOD("get_editor_main_control"), &EditorInterface::get_editor_main_control); ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews); ClassDB::bind_method(D_METHOD("select_file", "file"), &EditorInterface::select_file); ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 03908b43ca..1697b79216 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -69,7 +69,7 @@ protected: public: static EditorInterface *get_singleton() { return singleton; } - Control *get_editor_viewport(); + Control *get_editor_main_control(); void edit_resource(const Ref<Resource> &p_resource); void open_scene_from_path(const String &scene_path); void reload_scene_from_path(const String &scene_path); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 523e65babe..972fd0723a 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2356,7 +2356,7 @@ void EditorPropertyResource::_file_selected(const String &p_path) { property_types = E->get().hint_string; } } - if (!property_types.empty()) { + if (!property_types.is_empty()) { bool any_type_matches = false; const Vector<String> split_property_types = property_types.split(","); for (int i = 0; i < split_property_types.size(); ++i) { @@ -2514,7 +2514,7 @@ void EditorPropertyResource::_menu_option(int p_which) { update_property(); break; } - ERR_FAIL_COND(inheritors_array.empty()); + ERR_FAIL_COND(inheritors_array.is_empty()); String intype = inheritors_array[p_which - TYPE_BASE_ID]; @@ -2590,7 +2590,7 @@ void EditorPropertyResource::_resource_preview(const String &p_path, const Ref<T } if (p_preview.is_valid()) { - preview->set_margin(MARGIN_LEFT, assign->get_icon()->get_width() + assign->get_theme_stylebox("normal")->get_default_margin(MARGIN_LEFT) + get_theme_constant("hseparation", "Button")); + preview->set_offset(SIDE_LEFT, assign->get_icon()->get_width() + assign->get_theme_stylebox("normal")->get_default_margin(SIDE_LEFT) + get_theme_constant("hseparation", "Button")); if (type == "GradientTexture") { preview->set_stretch_mode(TextureRect::STRETCH_SCALE); assign->set_custom_minimum_size(Size2(1, 1)); @@ -2658,7 +2658,7 @@ void EditorPropertyResource::_update_menu_items() { bool is_custom_resource = false; Ref<Texture2D> icon; - if (!custom_resources.empty()) { + if (!custom_resources.is_empty()) { for (int j = 0; j < custom_resources.size(); j++) { if (custom_resources[j].name == t) { is_custom_resource = true; @@ -3167,10 +3167,10 @@ EditorPropertyResource::EditorPropertyResource() { preview = memnew(TextureRect); preview->set_expand(true); - preview->set_anchors_and_margins_preset(PRESET_WIDE); - preview->set_margin(MARGIN_TOP, 1); - preview->set_margin(MARGIN_BOTTOM, -1); - preview->set_margin(MARGIN_RIGHT, -1); + preview->set_anchors_and_offsets_preset(PRESET_WIDE); + preview->set_offset(SIDE_TOP, 1); + preview->set_offset(SIDE_BOTTOM, -1); + preview->set_offset(SIDE_RIGHT, -1); assign->add_child(preview); assign->connect("gui_input", callable_mp(this, &EditorPropertyResource::_button_input)); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 56fbfbd0c2..774c08c4f0 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -550,7 +550,7 @@ void EditorPropertyArray::_length_changed(double p_page) { void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint_string) { array_type = p_array_type; - if (array_type == Variant::ARRAY && !p_hint_string.empty()) { + if (array_type == Variant::ARRAY && !p_hint_string.is_empty()) { int hint_subtype_separator = p_hint_string.find(":"); if (hint_subtype_separator >= 0) { String subtype_string = p_hint_string.substr(0, hint_subtype_separator); @@ -975,7 +975,7 @@ void EditorPropertyDictionary::update_property() { Ref<StyleBoxFlat> flat; flat.instance(); for (int j = 0; j < 4; j++) { - flat->set_default_margin(Margin(j), 2 * EDSCALE); + flat->set_default_margin(Side(j), 2 * EDSCALE); } flat->set_bg_color(get_theme_color("prop_subsection", "Editor")); diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index 639da371bd..3ebcd16275 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -46,7 +46,7 @@ void EditorRunNative::_notification(int p_what) { Ref<Image> im = icon->get_data(); im = im->duplicate(); im->clear_mipmaps(); - if (!im->empty()) { + if (!im->is_empty()) { im->resize(16 * EDSCALE, 16 * EDSCALE); Ref<ImageTexture> small_icon; small_icon.instance(); diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index bc9ca15467..691f2e8228 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -234,7 +234,7 @@ void SectionedInspector::update_category_list() { continue; } - if (!filter.empty() && pi.name.findn(filter) == -1 && pi.name.replace("/", " ").capitalize().findn(filter) == -1) { + if (!filter.is_empty() && pi.name.findn(filter) == -1 && pi.name.replace("/", " ").capitalize().findn(filter) == -1) { continue; } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index e88f27c857..3d131d373a 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -281,7 +281,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { locales_to_skip.push_back("te"); // Telugu } - if (!locales_to_skip.empty()) { + if (!locales_to_skip.is_empty()) { WARN_PRINT("Some locales are not properly supported by selected Text Server and are disabled."); } @@ -628,6 +628,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Animation _initial_set("editors/animation/autorename_animation_tracks", true); _initial_set("editors/animation/confirm_insert_track", true); + _initial_set("editors/animation/default_create_bezier_tracks", false); + _initial_set("editors/animation/default_create_reset_tracks", true); _initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0)); _initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 0)); @@ -1474,7 +1476,7 @@ bool EditorSettings::is_default_text_editor_theme() { Vector<String> EditorSettings::get_script_templates(const String &p_extension, const String &p_custom_path) { Vector<String> templates; String template_dir = get_script_templates_dir(); - if (!p_custom_path.empty()) { + if (!p_custom_path.is_empty()) { template_dir = p_custom_path; } DirAccess *d = DirAccess::open(template_dir); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index d72510d40d..4a37d26a26 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -202,7 +202,7 @@ void EditorSpinSlider::_notification(int p_what) { // EditorSpinSliders with a label have more space on the left, so add an // higher margin to match the location where the text begins. // The margin values below were determined by empirical testing. - stylebox->set_default_margin(MARGIN_LEFT, (get_label() != String() ? 23 : 16) * EDSCALE); + stylebox->set_default_margin(SIDE_LEFT, (get_label() != String() ? 23 : 16) * EDSCALE); value_input->add_theme_style_override("normal", stylebox); } @@ -256,7 +256,7 @@ void EditorSpinSlider::_notification(int p_what) { if (get_step() == 1) { Ref<Texture2D> updown2 = get_theme_icon("updown", "SpinBox"); int updown_vofs = (get_size().height - updown2->get_height()) / 2; - updown_offset = get_size().width - sb->get_margin(MARGIN_RIGHT) - updown2->get_width(); + updown_offset = get_size().width - sb->get_margin(SIDE_RIGHT) - updown2->get_width(); Color c(1, 1, 1); if (hover_updown) { c *= Color(1.2, 1.2, 1.2); @@ -500,7 +500,7 @@ EditorSpinSlider::EditorSpinSlider() { value_input = memnew(LineEdit); value_input_popup->add_child(value_input); value_input_popup->set_wrap_controls(true); - value_input->set_anchors_and_margins_preset(PRESET_WIDE); + value_input->set_anchors_and_offsets_preset(PRESET_WIDE); value_input_popup->connect("popup_hide", callable_mp(this, &EditorSpinSlider::_value_input_closed)); value_input->connect("text_entered", callable_mp(this, &EditorSpinSlider::_value_input_entered)); value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited)); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 35de38fad2..7582c2073f 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -44,34 +44,34 @@ static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_botton, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_botton = -1, bool p_draw_center = true) { Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); style->set_texture(p_texture); - style->set_margin_size(MARGIN_LEFT, p_left * EDSCALE); - style->set_margin_size(MARGIN_RIGHT, p_right * EDSCALE); - style->set_margin_size(MARGIN_BOTTOM, p_botton * EDSCALE); - style->set_margin_size(MARGIN_TOP, p_top * EDSCALE); - style->set_default_margin(MARGIN_LEFT, p_margin_left * EDSCALE); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * EDSCALE); - style->set_default_margin(MARGIN_BOTTOM, p_margin_botton * EDSCALE); - style->set_default_margin(MARGIN_TOP, p_margin_top * EDSCALE); + style->set_margin_size(SIDE_LEFT, p_left * EDSCALE); + style->set_margin_size(SIDE_RIGHT, p_right * EDSCALE); + style->set_margin_size(SIDE_BOTTOM, p_botton * EDSCALE); + style->set_margin_size(SIDE_TOP, p_top * EDSCALE); + style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE); + style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE); + style->set_default_margin(SIDE_BOTTOM, p_margin_botton * EDSCALE); + style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE); style->set_draw_center(p_draw_center); return style; } static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty)); - style->set_default_margin(MARGIN_LEFT, p_margin_left * EDSCALE); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * EDSCALE); - style->set_default_margin(MARGIN_BOTTOM, p_margin_bottom * EDSCALE); - style->set_default_margin(MARGIN_TOP, p_margin_top * EDSCALE); + style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE); + style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE); + style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE); return style; } static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBoxFlat> style(memnew(StyleBoxFlat)); style->set_bg_color(p_color); - style->set_default_margin(MARGIN_LEFT, p_margin_left * EDSCALE); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * EDSCALE); - style->set_default_margin(MARGIN_BOTTOM, p_margin_bottom * EDSCALE); - style->set_default_margin(MARGIN_TOP, p_margin_top * EDSCALE); + style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE); + style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE); + style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE); return style; } @@ -477,10 +477,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const float extra_spacing = EDITOR_GET("interface/theme/additional_spacing"); Ref<StyleBoxFlat> style_widget = style_default->duplicate(); - style_widget->set_default_margin(MARGIN_LEFT, (extra_spacing + 6) * EDSCALE); - style_widget->set_default_margin(MARGIN_TOP, (extra_spacing + default_margin_size) * EDSCALE); - style_widget->set_default_margin(MARGIN_RIGHT, (extra_spacing + 6) * EDSCALE); - style_widget->set_default_margin(MARGIN_BOTTOM, (extra_spacing + default_margin_size) * EDSCALE); + style_widget->set_default_margin(SIDE_LEFT, (extra_spacing + 6) * EDSCALE); + style_widget->set_default_margin(SIDE_TOP, (extra_spacing + default_margin_size) * EDSCALE); + style_widget->set_default_margin(SIDE_RIGHT, (extra_spacing + 6) * EDSCALE); + style_widget->set_default_margin(SIDE_BOTTOM, (extra_spacing + default_margin_size) * EDSCALE); style_widget->set_bg_color(dark_color_1); style_widget->set_border_color(dark_color_2); @@ -500,10 +500,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // style for windows, popups, etc.. Ref<StyleBoxFlat> style_popup = style_default->duplicate(); const int popup_margin_size = default_margin_size * EDSCALE * 2; - style_popup->set_default_margin(MARGIN_LEFT, popup_margin_size); - style_popup->set_default_margin(MARGIN_TOP, popup_margin_size); - style_popup->set_default_margin(MARGIN_RIGHT, popup_margin_size); - style_popup->set_default_margin(MARGIN_BOTTOM, popup_margin_size); + style_popup->set_default_margin(SIDE_LEFT, popup_margin_size); + style_popup->set_default_margin(SIDE_TOP, popup_margin_size); + style_popup->set_default_margin(SIDE_RIGHT, popup_margin_size); + style_popup->set_default_margin(SIDE_BOTTOM, popup_margin_size); style_popup->set_border_color(contrast_color_1); style_popup->set_border_width_all(MAX(EDSCALE, border_width)); const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1); @@ -536,13 +536,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_tab_selected = style_widget->duplicate(); style_tab_selected->set_border_width_all(border_width); - style_tab_selected->set_border_width(MARGIN_BOTTOM, 0); + style_tab_selected->set_border_width(SIDE_BOTTOM, 0); style_tab_selected->set_border_color(dark_color_3); - style_tab_selected->set_expand_margin_size(MARGIN_BOTTOM, border_width); - style_tab_selected->set_default_margin(MARGIN_LEFT, tab_default_margin_side); - style_tab_selected->set_default_margin(MARGIN_RIGHT, tab_default_margin_side); - style_tab_selected->set_default_margin(MARGIN_BOTTOM, tab_default_margin_vertical); - style_tab_selected->set_default_margin(MARGIN_TOP, tab_default_margin_vertical); + style_tab_selected->set_expand_margin_size(SIDE_BOTTOM, border_width); + style_tab_selected->set_default_margin(SIDE_LEFT, tab_default_margin_side); + style_tab_selected->set_default_margin(SIDE_RIGHT, tab_default_margin_side); + style_tab_selected->set_default_margin(SIDE_BOTTOM, tab_default_margin_vertical); + style_tab_selected->set_default_margin(SIDE_TOP, tab_default_margin_vertical); style_tab_selected->set_bg_color(tab_color); Ref<StyleBoxFlat> style_tab_unselected = style_tab_selected->duplicate(); @@ -580,7 +580,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_menu_hover_border = style_widget->duplicate(); style_menu_hover_border->set_draw_center(false); style_menu_hover_border->set_border_width_all(0); - style_menu_hover_border->set_border_width(MARGIN_BOTTOM, border_width); + style_menu_hover_border->set_border_width(SIDE_BOTTOM, border_width); style_menu_hover_border->set_border_color(accent_color); Ref<StyleBoxFlat> style_menu_hover_bg = style_widget->duplicate(); @@ -668,10 +668,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Checkbox Ref<StyleBoxFlat> sb_checkbox = style_menu->duplicate(); - sb_checkbox->set_default_margin(MARGIN_LEFT, default_margin_size * EDSCALE); - sb_checkbox->set_default_margin(MARGIN_RIGHT, default_margin_size * EDSCALE); - sb_checkbox->set_default_margin(MARGIN_TOP, default_margin_size * EDSCALE); - sb_checkbox->set_default_margin(MARGIN_BOTTOM, default_margin_size * EDSCALE); + sb_checkbox->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE); + sb_checkbox->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE); + sb_checkbox->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE); + sb_checkbox->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE); theme->set_stylebox("normal", "CheckBox", sb_checkbox); theme->set_stylebox("pressed", "CheckBox", sb_checkbox); @@ -697,10 +697,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // PopupMenu const int popup_menu_margin_size = default_margin_size * 1.5 * EDSCALE; Ref<StyleBoxFlat> style_popup_menu = style_popup->duplicate(); - style_popup_menu->set_default_margin(MARGIN_LEFT, popup_menu_margin_size); - style_popup_menu->set_default_margin(MARGIN_TOP, popup_menu_margin_size); - style_popup_menu->set_default_margin(MARGIN_RIGHT, popup_menu_margin_size); - style_popup_menu->set_default_margin(MARGIN_BOTTOM, popup_menu_margin_size); + style_popup_menu->set_default_margin(SIDE_LEFT, popup_menu_margin_size); + style_popup_menu->set_default_margin(SIDE_TOP, popup_menu_margin_size); + style_popup_menu->set_default_margin(SIDE_RIGHT, popup_menu_margin_size); + style_popup_menu->set_default_margin(SIDE_BOTTOM, popup_menu_margin_size); theme->set_stylebox("panel", "PopupMenu", style_popup_menu); theme->set_stylebox("separator", "PopupMenu", style_popup_separator); @@ -724,9 +724,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_constant("vseparation", "PopupMenu", (extra_spacing + default_margin_size + 1) * EDSCALE); Ref<StyleBoxFlat> sub_inspector_bg = make_flat_stylebox(dark_color_1.lerp(accent_color, 0.08), 2, 0, 2, 2); - sub_inspector_bg->set_border_width(MARGIN_LEFT, 2); - sub_inspector_bg->set_border_width(MARGIN_RIGHT, 2); - sub_inspector_bg->set_border_width(MARGIN_BOTTOM, 2); + sub_inspector_bg->set_border_width(SIDE_LEFT, 2); + sub_inspector_bg->set_border_width(SIDE_RIGHT, 2); + sub_inspector_bg->set_border_width(SIDE_BOTTOM, 2); sub_inspector_bg->set_border_color(accent_color * Color(1, 1, 1, 0.3)); sub_inspector_bg->set_draw_center(true); @@ -866,17 +866,17 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_content_panel->set_border_color(dark_color_3); style_content_panel->set_border_width_all(border_width); // compensate the border - style_content_panel->set_default_margin(MARGIN_TOP, margin_size_extra * EDSCALE); - style_content_panel->set_default_margin(MARGIN_RIGHT, margin_size_extra * EDSCALE); - style_content_panel->set_default_margin(MARGIN_BOTTOM, margin_size_extra * EDSCALE); - style_content_panel->set_default_margin(MARGIN_LEFT, margin_size_extra * EDSCALE); + style_content_panel->set_default_margin(SIDE_TOP, margin_size_extra * EDSCALE); + style_content_panel->set_default_margin(SIDE_RIGHT, margin_size_extra * EDSCALE); + style_content_panel->set_default_margin(SIDE_BOTTOM, margin_size_extra * EDSCALE); + style_content_panel->set_default_margin(SIDE_LEFT, margin_size_extra * EDSCALE); // this is the stylebox used in 3d and 2d viewports (no borders) Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate(); - style_content_panel_vp->set_default_margin(MARGIN_LEFT, border_width * 2); - style_content_panel_vp->set_default_margin(MARGIN_TOP, default_margin_size * EDSCALE); - style_content_panel_vp->set_default_margin(MARGIN_RIGHT, border_width * 2); - style_content_panel_vp->set_default_margin(MARGIN_BOTTOM, border_width * 2); + style_content_panel_vp->set_default_margin(SIDE_LEFT, border_width * 2); + style_content_panel_vp->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE); + style_content_panel_vp->set_default_margin(SIDE_RIGHT, border_width * 2); + style_content_panel_vp->set_default_margin(SIDE_BOTTOM, border_width * 2); theme->set_stylebox("panel", "TabContainer", style_content_panel); theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp); @@ -887,13 +887,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Debugger Ref<StyleBoxFlat> style_panel_debugger = style_content_panel->duplicate(); - style_panel_debugger->set_border_width(MARGIN_BOTTOM, 0); + style_panel_debugger->set_border_width(SIDE_BOTTOM, 0); theme->set_stylebox("DebuggerPanel", "EditorStyles", style_panel_debugger); Ref<StyleBoxFlat> style_panel_invisible_top = style_content_panel->duplicate(); - int stylebox_offset = theme->get_font("tab_fg", "TabContainer")->get_height(theme->get_font_size("tab_fg", "TabContainer")) + theme->get_stylebox("tab_fg", "TabContainer")->get_minimum_size().height + theme->get_stylebox("panel", "TabContainer")->get_default_margin(MARGIN_TOP); - style_panel_invisible_top->set_expand_margin_size(MARGIN_TOP, -stylebox_offset); - style_panel_invisible_top->set_default_margin(MARGIN_TOP, 0); + int stylebox_offset = theme->get_font("tab_fg", "TabContainer")->get_height(theme->get_font_size("tab_fg", "TabContainer")) + theme->get_stylebox("tab_fg", "TabContainer")->get_minimum_size().height + theme->get_stylebox("panel", "TabContainer")->get_default_margin(SIDE_TOP); + style_panel_invisible_top->set_expand_margin_size(SIDE_TOP, -stylebox_offset); + style_panel_invisible_top->set_default_margin(SIDE_TOP, 0); theme->set_stylebox("BottomPanelDebuggerOverride", "EditorStyles", style_panel_invisible_top); // LineEdit @@ -958,8 +958,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // WindowDialog Ref<StyleBoxFlat> style_window = style_popup->duplicate(); style_window->set_border_color(tab_color); - style_window->set_border_width(MARGIN_TOP, 24 * EDSCALE); - style_window->set_expand_margin_size(MARGIN_TOP, 24 * EDSCALE); + style_window->set_border_width(SIDE_TOP, 24 * EDSCALE); + style_window->set_expand_margin_size(SIDE_TOP, 24 * EDSCALE); theme->set_stylebox("panel", "Window", style_default); theme->set_stylebox("panel_window", "Window", style_window); @@ -1055,10 +1055,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // TooltipPanel Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate(); float v = MAX(border_size * EDSCALE, 1.0); - style_tooltip->set_default_margin(MARGIN_LEFT, v); - style_tooltip->set_default_margin(MARGIN_TOP, v); - style_tooltip->set_default_margin(MARGIN_RIGHT, v); - style_tooltip->set_default_margin(MARGIN_BOTTOM, v); + style_tooltip->set_default_margin(SIDE_LEFT, v); + style_tooltip->set_default_margin(SIDE_TOP, v); + style_tooltip->set_default_margin(SIDE_RIGHT, v); + style_tooltip->set_default_margin(SIDE_BOTTOM, v); style_tooltip->set_bg_color(Color(mono_color.r, mono_color.g, mono_color.b, 0.9)); style_tooltip->set_border_width_all(border_width); style_tooltip->set_border_color(mono_color); @@ -1155,10 +1155,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { smgraphsbselected->set_shadow_color(shadow_color); if (use_gn_headers) { - graphsb->set_border_width(MARGIN_TOP, 24 * EDSCALE); - graphsbselected->set_border_width(MARGIN_TOP, 24 * EDSCALE); - graphsbcomment->set_border_width(MARGIN_TOP, 24 * EDSCALE); - graphsbcommentselected->set_border_width(MARGIN_TOP, 24 * EDSCALE); + graphsb->set_border_width(SIDE_TOP, 24 * EDSCALE); + graphsbselected->set_border_width(SIDE_TOP, 24 * EDSCALE); + graphsbcomment->set_border_width(SIDE_TOP, 24 * EDSCALE); + graphsbcommentselected->set_border_width(SIDE_TOP, 24 * EDSCALE); } theme->set_stylebox("frame", "GraphNode", graphsb); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 6c8bd1901e..e7a621eee6 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -531,7 +531,7 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa } String file_name = p_path.get_file(); - if (!file_name.empty()) { + if (!file_name.is_empty()) { for (int i = 0; i < files->get_item_count(); i++) { if (files->get_item_text(i) == file_name) { files->select(i, true); @@ -1528,7 +1528,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove if (!p_overwrite) { to_move_path = p_to_path; Vector<String> conflicting_items = _check_existing(); - if (!conflicting_items.empty()) { + if (!conflicting_items.is_empty()) { // Ask to do something. overwrite_dialog->set_text(vformat( TTR("The following files or folders conflict with items in the target location '%s':\n\n%s\n\nDo you wish to overwrite them?"), @@ -1721,7 +1721,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected paths.push_back(fpath); } } - if (!paths.empty()) { + if (!paths.is_empty()) { emit_signal("instance", paths); } } break; @@ -1753,7 +1753,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected case FILE_DEPENDENCIES: { // Checkout the file dependencies. - if (!p_selected.empty()) { + if (!p_selected.is_empty()) { String fpath = p_selected[0]; deps_editor->edit(fpath); } @@ -1761,7 +1761,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected case FILE_OWNERS: { // Checkout the file owners. - if (!p_selected.empty()) { + if (!p_selected.is_empty()) { String fpath = p_selected[0]; owners_editor->show(fpath); } @@ -1784,7 +1784,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected case FILE_RENAME: { // Rename the active file. - if (!p_selected.empty()) { + if (!p_selected.is_empty()) { to_rename.path = p_selected[0]; if (to_rename.path != "res://") { to_rename.is_file = !to_rename.path.ends_with("/"); @@ -1885,7 +1885,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected } break; case FILE_COPY_PATH: { - if (!p_selected.empty()) { + if (!p_selected.is_empty()) { String fpath = p_selected[0]; DisplayServer::get_singleton()->clipboard_set(fpath); } @@ -2013,7 +2013,7 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from) all_not_favorites = true; } - if (paths.empty()) { + if (paths.is_empty()) { return Variant(); } @@ -2061,7 +2061,7 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da String to_dir; bool favorite; _get_drag_target_folder(to_dir, favorite, p_point, p_from); - return !to_dir.empty(); + return !to_dir.is_empty(); } if (drag_data.has("type") && (String(drag_data["type"]) == "files" || String(drag_data["type"]) == "files_and_dirs")) { @@ -2074,7 +2074,7 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da return true; } - if (to_dir.empty()) { + if (to_dir.is_empty()) { return false; } @@ -2169,7 +2169,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, String to_dir; bool favorite; _get_drag_target_folder(to_dir, favorite, p_point, p_from); - if (res.is_valid() && !to_dir.empty()) { + if (res.is_valid() && !to_dir.is_empty()) { EditorNode::get_singleton()->push_item(res.ptr()); EditorNode::get_singleton()->save_resource_as(res, to_dir); } @@ -2180,7 +2180,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, String to_dir; bool favorite; _get_drag_target_folder(to_dir, favorite, p_point, p_from); - if (!to_dir.empty()) { + if (!to_dir.is_empty()) { Vector<String> fnames = drag_data["files"]; to_move.clear(); for (int i = 0; i < fnames.size(); i++) { @@ -2188,7 +2188,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, to_move.push_back(FileOrFolder(fnames[i], !fnames[i].ends_with("/"))); } } - if (!to_move.empty()) { + if (!to_move.is_empty()) { if (Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { for (int i = 0; i < to_move.size(); i++) { String new_path; @@ -2291,7 +2291,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths, bool p_display_path_dependent_options) { // Add options for files and folders. - ERR_FAIL_COND_MSG(p_paths.empty(), "Path cannot be empty."); + ERR_FAIL_COND_MSG(p_paths.is_empty(), "Path cannot be empty."); Vector<String> filenames; Vector<String> foldernames; @@ -2414,7 +2414,7 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) { } // Popup. - if (!paths.empty()) { + if (!paths.is_empty()) { tree_popup->set_size(Size2(1, 1)); _file_and_folders_fill_popup(tree_popup, paths); tree_popup->set_position(tree->get_screen_position() + p_pos); @@ -2447,14 +2447,14 @@ void FileSystemDock::_file_list_rmb_select(int p_item, const Vector2 &p_pos) { continue; } if (files->get_item_text(p_item) == "..") { - files->unselect(i); + files->deselect(i); continue; } paths.push_back(files->get_item_metadata(i)); } // Popup. - if (!paths.empty()) { + if (!paths.is_empty()) { file_list_popup->clear(); file_list_popup->set_size(Size2(1, 1)); _file_and_folders_fill_popup(file_list_popup, paths, searched_string.length() == 0); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 076b873eac..ac4acc613f 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -294,10 +294,10 @@ FindInFilesDialog::FindInFilesDialog() { set_title(TTR("Find in Files")); VBoxContainer *vbc = memnew(VBoxContainer); - vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE); add_child(vbc); GridContainer *gc = memnew(GridContainer); @@ -499,8 +499,8 @@ void FindInFilesDialog::_on_search_text_modified(String text) { ERR_FAIL_COND(!_find_button); ERR_FAIL_COND(!_replace_button); - _find_button->set_disabled(get_search_text().empty()); - _replace_button->set_disabled(get_search_text().empty()); + _find_button->set_disabled(get_search_text().is_empty()); + _replace_button->set_disabled(get_search_text().is_empty()); } void FindInFilesDialog::_on_search_text_entered(String text) { @@ -551,10 +551,10 @@ FindInFilesPanel::FindInFilesPanel() { add_child(_finder); VBoxContainer *vbc = memnew(VBoxContainer); - vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0); - vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0); - vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); - vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); + vbc->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0); + vbc->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); + vbc->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + vbc->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); add_child(vbc); { diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 32c50321d7..55bd475543 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -198,7 +198,7 @@ void GroupDialog::_add_group(String p_name) { } String name = p_name.strip_edges(); - if (name.empty() || groups->get_item_with_text(name)) { + if (name.is_empty() || groups->get_item_with_text(name)) { return; } @@ -413,7 +413,7 @@ GroupDialog::GroupDialog() { VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); - vbc->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + vbc->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); HBoxContainer *hbc = memnew(HBoxContainer); vbc->add_child(hbc); @@ -534,7 +534,7 @@ GroupDialog::GroupDialog() { group_empty->set_autowrap(true); group_empty->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); nodes_to_remove->add_child(group_empty); - group_empty->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + group_empty->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); set_title(TTR("Group Editor")); @@ -551,7 +551,7 @@ void GroupsEditor::_add_group(const String &p_group) { } const String name = group_name->get_text().strip_edges(); - if (name.empty()) { + if (name.is_empty()) { return; } diff --git a/editor/icons/GuiToggleOn.svg b/editor/icons/GuiToggleOn.svg index 8ab0998f71..37b47e8de4 100644 --- a/editor/icons/GuiToggleOn.svg +++ b/editor/icons/GuiToggleOn.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 38 15.999999" width="38" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.878 0-7 3.122-7 7s3.122 7 7 7h22c3.878 0 7-3.122 7-7s-3.122-7-7-7zm22 2a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5z" fill="#e0e0e0" stroke-width="55.8958"/></svg> +<svg height="16" viewBox="0 0 38 15.999999" width="38" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-4 0-7 3.0000002-7 7.0000002 0 3.9999998 3 6.9999998 7 6.9999998h22c4 0 7-3 7-6.9999998 0-4-3-7.0000002-7-7.0000002-7.333334 0-14.55609 0-22 0z" fill="#699ce8"/><circle cx="30" cy="8" fill="#fefefe" r="5"/></svg> diff --git a/editor/icons/GuiToggleOnMirrored.svg b/editor/icons/GuiToggleOnMirrored.svg index 7339b6efd2..fa7f602ee7 100644 --- a/editor/icons/GuiToggleOnMirrored.svg +++ b/editor/icons/GuiToggleOnMirrored.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="42" height="26"><path fill="#e0e0e0" d="M31 5c4.986 0 9 3.568 9 8s-4.014 8-9 8H11c-4.986 0-9-3.568-9-8s4.014-8 9-8zM10 8a-5 5 0 0 0-5 5-5 5 0 0 0 5 5-5 5 0 0 0 5-5-5 5 0 0 0-5-5z"/></svg> +<svg height="26" width="42" xmlns="http://www.w3.org/2000/svg"><path d="m31 5c4.986 0 9 3.568 9 8s-4.014 8-9 8h-20c-4.986 0-9-3.568-9-8s4.014-8 9-8z" fill="#699ce8"/><circle cx="10" cy="13" fill="#fefefe" r="5"/></svg> diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp index 8eb68ecdcf..91c4e3afd2 100644 --- a/editor/import/collada.cpp +++ b/editor/import/collada.cpp @@ -1365,7 +1365,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) { } if (geom->controller) { - if (geom->skeletons.empty()) { + if (geom->skeletons.is_empty()) { //XSI style if (state.skin_controller_data_map.has(geom->source)) { @@ -2321,7 +2321,7 @@ void Collada::_optimize() { i--; } - while (!mgeom.empty()) { + while (!mgeom.is_empty()) { Node *n = mgeom.front()->get(); n->parent->children.push_back(n); mgeom.pop_front(); diff --git a/editor/import/collada.h b/editor/import/collada.h index 29d49d4aa7..354a3e697a 100644 --- a/editor/import/collada.h +++ b/editor/import/collada.h @@ -274,7 +274,7 @@ public: if (normal == p_vert.normal) { if (uv == p_vert.uv) { if (uv2 == p_vert.uv2) { - if (!weights.empty() || !p_vert.weights.empty()) { + if (!weights.is_empty() || !p_vert.weights.is_empty()) { if (weights.size() == p_vert.weights.size()) { for (int i = 0; i < weights.size(); i++) { if (weights[i].bone_idx != p_vert.weights[i].bone_idx) { diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 4e93fe6f12..19a846bf37 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -33,6 +33,7 @@ #include "core/os/os.h" #include "editor/editor_node.h" #include "editor/import/collada.h" +#include "editor/import/scene_importer_mesh_node_3d.h" #include "scene/3d/camera_3d.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" @@ -278,8 +279,8 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) { node = memnew(Path3D); } else { //mesh since nothing else - node = memnew(EditorSceneImporterMeshNode); - //Object::cast_to<EditorSceneImporterMeshNode>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true); + node = memnew(EditorSceneImporterMeshNode3D); + //Object::cast_to<EditorSceneImporterMeshNode3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true); } } break; case Collada::Node::TYPE_SKELETON: { @@ -1003,10 +1004,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres } } - if (Object::cast_to<EditorSceneImporterMeshNode>(node)) { + if (Object::cast_to<EditorSceneImporterMeshNode3D>(node)) { Collada::NodeGeometry *ng2 = static_cast<Collada::NodeGeometry *>(p_node); - EditorSceneImporterMeshNode *mi = Object::cast_to<EditorSceneImporterMeshNode>(node); + EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(node); ERR_FAIL_COND_V(!mi, ERR_BUG); @@ -1026,7 +1027,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres Vector<String> skeletons = ng2->skeletons; - ERR_FAIL_COND_V(skeletons.empty(), ERR_INVALID_DATA); + ERR_FAIL_COND_V(skeletons.is_empty(), ERR_INVALID_DATA); String skname = skeletons[0]; ERR_FAIL_COND_V(!node_map.has(skname), ERR_INVALID_DATA); @@ -1470,7 +1471,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones } Vector<float> data = at.get_value_at_time(snapshots[i]); - ERR_CONTINUE(data.empty()); + ERR_CONTINUE(data.is_empty()); Collada::Node::XForm &xf = cn->xform_list.write[xform_idx]; diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp deleted file mode 100644 index 1059692ca0..0000000000 --- a/editor/import/editor_scene_importer_gltf.cpp +++ /dev/null @@ -1,3254 +0,0 @@ -/*************************************************************************/ -/* editor_scene_importer_gltf.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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_scene_importer_gltf.h" - -#include "core/crypto/crypto_core.h" -#include "core/io/json.h" -#include "core/math/disjoint_set.h" -#include "core/math/math_defs.h" -#include "core/os/file_access.h" -#include "core/os/os.h" -#include "modules/regex/regex.h" -#include "scene/3d/bone_attachment_3d.h" -#include "scene/3d/camera_3d.h" -#include "scene/3d/mesh_instance_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/resources/surface_tool.h" - -uint32_t EditorSceneImporterGLTF::get_import_flags() const { - return IMPORT_SCENE | IMPORT_ANIMATION; -} - -void EditorSceneImporterGLTF::get_extensions(List<String> *r_extensions) const { - r_extensions->push_back("gltf"); - r_extensions->push_back("glb"); -} - -Error EditorSceneImporterGLTF::_parse_json(const String &p_path, GLTFState &state) { - Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { - return err; - } - - Vector<uint8_t> array; - array.resize(f->get_len()); - f->get_buffer(array.ptrw(), array.size()); - String text; - text.parse_utf8((const char *)array.ptr(), array.size()); - - String err_txt; - int err_line; - Variant v; - err = JSON::parse(text, v, err_txt, err_line); - if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT); - return err; - } - state.json = v; - - return OK; -} - -Error EditorSceneImporterGLTF::_parse_glb(const String &p_path, GLTFState &state) { - Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { - return err; - } - - uint32_t magic = f->get_32(); - ERR_FAIL_COND_V(magic != 0x46546C67, ERR_FILE_UNRECOGNIZED); //glTF - f->get_32(); // version - f->get_32(); // length - - uint32_t chunk_length = f->get_32(); - uint32_t chunk_type = f->get_32(); - - ERR_FAIL_COND_V(chunk_type != 0x4E4F534A, ERR_PARSE_ERROR); //JSON - Vector<uint8_t> json_data; - json_data.resize(chunk_length); - uint32_t len = f->get_buffer(json_data.ptrw(), chunk_length); - ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT); - - String text; - text.parse_utf8((const char *)json_data.ptr(), json_data.size()); - - String err_txt; - int err_line; - Variant v; - err = JSON::parse(text, v, err_txt, err_line); - if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT); - return err; - } - - state.json = v; - - //data? - - chunk_length = f->get_32(); - chunk_type = f->get_32(); - - if (f->eof_reached()) { - return OK; //all good - } - - ERR_FAIL_COND_V(chunk_type != 0x004E4942, ERR_PARSE_ERROR); //BIN - - state.glb_data.resize(chunk_length); - len = f->get_buffer(state.glb_data.ptrw(), chunk_length); - ERR_FAIL_COND_V(len != chunk_length, ERR_FILE_CORRUPT); - - return OK; -} - -static Vector3 _arr_to_vec3(const Array &p_array) { - ERR_FAIL_COND_V(p_array.size() != 3, Vector3()); - return Vector3(p_array[0], p_array[1], p_array[2]); -} - -static Quat _arr_to_quat(const Array &p_array) { - ERR_FAIL_COND_V(p_array.size() != 4, Quat()); - return Quat(p_array[0], p_array[1], p_array[2], p_array[3]); -} - -static Transform _arr_to_xform(const Array &p_array) { - ERR_FAIL_COND_V(p_array.size() != 16, Transform()); - - Transform xform; - xform.basis.set_axis(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2])); - xform.basis.set_axis(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6])); - xform.basis.set_axis(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10])); - xform.set_origin(Vector3(p_array[12], p_array[13], p_array[14])); - - return xform; -} - -String EditorSceneImporterGLTF::_sanitize_scene_name(const String &name) { - RegEx regex("([^a-zA-Z0-9_ -]+)"); - String p_name = regex.sub(name, "", true); - return p_name; -} - -String EditorSceneImporterGLTF::_gen_unique_name(GLTFState &state, const String &p_name) { - const String s_name = _sanitize_scene_name(p_name); - - String name; - int index = 1; - while (true) { - name = s_name; - - if (index > 1) { - name += " " + itos(index); - } - if (!state.unique_names.has(name)) { - break; - } - index++; - } - - state.unique_names.insert(name); - - return name; -} - -String EditorSceneImporterGLTF::_sanitize_bone_name(const String &name) { - String p_name = name.camelcase_to_underscore(true); - - RegEx pattern_nocolon(":"); - p_name = pattern_nocolon.sub(p_name, "_", true); - - RegEx pattern_noslash("/"); - p_name = pattern_noslash.sub(p_name, "_", true); - - RegEx pattern_nospace(" +"); - p_name = pattern_nospace.sub(p_name, "_", true); - - RegEx pattern_multiple("_+"); - p_name = pattern_multiple.sub(p_name, "_", true); - - RegEx pattern_padded("0+(\\d+)"); - p_name = pattern_padded.sub(p_name, "$1", true); - - return p_name; -} - -String EditorSceneImporterGLTF::_gen_unique_bone_name(GLTFState &state, const GLTFSkeletonIndex skel_i, const String &p_name) { - String s_name = _sanitize_bone_name(p_name); - if (s_name.empty()) { - s_name = "bone"; - } - String name; - int index = 1; - while (true) { - name = s_name; - - if (index > 1) { - name += "_" + itos(index); - } - if (!state.skeletons[skel_i].unique_names.has(name)) { - break; - } - index++; - } - - state.skeletons.write[skel_i].unique_names.insert(name); - - return name; -} - -Error EditorSceneImporterGLTF::_parse_scenes(GLTFState &state) { - ERR_FAIL_COND_V(!state.json.has("scenes"), ERR_FILE_CORRUPT); - const Array &scenes = state.json["scenes"]; - int loaded_scene = 0; - if (state.json.has("scene")) { - loaded_scene = state.json["scene"]; - } else { - WARN_PRINT("The load-time scene is not defined in the glTF2 file. Picking the first scene."); - } - - if (scenes.size()) { - ERR_FAIL_COND_V(loaded_scene >= scenes.size(), ERR_FILE_CORRUPT); - const Dictionary &s = scenes[loaded_scene]; - ERR_FAIL_COND_V(!s.has("nodes"), ERR_UNAVAILABLE); - const Array &nodes = s["nodes"]; - for (int j = 0; j < nodes.size(); j++) { - state.root_nodes.push_back(nodes[j]); - } - - if (s.has("name") && s["name"] != "") { - state.scene_name = _gen_unique_name(state, s["name"]); - } else { - state.scene_name = _gen_unique_name(state, "Scene"); - } - } - - return OK; -} - -Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) { - ERR_FAIL_COND_V(!state.json.has("nodes"), ERR_FILE_CORRUPT); - const Array &nodes = state.json["nodes"]; - for (int i = 0; i < nodes.size(); i++) { - GLTFNode *node = memnew(GLTFNode); - const Dictionary &n = nodes[i]; - - if (n.has("name")) { - node->name = n["name"]; - } - if (n.has("camera")) { - node->camera = n["camera"]; - } - if (n.has("mesh")) { - node->mesh = n["mesh"]; - } - if (n.has("skin")) { - node->skin = n["skin"]; - } - if (n.has("matrix")) { - node->xform = _arr_to_xform(n["matrix"]); - - } else { - if (n.has("translation")) { - node->translation = _arr_to_vec3(n["translation"]); - } - if (n.has("rotation")) { - node->rotation = _arr_to_quat(n["rotation"]); - } - if (n.has("scale")) { - node->scale = _arr_to_vec3(n["scale"]); - } - - node->xform.basis.set_quat_scale(node->rotation, node->scale); - node->xform.origin = node->translation; - } - if (n.has("extensions")) { - Dictionary extensions = n["extensions"]; - if (extensions.has("KHR_lights_punctual")) { - Dictionary lights_punctual = extensions["KHR_lights_punctual"]; - if (lights_punctual.has("light")) { - GLTFLightIndex light = lights_punctual["light"]; - node->light = light; - } - } - } - if (n.has("children")) { - const Array &children = n["children"]; - for (int j = 0; j < children.size(); j++) { - node->children.push_back(children[j]); - } - } - - state.nodes.push_back(node); - } - - // build the hierarchy - for (GLTFNodeIndex node_i = 0; node_i < state.nodes.size(); node_i++) { - for (int j = 0; j < state.nodes[node_i]->children.size(); j++) { - GLTFNodeIndex child_i = state.nodes[node_i]->children[j]; - - ERR_FAIL_INDEX_V(child_i, state.nodes.size(), ERR_FILE_CORRUPT); - ERR_CONTINUE(state.nodes[child_i]->parent != -1); //node already has a parent, wtf. - - state.nodes[child_i]->parent = node_i; - } - } - - _compute_node_heights(state); - - return OK; -} - -void EditorSceneImporterGLTF::_compute_node_heights(GLTFState &state) { - state.root_nodes.clear(); - for (GLTFNodeIndex node_i = 0; node_i < state.nodes.size(); ++node_i) { - GLTFNode *node = state.nodes[node_i]; - node->height = 0; - - GLTFNodeIndex current_i = node_i; - while (current_i >= 0) { - const GLTFNodeIndex parent_i = state.nodes[current_i]->parent; - if (parent_i >= 0) { - ++node->height; - } - current_i = parent_i; - } - - if (node->height == 0) { - state.root_nodes.push_back(node_i); - } - } -} - -static Vector<uint8_t> _parse_base64_uri(const String &uri) { - int start = uri.find(","); - ERR_FAIL_COND_V(start == -1, Vector<uint8_t>()); - - CharString substr = uri.right(start + 1).ascii(); - - int strlen = substr.length(); - - Vector<uint8_t> buf; - buf.resize(strlen / 4 * 3 + 1 + 1); - - size_t len = 0; - ERR_FAIL_COND_V(CryptoCore::b64_decode(buf.ptrw(), buf.size(), &len, (unsigned char *)substr.get_data(), strlen) != OK, Vector<uint8_t>()); - - buf.resize(len); - - return buf; -} - -Error EditorSceneImporterGLTF::_parse_buffers(GLTFState &state, const String &p_base_path) { - if (!state.json.has("buffers")) { - return OK; - } - - const Array &buffers = state.json["buffers"]; - for (GLTFBufferIndex i = 0; i < buffers.size(); i++) { - if (i == 0 && state.glb_data.size()) { - state.buffers.push_back(state.glb_data); - - } else { - const Dictionary &buffer = buffers[i]; - if (buffer.has("uri")) { - Vector<uint8_t> buffer_data; - String uri = buffer["uri"]; - - if (uri.begins_with("data:")) { // Embedded data using base64. - // Validate data MIME types and throw an error if it's one we don't know/support. - if (!uri.begins_with("data:application/octet-stream;base64") && - !uri.begins_with("data:application/gltf-buffer;base64")) { - ERR_PRINT("glTF: Got buffer with an unknown URI data type: " + uri); - } - buffer_data = _parse_base64_uri(uri); - } else { // Relative path to an external image file. - uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows. - buffer_data = FileAccess::get_file_as_array(uri); - ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri); - } - - ERR_FAIL_COND_V(!buffer.has("byteLength"), ERR_PARSE_ERROR); - int byteLength = buffer["byteLength"]; - ERR_FAIL_COND_V(byteLength < buffer_data.size(), ERR_PARSE_ERROR); - state.buffers.push_back(buffer_data); - } - } - } - - print_verbose("glTF: Total buffers: " + itos(state.buffers.size())); - - return OK; -} - -Error EditorSceneImporterGLTF::_parse_buffer_views(GLTFState &state) { - ERR_FAIL_COND_V(!state.json.has("bufferViews"), ERR_FILE_CORRUPT); - const Array &buffers = state.json["bufferViews"]; - for (GLTFBufferViewIndex i = 0; i < buffers.size(); i++) { - const Dictionary &d = buffers[i]; - - GLTFBufferView buffer_view; - - ERR_FAIL_COND_V(!d.has("buffer"), ERR_PARSE_ERROR); - buffer_view.buffer = d["buffer"]; - ERR_FAIL_COND_V(!d.has("byteLength"), ERR_PARSE_ERROR); - buffer_view.byte_length = d["byteLength"]; - - if (d.has("byteOffset")) { - buffer_view.byte_offset = d["byteOffset"]; - } - - if (d.has("byteStride")) { - buffer_view.byte_stride = d["byteStride"]; - } - - if (d.has("target")) { - const int target = d["target"]; - buffer_view.indices = target == ELEMENT_ARRAY_BUFFER; - } - - state.buffer_views.push_back(buffer_view); - } - - print_verbose("glTF: Total buffer views: " + itos(state.buffer_views.size())); - - return OK; -} - -EditorSceneImporterGLTF::GLTFType EditorSceneImporterGLTF::_get_type_from_str(const String &p_string) { - if (p_string == "SCALAR") { - return TYPE_SCALAR; - } - - if (p_string == "VEC2") { - return TYPE_VEC2; - } - if (p_string == "VEC3") { - return TYPE_VEC3; - } - if (p_string == "VEC4") { - return TYPE_VEC4; - } - - if (p_string == "MAT2") { - return TYPE_MAT2; - } - if (p_string == "MAT3") { - return TYPE_MAT3; - } - if (p_string == "MAT4") { - return TYPE_MAT4; - } - - ERR_FAIL_V(TYPE_SCALAR); -} - -Error EditorSceneImporterGLTF::_parse_accessors(GLTFState &state) { - ERR_FAIL_COND_V(!state.json.has("accessors"), ERR_FILE_CORRUPT); - const Array &accessors = state.json["accessors"]; - for (GLTFAccessorIndex i = 0; i < accessors.size(); i++) { - const Dictionary &d = accessors[i]; - - GLTFAccessor accessor; - - ERR_FAIL_COND_V(!d.has("componentType"), ERR_PARSE_ERROR); - accessor.component_type = d["componentType"]; - ERR_FAIL_COND_V(!d.has("count"), ERR_PARSE_ERROR); - accessor.count = d["count"]; - ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - accessor.type = _get_type_from_str(d["type"]); - - if (d.has("bufferView")) { - accessor.buffer_view = d["bufferView"]; //optional because it may be sparse... - } - - if (d.has("byteOffset")) { - accessor.byte_offset = d["byteOffset"]; - } - - if (d.has("max")) { - accessor.max = d["max"]; - } - - if (d.has("min")) { - accessor.min = d["min"]; - } - - if (d.has("sparse")) { - //eeh.. - - const Dictionary &s = d["sparse"]; - - ERR_FAIL_COND_V(!s.has("count"), ERR_PARSE_ERROR); - accessor.sparse_count = s["count"]; - ERR_FAIL_COND_V(!s.has("indices"), ERR_PARSE_ERROR); - const Dictionary &si = s["indices"]; - - ERR_FAIL_COND_V(!si.has("bufferView"), ERR_PARSE_ERROR); - accessor.sparse_indices_buffer_view = si["bufferView"]; - ERR_FAIL_COND_V(!si.has("componentType"), ERR_PARSE_ERROR); - accessor.sparse_indices_component_type = si["componentType"]; - - if (si.has("byteOffset")) { - accessor.sparse_indices_byte_offset = si["byteOffset"]; - } - - ERR_FAIL_COND_V(!s.has("values"), ERR_PARSE_ERROR); - const Dictionary &sv = s["values"]; - - ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR); - accessor.sparse_values_buffer_view = sv["bufferView"]; - if (sv.has("byteOffset")) { - accessor.sparse_values_byte_offset = sv["byteOffset"]; - } - } - - state.accessors.push_back(accessor); - } - - print_verbose("glTF: Total accessors: " + itos(state.accessors.size())); - - return OK; -} - -String EditorSceneImporterGLTF::_get_component_type_name(const uint32_t p_component) { - switch (p_component) { - case COMPONENT_TYPE_BYTE: - return "Byte"; - case COMPONENT_TYPE_UNSIGNED_BYTE: - return "UByte"; - case COMPONENT_TYPE_SHORT: - return "Short"; - case COMPONENT_TYPE_UNSIGNED_SHORT: - return "UShort"; - case COMPONENT_TYPE_INT: - return "Int"; - case COMPONENT_TYPE_FLOAT: - return "Float"; - } - - return "<Error>"; -} - -String EditorSceneImporterGLTF::_get_type_name(const GLTFType p_component) { - static const char *names[] = { - "float", - "vec2", - "vec3", - "vec4", - "mat2", - "mat3", - "mat4" - }; - - return names[p_component]; -} - -Error EditorSceneImporterGLTF::_decode_buffer_view(GLTFState &state, double *dst, const GLTFBufferViewIndex p_buffer_view, const int skip_every, const int skip_bytes, const int element_size, const int count, const GLTFType type, const int component_count, const int component_type, const int component_size, const bool normalized, const int byte_offset, const bool for_vertex) { - const GLTFBufferView &bv = state.buffer_views[p_buffer_view]; - - int stride = bv.byte_stride ? bv.byte_stride : element_size; - if (for_vertex && stride % 4) { - stride += 4 - (stride % 4); //according to spec must be multiple of 4 - } - - ERR_FAIL_INDEX_V(bv.buffer, state.buffers.size(), ERR_PARSE_ERROR); - - const uint32_t offset = bv.byte_offset + byte_offset; - Vector<uint8_t> buffer = state.buffers[bv.buffer]; //copy on write, so no performance hit - const uint8_t *bufptr = buffer.ptr(); - - //use to debug - print_verbose("glTF: type " + _get_type_name(type) + " component type: " + _get_component_type_name(component_type) + " stride: " + itos(stride) + " amount " + itos(count)); - print_verbose("glTF: accessor offset" + itos(byte_offset) + " view offset: " + itos(bv.byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv.byte_length)); - - const int buffer_end = (stride * (count - 1)) + element_size; - ERR_FAIL_COND_V(buffer_end > bv.byte_length, ERR_PARSE_ERROR); - - ERR_FAIL_COND_V((int)(offset + buffer_end) > buffer.size(), ERR_PARSE_ERROR); - - //fill everything as doubles - - for (int i = 0; i < count; i++) { - const uint8_t *src = &bufptr[offset + i * stride]; - - for (int j = 0; j < component_count; j++) { - if (skip_every && j > 0 && (j % skip_every) == 0) { - src += skip_bytes; - } - - double d = 0; - - switch (component_type) { - case COMPONENT_TYPE_BYTE: { - int8_t b = int8_t(*src); - if (normalized) { - d = (double(b) / 128.0); - } else { - d = double(b); - } - } break; - case COMPONENT_TYPE_UNSIGNED_BYTE: { - uint8_t b = *src; - if (normalized) { - d = (double(b) / 255.0); - } else { - d = double(b); - } - } break; - case COMPONENT_TYPE_SHORT: { - int16_t s = *(int16_t *)src; - if (normalized) { - d = (double(s) / 32768.0); - } else { - d = double(s); - } - } break; - case COMPONENT_TYPE_UNSIGNED_SHORT: { - uint16_t s = *(uint16_t *)src; - if (normalized) { - d = (double(s) / 65535.0); - } else { - d = double(s); - } - - } break; - case COMPONENT_TYPE_INT: { - d = *(int *)src; - } break; - case COMPONENT_TYPE_FLOAT: { - d = *(float *)src; - } break; - } - - *dst++ = d; - src += component_size; - } - } - - return OK; -} - -int EditorSceneImporterGLTF::_get_component_type_size(const int component_type) { - switch (component_type) { - case COMPONENT_TYPE_BYTE: - return 1; - break; - case COMPONENT_TYPE_UNSIGNED_BYTE: - return 1; - break; - case COMPONENT_TYPE_SHORT: - return 2; - break; - case COMPONENT_TYPE_UNSIGNED_SHORT: - return 2; - break; - case COMPONENT_TYPE_INT: - return 4; - break; - case COMPONENT_TYPE_FLOAT: - return 4; - break; - default: { - ERR_FAIL_V(0); - } - } - return 0; -} - -Vector<double> EditorSceneImporterGLTF::_decode_accessor(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - //spec, for reference: - //https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment - - ERR_FAIL_INDEX_V(p_accessor, state.accessors.size(), Vector<double>()); - - const GLTFAccessor &a = state.accessors[p_accessor]; - - const int component_count_for_type[7] = { - 1, 2, 3, 4, 4, 9, 16 - }; - - const int component_count = component_count_for_type[a.type]; - const int component_size = _get_component_type_size(a.component_type); - ERR_FAIL_COND_V(component_size == 0, Vector<double>()); - int element_size = component_count * component_size; - - int skip_every = 0; - int skip_bytes = 0; - //special case of alignments, as described in spec - switch (a.component_type) { - case COMPONENT_TYPE_BYTE: - case COMPONENT_TYPE_UNSIGNED_BYTE: { - if (a.type == TYPE_MAT2) { - skip_every = 2; - skip_bytes = 2; - element_size = 8; //override for this case - } - if (a.type == TYPE_MAT3) { - skip_every = 3; - skip_bytes = 1; - element_size = 12; //override for this case - } - - } break; - case COMPONENT_TYPE_SHORT: - case COMPONENT_TYPE_UNSIGNED_SHORT: { - if (a.type == TYPE_MAT3) { - skip_every = 6; - skip_bytes = 4; - element_size = 16; //override for this case - } - } break; - default: { - } - } - - Vector<double> dst_buffer; - dst_buffer.resize(component_count * a.count); - double *dst = dst_buffer.ptrw(); - - if (a.buffer_view >= 0) { - ERR_FAIL_INDEX_V(a.buffer_view, state.buffer_views.size(), Vector<double>()); - - const Error err = _decode_buffer_view(state, dst, a.buffer_view, skip_every, skip_bytes, element_size, a.count, a.type, component_count, a.component_type, component_size, a.normalized, a.byte_offset, p_for_vertex); - if (err != OK) { - return Vector<double>(); - } - - } else { - //fill with zeros, as bufferview is not defined. - for (int i = 0; i < (a.count * component_count); i++) { - dst_buffer.write[i] = 0; - } - } - - if (a.sparse_count > 0) { - // I could not find any file using this, so this code is so far untested - Vector<double> indices; - indices.resize(a.sparse_count); - const int indices_component_size = _get_component_type_size(a.sparse_indices_component_type); - - Error err = _decode_buffer_view(state, indices.ptrw(), a.sparse_indices_buffer_view, 0, 0, indices_component_size, a.sparse_count, TYPE_SCALAR, 1, a.sparse_indices_component_type, indices_component_size, false, a.sparse_indices_byte_offset, false); - if (err != OK) { - return Vector<double>(); - } - - Vector<double> data; - data.resize(component_count * a.sparse_count); - err = _decode_buffer_view(state, data.ptrw(), a.sparse_values_buffer_view, skip_every, skip_bytes, element_size, a.sparse_count, a.type, component_count, a.component_type, component_size, a.normalized, a.sparse_values_byte_offset, p_for_vertex); - if (err != OK) { - return Vector<double>(); - } - - for (int i = 0; i < indices.size(); i++) { - const int write_offset = int(indices[i]) * component_count; - - for (int j = 0; j < component_count; j++) { - dst[write_offset + j] = data[i * component_count + j]; - } - } - } - - return dst_buffer; -} - -Vector<int> EditorSceneImporterGLTF::_decode_accessor_as_ints(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<int> ret; - - if (attribs.size() == 0) { - return ret; - } - - const double *attribs_ptr = attribs.ptr(); - const int ret_size = attribs.size(); - ret.resize(ret_size); - { - int *w = ret.ptrw(); - for (int i = 0; i < ret_size; i++) { - w[i] = int(attribs_ptr[i]); - } - } - return ret; -} - -Vector<float> EditorSceneImporterGLTF::_decode_accessor_as_floats(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<float> ret; - - if (attribs.size() == 0) { - return ret; - } - - const double *attribs_ptr = attribs.ptr(); - const int ret_size = attribs.size(); - ret.resize(ret_size); - { - float *w = ret.ptrw(); - for (int i = 0; i < ret_size; i++) { - w[i] = float(attribs_ptr[i]); - } - } - return ret; -} - -Vector<Vector2> EditorSceneImporterGLTF::_decode_accessor_as_vec2(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Vector2> ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret); - const double *attribs_ptr = attribs.ptr(); - const int ret_size = attribs.size() / 2; - ret.resize(ret_size); - { - Vector2 *w = ret.ptrw(); - for (int i = 0; i < ret_size; i++) { - w[i] = Vector2(attribs_ptr[i * 2 + 0], attribs_ptr[i * 2 + 1]); - } - } - return ret; -} - -Vector<Vector3> EditorSceneImporterGLTF::_decode_accessor_as_vec3(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Vector3> ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret); - const double *attribs_ptr = attribs.ptr(); - const int ret_size = attribs.size() / 3; - ret.resize(ret_size); - { - Vector3 *w = ret.ptrw(); - for (int i = 0; i < ret_size; i++) { - w[i] = Vector3(attribs_ptr[i * 3 + 0], attribs_ptr[i * 3 + 1], attribs_ptr[i * 3 + 2]); - } - } - return ret; -} - -Vector<Color> EditorSceneImporterGLTF::_decode_accessor_as_color(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Color> ret; - - if (attribs.size() == 0) { - return ret; - } - - const int type = state.accessors[p_accessor].type; - ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret); - int vec_len = 3; - if (type == TYPE_VEC4) { - vec_len = 4; - } - - ERR_FAIL_COND_V(attribs.size() % vec_len != 0, ret); - const double *attribs_ptr = attribs.ptr(); - const int ret_size = attribs.size() / vec_len; - ret.resize(ret_size); - { - Color *w = ret.ptrw(); - for (int i = 0; i < ret_size; i++) { - w[i] = Color(attribs_ptr[i * vec_len + 0], attribs_ptr[i * vec_len + 1], attribs_ptr[i * vec_len + 2], vec_len == 4 ? attribs_ptr[i * 4 + 3] : 1.0); - } - } - return ret; -} - -Vector<Quat> EditorSceneImporterGLTF::_decode_accessor_as_quat(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Quat> ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); - const double *attribs_ptr = attribs.ptr(); - const int ret_size = attribs.size() / 4; - ret.resize(ret_size); - { - for (int i = 0; i < ret_size; i++) { - ret.write[i] = Quat(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized(); - } - } - return ret; -} - -Vector<Transform2D> EditorSceneImporterGLTF::_decode_accessor_as_xform2d(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Transform2D> ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); - ret.resize(attribs.size() / 4); - for (int i = 0; i < ret.size(); i++) { - ret.write[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]); - ret.write[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]); - } - return ret; -} - -Vector<Basis> EditorSceneImporterGLTF::_decode_accessor_as_basis(GLTFState &state, const GLTFAccessorIndex p_accessor, bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Basis> ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret); - ret.resize(attribs.size() / 9); - for (int i = 0; i < ret.size(); i++) { - ret.write[i].set_axis(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2])); - ret.write[i].set_axis(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5])); - ret.write[i].set_axis(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8])); - } - return ret; -} - -Vector<Transform> EditorSceneImporterGLTF::_decode_accessor_as_xform(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { - const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Transform> ret; - - if (attribs.size() == 0) { - return ret; - } - - ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret); - ret.resize(attribs.size() / 16); - for (int i = 0; i < ret.size(); i++) { - ret.write[i].basis.set_axis(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2])); - ret.write[i].basis.set_axis(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6])); - ret.write[i].basis.set_axis(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10])); - ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14])); - } - return ret; -} - -Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { - if (!state.json.has("meshes")) { - return OK; - } - - Array meshes = state.json["meshes"]; - for (GLTFMeshIndex i = 0; i < meshes.size(); i++) { - print_verbose("glTF: Parsing mesh: " + itos(i)); - Dictionary d = meshes[i]; - - GLTFMesh mesh; - mesh.mesh.instance(); - bool has_vertex_color = false; - - ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR); - - Array primitives = d["primitives"]; - const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary(); - - for (int j = 0; j < primitives.size(); j++) { - Dictionary p = primitives[j]; - - Array array; - array.resize(Mesh::ARRAY_MAX); - - ERR_FAIL_COND_V(!p.has("attributes"), ERR_PARSE_ERROR); - - Dictionary a = p["attributes"]; - - Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES; - if (p.has("mode")) { - const int mode = p["mode"]; - ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT); - static const Mesh::PrimitiveType primitives2[7] = { - Mesh::PRIMITIVE_POINTS, - Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_LINES, //loop not supported, should ce converted - Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_TRIANGLES, - Mesh::PRIMITIVE_TRIANGLE_STRIP, - Mesh::PRIMITIVE_TRIANGLES, //fan not supported, should be converted -#ifndef _MSC_VER -#warning line loop and triangle fan are not supported and need to be converted to lines and triangles -#endif - - }; - - primitive = primitives2[mode]; - } - - ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR); - if (a.has("POSITION")) { - array[Mesh::ARRAY_VERTEX] = _decode_accessor_as_vec3(state, a["POSITION"], true); - } - if (a.has("NORMAL")) { - array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(state, a["NORMAL"], true); - } - if (a.has("TANGENT")) { - array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(state, a["TANGENT"], true); - } - if (a.has("TEXCOORD_0")) { - array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(state, a["TEXCOORD_0"], true); - } - if (a.has("TEXCOORD_1")) { - array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(state, a["TEXCOORD_1"], true); - } - if (a.has("COLOR_0")) { - array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true); - has_vertex_color = true; - } - if (a.has("JOINTS_0")) { - array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true); - } - if (a.has("WEIGHTS_0")) { - Vector<float> weights = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true); - { //gltf does not seem to normalize the weights for some reason.. - int wc = weights.size(); - float *w = weights.ptrw(); - - for (int k = 0; k < wc; k += 4) { - float total = 0.0; - total += w[k + 0]; - total += w[k + 1]; - total += w[k + 2]; - total += w[k + 3]; - if (total > 0.0) { - w[k + 0] /= total; - w[k + 1] /= total; - w[k + 2] /= total; - w[k + 3] /= total; - } - } - } - array[Mesh::ARRAY_WEIGHTS] = weights; - } - - if (p.has("indices")) { - Vector<int> indices = _decode_accessor_as_ints(state, p["indices"], false); - - if (primitive == Mesh::PRIMITIVE_TRIANGLES) { - //swap around indices, convert ccw to cw for front face - - const int is = indices.size(); - int *w = indices.ptrw(); - for (int k = 0; k < is; k += 3) { - SWAP(w[k + 1], w[k + 2]); - } - } - array[Mesh::ARRAY_INDEX] = indices; - - } else if (primitive == Mesh::PRIMITIVE_TRIANGLES) { - //generate indices because they need to be swapped for CW/CCW - const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX]; - ERR_FAIL_COND_V(vertices.size() == 0, ERR_PARSE_ERROR); - Vector<int> indices; - const int vs = vertices.size(); - indices.resize(vs); - { - int *w = indices.ptrw(); - for (int k = 0; k < vs; k += 3) { - w[k] = k; - w[k + 1] = k + 2; - w[k + 2] = k + 1; - } - } - array[Mesh::ARRAY_INDEX] = indices; - } - - bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL")); - - if (generate_tangents) { - //must generate mikktspace tangents.. ergh.. - Ref<SurfaceTool> st; - st.instance(); - st->create_from_triangle_arrays(array); - st->generate_tangents(); - array = st->commit_to_arrays(); - } - - Array morphs; - //blend shapes - if (p.has("targets")) { - print_verbose("glTF: Mesh has targets"); - const Array &targets = p["targets"]; - - //ideally BLEND_SHAPE_MODE_RELATIVE since gltf2 stores in displacement - //but it could require a larger refactor? - mesh.mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); - - if (j == 0) { - const Array &target_names = extras.has("targetNames") ? (Array)extras["targetNames"] : Array(); - for (int k = 0; k < targets.size(); k++) { - const String name = k < target_names.size() ? (String)target_names[k] : String("morph_") + itos(k); - mesh.mesh->add_blend_shape(name); - } - } - - for (int k = 0; k < targets.size(); k++) { - const Dictionary &t = targets[k]; - - Array array_copy; - array_copy.resize(Mesh::ARRAY_MAX); - - for (int l = 0; l < Mesh::ARRAY_MAX; l++) { - array_copy[l] = array[l]; - } - - array_copy[Mesh::ARRAY_INDEX] = Variant(); - - if (t.has("POSITION")) { - Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true); - const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX]; - const int size = src_varr.size(); - ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); - { - const int max_idx = varr.size(); - varr.resize(size); - - Vector3 *w_varr = varr.ptrw(); - const Vector3 *r_varr = varr.ptr(); - const Vector3 *r_src_varr = src_varr.ptr(); - for (int l = 0; l < size; l++) { - if (l < max_idx) { - w_varr[l] = r_varr[l] + r_src_varr[l]; - } else { - w_varr[l] = r_src_varr[l]; - } - } - } - array_copy[Mesh::ARRAY_VERTEX] = varr; - } - if (t.has("NORMAL")) { - Vector<Vector3> narr = _decode_accessor_as_vec3(state, t["NORMAL"], true); - const Vector<Vector3> src_narr = array[Mesh::ARRAY_NORMAL]; - int size = src_narr.size(); - ERR_FAIL_COND_V(size == 0, ERR_PARSE_ERROR); - { - int max_idx = narr.size(); - narr.resize(size); - - Vector3 *w_narr = narr.ptrw(); - const Vector3 *r_narr = narr.ptr(); - const Vector3 *r_src_narr = src_narr.ptr(); - for (int l = 0; l < size; l++) { - if (l < max_idx) { - w_narr[l] = r_narr[l] + r_src_narr[l]; - } else { - w_narr[l] = r_src_narr[l]; - } - } - } - array_copy[Mesh::ARRAY_NORMAL] = narr; - } - if (t.has("TANGENT")) { - const Vector<Vector3> tangents_v3 = _decode_accessor_as_vec3(state, t["TANGENT"], true); - const Vector<float> src_tangents = array[Mesh::ARRAY_TANGENT]; - ERR_FAIL_COND_V(src_tangents.size() == 0, ERR_PARSE_ERROR); - - Vector<float> tangents_v4; - - { - int max_idx = tangents_v3.size(); - - int size4 = src_tangents.size(); - tangents_v4.resize(size4); - float *w4 = tangents_v4.ptrw(); - - const Vector3 *r3 = tangents_v3.ptr(); - const float *r4 = src_tangents.ptr(); - - for (int l = 0; l < size4 / 4; l++) { - if (l < max_idx) { - w4[l * 4 + 0] = r3[l].x + r4[l * 4 + 0]; - w4[l * 4 + 1] = r3[l].y + r4[l * 4 + 1]; - w4[l * 4 + 2] = r3[l].z + r4[l * 4 + 2]; - } else { - w4[l * 4 + 0] = r4[l * 4 + 0]; - w4[l * 4 + 1] = r4[l * 4 + 1]; - w4[l * 4 + 2] = r4[l * 4 + 2]; - } - w4[l * 4 + 3] = r4[l * 4 + 3]; //copy flip value - } - } - - array_copy[Mesh::ARRAY_TANGENT] = tangents_v4; - } - - if (generate_tangents) { - Ref<SurfaceTool> st; - st.instance(); - st->create_from_triangle_arrays(array_copy); - st->deindex(); - st->generate_tangents(); - array_copy = st->commit_to_arrays(); - } - - morphs.push_back(array_copy); - } - } - - //just add it - - Ref<Material> mat; - if (p.has("material")) { - const int material = p["material"]; - ERR_FAIL_INDEX_V(material, state.materials.size(), ERR_FILE_CORRUPT); - Ref<StandardMaterial3D> mat3d = state.materials[material]; - if (has_vertex_color) { - mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - } - mat = mat3d; - - } else if (has_vertex_color) { - Ref<StandardMaterial3D> mat3d; - mat3d.instance(); - mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat = mat3d; - } - - mesh.mesh->add_surface(primitive, array, morphs, Dictionary(), mat); - } - - mesh.blend_weights.resize(mesh.mesh->get_blend_shape_count()); - for (int32_t weight_i = 0; weight_i < mesh.blend_weights.size(); weight_i++) { - mesh.blend_weights.write[weight_i] = 0.0f; - } - - if (d.has("weights")) { - const Array &weights = d["weights"]; - ERR_FAIL_COND_V(mesh.blend_weights.size() != weights.size(), ERR_PARSE_ERROR); - for (int j = 0; j < weights.size(); j++) { - mesh.blend_weights.write[j] = weights[j]; - } - } - - state.meshes.push_back(mesh); - } - - print_verbose("glTF: Total meshes: " + itos(state.meshes.size())); - - return OK; -} - -Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_base_path) { - if (!state.json.has("images")) { - return OK; - } - - // Ref: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#images - - const Array &images = state.json["images"]; - for (int i = 0; i < images.size(); i++) { - const Dictionary &d = images[i]; - - // glTF 2.0 supports PNG and JPEG types, which can be specified as (from spec): - // "- a URI to an external file in one of the supported images formats, or - // - a URI with embedded base64-encoded data, or - // - a reference to a bufferView; in that case mimeType must be defined." - // Since mimeType is optional for external files and base64 data, we'll have to - // fall back on letting Godot parse the data to figure out if it's PNG or JPEG. - - // We'll assume that we use either URI or bufferView, so let's warn the user - // if their image somehow uses both. And fail if it has neither. - ERR_CONTINUE_MSG(!d.has("uri") && !d.has("bufferView"), "Invalid image definition in glTF file, it should specific an 'uri' or 'bufferView'."); - if (d.has("uri") && d.has("bufferView")) { - WARN_PRINT("Invalid image definition in glTF file using both 'uri' and 'bufferView'. 'bufferView' will take precedence."); - } - - String mimetype; - if (d.has("mimeType")) { // Should be "image/png" or "image/jpeg". - mimetype = d["mimeType"]; - } - - Vector<uint8_t> data; - const uint8_t *data_ptr = nullptr; - int data_size = 0; - - if (d.has("uri")) { - // Handles the first two bullet points from the spec (embedded data, or external file). - String uri = d["uri"]; - - if (uri.begins_with("data:")) { // Embedded data using base64. - // Validate data MIME types and throw a warning if it's one we don't know/support. - if (!uri.begins_with("data:application/octet-stream;base64") && - !uri.begins_with("data:application/gltf-buffer;base64") && - !uri.begins_with("data:image/png;base64") && - !uri.begins_with("data:image/jpeg;base64")) { - WARN_PRINT(vformat("glTF: Image index '%d' uses an unsupported URI data type: %s. Skipping it.", i, uri)); - state.images.push_back(Ref<Texture2D>()); // Placeholder to keep count. - continue; - } - data = _parse_base64_uri(uri); - data_ptr = data.ptr(); - data_size = data.size(); - // mimeType is optional, but if we have it defined in the URI, let's use it. - if (mimetype.empty()) { - if (uri.begins_with("data:image/png;base64")) { - mimetype = "image/png"; - } else if (uri.begins_with("data:image/jpeg;base64")) { - mimetype = "image/jpeg"; - } - } - } else { // Relative path to an external image file. - uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows. - // The spec says that if mimeType is defined, we should enforce it. - // So we should only rely on ResourceLoader::load if mimeType is not defined, - // otherwise we should use the same logic as for buffers. - if (mimetype == "image/png" || mimetype == "image/jpeg") { - // Load data buffer and rely on PNG and JPEG-specific logic below to load the image. - // This makes it possible to load a file with a wrong extension but correct MIME type, - // e.g. "foo.jpg" containing PNG data and with MIME type "image/png". ResourceLoader would fail. - data = FileAccess::get_file_as_array(uri); - ERR_FAIL_COND_V_MSG(data.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load image file as an array: " + uri); - data_ptr = data.ptr(); - data_size = data.size(); - } else { - // Good old ResourceLoader will rely on file extension. - Ref<Texture2D> texture = ResourceLoader::load(uri); - state.images.push_back(texture); - continue; - } - } - } else if (d.has("bufferView")) { - // Handles the third bullet point from the spec (bufferView). - ERR_FAIL_COND_V_MSG(mimetype.empty(), ERR_FILE_CORRUPT, - vformat("glTF: Image index '%d' specifies 'bufferView' but no 'mimeType', which is invalid.", i)); - - const GLTFBufferViewIndex bvi = d["bufferView"]; - - ERR_FAIL_INDEX_V(bvi, state.buffer_views.size(), ERR_PARAMETER_RANGE_ERROR); - - const GLTFBufferView &bv = state.buffer_views[bvi]; - - const GLTFBufferIndex bi = bv.buffer; - ERR_FAIL_INDEX_V(bi, state.buffers.size(), ERR_PARAMETER_RANGE_ERROR); - - ERR_FAIL_COND_V(bv.byte_offset + bv.byte_length > state.buffers[bi].size(), ERR_FILE_CORRUPT); - - data_ptr = &state.buffers[bi][bv.byte_offset]; - data_size = bv.byte_length; - } - - Ref<Image> img; - - if (mimetype == "image/png") { // Load buffer as PNG. - ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, ERR_UNAVAILABLE); - img = Image::_png_mem_loader_func(data_ptr, data_size); - } else if (mimetype == "image/jpeg") { // Loader buffer as JPEG. - ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE); - img = Image::_jpg_mem_loader_func(data_ptr, data_size); - } else { - // We can land here if we got an URI with base64-encoded data with application/* MIME type, - // and the optional mimeType property was not defined to tell us how to handle this data (or was invalid). - // So let's try PNG first, then JPEG. - ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, ERR_UNAVAILABLE); - img = Image::_png_mem_loader_func(data_ptr, data_size); - if (img.is_null()) { - ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE); - img = Image::_jpg_mem_loader_func(data_ptr, data_size); - } - } - - ERR_FAIL_COND_V_MSG(img.is_null(), ERR_FILE_CORRUPT, - vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype)); - - Ref<ImageTexture> t; - t.instance(); - t->create_from_image(img); - - state.images.push_back(t); - } - - print_verbose("glTF: Total images: " + itos(state.images.size())); - - return OK; -} - -Error EditorSceneImporterGLTF::_parse_textures(GLTFState &state) { - if (!state.json.has("textures")) { - return OK; - } - - const Array &textures = state.json["textures"]; - for (GLTFTextureIndex i = 0; i < textures.size(); i++) { - const Dictionary &d = textures[i]; - - ERR_FAIL_COND_V(!d.has("source"), ERR_PARSE_ERROR); - - GLTFTexture t; - t.src_image = d["source"]; - state.textures.push_back(t); - } - - return OK; -} - -Ref<Texture2D> EditorSceneImporterGLTF::_get_texture(GLTFState &state, const GLTFTextureIndex p_texture) { - ERR_FAIL_INDEX_V(p_texture, state.textures.size(), Ref<Texture2D>()); - const GLTFImageIndex image = state.textures[p_texture].src_image; - - ERR_FAIL_INDEX_V(image, state.images.size(), Ref<Texture2D>()); - - return state.images[image]; -} - -Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) { - if (!state.json.has("materials")) { - return OK; - } - - const Array &materials = state.json["materials"]; - for (GLTFMaterialIndex i = 0; i < materials.size(); i++) { - const Dictionary &d = materials[i]; - - Ref<StandardMaterial3D> material; - material.instance(); - if (d.has("name")) { - material->set_name(d["name"]); - } - //don't do this here only if vertex color exists - //material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - - if (d.has("pbrMetallicRoughness")) { - const Dictionary &mr = d["pbrMetallicRoughness"]; - if (mr.has("baseColorFactor")) { - const Array &arr = mr["baseColorFactor"]; - ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb(); - - material->set_albedo(c); - } - - if (mr.has("baseColorTexture")) { - const Dictionary &bct = mr["baseColorTexture"]; - if (bct.has("index")) { - material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, _get_texture(state, bct["index"])); - } - if (!mr.has("baseColorFactor")) { - material->set_albedo(Color(1, 1, 1)); - } - } - - if (mr.has("metallicFactor")) { - material->set_metallic(mr["metallicFactor"]); - } else { - material->set_metallic(1.0); - } - - if (mr.has("roughnessFactor")) { - material->set_roughness(mr["roughnessFactor"]); - } else { - material->set_roughness(1.0); - } - - if (mr.has("metallicRoughnessTexture")) { - const Dictionary &bct = mr["metallicRoughnessTexture"]; - if (bct.has("index")) { - const Ref<Texture2D> t = _get_texture(state, bct["index"]); - material->set_texture(StandardMaterial3D::TEXTURE_METALLIC, t); - material->set_metallic_texture_channel(StandardMaterial3D::TEXTURE_CHANNEL_BLUE); - material->set_texture(StandardMaterial3D::TEXTURE_ROUGHNESS, t); - material->set_roughness_texture_channel(StandardMaterial3D::TEXTURE_CHANNEL_GREEN); - if (!mr.has("metallicFactor")) { - material->set_metallic(1); - } - if (!mr.has("roughnessFactor")) { - material->set_roughness(1); - } - } - } - } - - if (d.has("normalTexture")) { - const Dictionary &bct = d["normalTexture"]; - if (bct.has("index")) { - material->set_texture(StandardMaterial3D::TEXTURE_NORMAL, _get_texture(state, bct["index"])); - material->set_feature(StandardMaterial3D::FEATURE_NORMAL_MAPPING, true); - } - if (bct.has("scale")) { - material->set_normal_scale(bct["scale"]); - } - } - if (d.has("occlusionTexture")) { - const Dictionary &bct = d["occlusionTexture"]; - if (bct.has("index")) { - material->set_texture(StandardMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"])); - material->set_ao_texture_channel(StandardMaterial3D::TEXTURE_CHANNEL_RED); - material->set_feature(StandardMaterial3D::FEATURE_AMBIENT_OCCLUSION, true); - } - } - - if (d.has("emissiveFactor")) { - const Array &arr = d["emissiveFactor"]; - ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2]).to_srgb(); - material->set_feature(StandardMaterial3D::FEATURE_EMISSION, true); - - material->set_emission(c); - } - - if (d.has("emissiveTexture")) { - const Dictionary &bct = d["emissiveTexture"]; - if (bct.has("index")) { - material->set_texture(StandardMaterial3D::TEXTURE_EMISSION, _get_texture(state, bct["index"])); - material->set_feature(StandardMaterial3D::FEATURE_EMISSION, true); - material->set_emission(Color(0, 0, 0)); - } - } - - if (d.has("doubleSided")) { - const bool ds = d["doubleSided"]; - if (ds) { - material->set_cull_mode(StandardMaterial3D::CULL_DISABLED); - } - } - - if (d.has("alphaMode")) { - const String &am = d["alphaMode"]; - if (am == "BLEND") { - material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); - } else if (am == "MASK") { - material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_SCISSOR); - if (d.has("alphaCutoff")) { - material->set_alpha_scissor_threshold(d["alphaCutoff"]); - } else { - material->set_alpha_scissor_threshold(0.5f); - } - } - } - - state.materials.push_back(material); - } - - print_verbose("glTF: Total materials: " + itos(state.materials.size())); - - return OK; -} - -EditorSceneImporterGLTF::GLTFNodeIndex EditorSceneImporterGLTF::_find_highest_node(GLTFState &state, const Vector<GLTFNodeIndex> &subset) { - int highest = -1; - GLTFNodeIndex best_node = -1; - - for (int i = 0; i < subset.size(); ++i) { - const GLTFNodeIndex node_i = subset[i]; - const GLTFNode *node = state.nodes[node_i]; - - if (highest == -1 || node->height < highest) { - highest = node->height; - best_node = node_i; - } - } - - return best_node; -} - -bool EditorSceneImporterGLTF::_capture_nodes_in_skin(GLTFState &state, GLTFSkin &skin, const GLTFNodeIndex node_index) { - bool found_joint = false; - - for (int i = 0; i < state.nodes[node_index]->children.size(); ++i) { - found_joint |= _capture_nodes_in_skin(state, skin, state.nodes[node_index]->children[i]); - } - - if (found_joint) { - // Mark it if we happen to find another skins joint... - if (state.nodes[node_index]->joint && skin.joints.find(node_index) < 0) { - skin.joints.push_back(node_index); - } else if (skin.non_joints.find(node_index) < 0) { - skin.non_joints.push_back(node_index); - } - } - - if (skin.joints.find(node_index) > 0) { - return true; - } - - return false; -} - -void EditorSceneImporterGLTF::_capture_nodes_for_multirooted_skin(GLTFState &state, GLTFSkin &skin) { - DisjointSet<GLTFNodeIndex> disjoint_set; - - for (int i = 0; i < skin.joints.size(); ++i) { - const GLTFNodeIndex node_index = skin.joints[i]; - const GLTFNodeIndex parent = state.nodes[node_index]->parent; - disjoint_set.insert(node_index); - - if (skin.joints.find(parent) >= 0) { - disjoint_set.create_union(parent, node_index); - } - } - - Vector<GLTFNodeIndex> roots; - disjoint_set.get_representatives(roots); - - if (roots.size() <= 1) { - return; - } - - int maxHeight = -1; - - // Determine the max height rooted tree - for (int i = 0; i < roots.size(); ++i) { - const GLTFNodeIndex root = roots[i]; - - if (maxHeight == -1 || state.nodes[root]->height < maxHeight) { - maxHeight = state.nodes[root]->height; - } - } - - // Go up the tree till all of the multiple roots of the skin are at the same hierarchy level. - // This sucks, but 99% of all game engines (not just Godot) would have this same issue. - for (int i = 0; i < roots.size(); ++i) { - GLTFNodeIndex current_node = roots[i]; - while (state.nodes[current_node]->height > maxHeight) { - GLTFNodeIndex parent = state.nodes[current_node]->parent; - - if (state.nodes[parent]->joint && skin.joints.find(parent) < 0) { - skin.joints.push_back(parent); - } else if (skin.non_joints.find(parent) < 0) { - skin.non_joints.push_back(parent); - } - - current_node = parent; - } - - // replace the roots - roots.write[i] = current_node; - } - - // Climb up the tree until they all have the same parent - bool all_same; - - do { - all_same = true; - const GLTFNodeIndex first_parent = state.nodes[roots[0]]->parent; - - for (int i = 1; i < roots.size(); ++i) { - all_same &= (first_parent == state.nodes[roots[i]]->parent); - } - - if (!all_same) { - for (int i = 0; i < roots.size(); ++i) { - const GLTFNodeIndex current_node = roots[i]; - const GLTFNodeIndex parent = state.nodes[current_node]->parent; - - if (state.nodes[parent]->joint && skin.joints.find(parent) < 0) { - skin.joints.push_back(parent); - } else if (skin.non_joints.find(parent) < 0) { - skin.non_joints.push_back(parent); - } - - roots.write[i] = parent; - } - } - - } while (!all_same); -} - -Error EditorSceneImporterGLTF::_expand_skin(GLTFState &state, GLTFSkin &skin) { - _capture_nodes_for_multirooted_skin(state, skin); - - // Grab all nodes that lay in between skin joints/nodes - DisjointSet<GLTFNodeIndex> disjoint_set; - - Vector<GLTFNodeIndex> all_skin_nodes; - all_skin_nodes.append_array(skin.joints); - all_skin_nodes.append_array(skin.non_joints); - - for (int i = 0; i < all_skin_nodes.size(); ++i) { - const GLTFNodeIndex node_index = all_skin_nodes[i]; - const GLTFNodeIndex parent = state.nodes[node_index]->parent; - disjoint_set.insert(node_index); - - if (all_skin_nodes.find(parent) >= 0) { - disjoint_set.create_union(parent, node_index); - } - } - - Vector<GLTFNodeIndex> out_owners; - disjoint_set.get_representatives(out_owners); - - Vector<GLTFNodeIndex> out_roots; - - for (int i = 0; i < out_owners.size(); ++i) { - Vector<GLTFNodeIndex> set; - disjoint_set.get_members(set, out_owners[i]); - - const GLTFNodeIndex root = _find_highest_node(state, set); - ERR_FAIL_COND_V(root < 0, FAILED); - out_roots.push_back(root); - } - - out_roots.sort(); - - for (int i = 0; i < out_roots.size(); ++i) { - _capture_nodes_in_skin(state, skin, out_roots[i]); - } - - skin.roots = out_roots; - - return OK; -} - -Error EditorSceneImporterGLTF::_verify_skin(GLTFState &state, GLTFSkin &skin) { - // This may seem duplicated from expand_skins, but this is really a sanity check! (so it kinda is) - // In case additional interpolating logic is added to the skins, this will help ensure that you - // do not cause it to self implode into a fiery blaze - - // We are going to re-calculate the root nodes and compare them to the ones saved in the skin, - // then ensure the multiple trees (if they exist) are on the same sublevel - - // Grab all nodes that lay in between skin joints/nodes - DisjointSet<GLTFNodeIndex> disjoint_set; - - Vector<GLTFNodeIndex> all_skin_nodes; - all_skin_nodes.append_array(skin.joints); - all_skin_nodes.append_array(skin.non_joints); - - for (int i = 0; i < all_skin_nodes.size(); ++i) { - const GLTFNodeIndex node_index = all_skin_nodes[i]; - const GLTFNodeIndex parent = state.nodes[node_index]->parent; - disjoint_set.insert(node_index); - - if (all_skin_nodes.find(parent) >= 0) { - disjoint_set.create_union(parent, node_index); - } - } - - Vector<GLTFNodeIndex> out_owners; - disjoint_set.get_representatives(out_owners); - - Vector<GLTFNodeIndex> out_roots; - - for (int i = 0; i < out_owners.size(); ++i) { - Vector<GLTFNodeIndex> set; - disjoint_set.get_members(set, out_owners[i]); - - const GLTFNodeIndex root = _find_highest_node(state, set); - ERR_FAIL_COND_V(root < 0, FAILED); - out_roots.push_back(root); - } - - out_roots.sort(); - - ERR_FAIL_COND_V(out_roots.size() == 0, FAILED); - - // Make sure the roots are the exact same (they better be) - ERR_FAIL_COND_V(out_roots.size() != skin.roots.size(), FAILED); - for (int i = 0; i < out_roots.size(); ++i) { - ERR_FAIL_COND_V(out_roots[i] != skin.roots[i], FAILED); - } - - // Single rooted skin? Perfectly ok! - if (out_roots.size() == 1) { - return OK; - } - - // Make sure all parents of a multi-rooted skin are the SAME - const GLTFNodeIndex parent = state.nodes[out_roots[0]]->parent; - for (int i = 1; i < out_roots.size(); ++i) { - if (state.nodes[out_roots[i]]->parent != parent) { - return FAILED; - } - } - - return OK; -} - -Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) { - if (!state.json.has("skins")) { - return OK; - } - - const Array &skins = state.json["skins"]; - - // Create the base skins, and mark nodes that are joints - for (int i = 0; i < skins.size(); i++) { - const Dictionary &d = skins[i]; - - GLTFSkin skin; - - ERR_FAIL_COND_V(!d.has("joints"), ERR_PARSE_ERROR); - - const Array &joints = d["joints"]; - - if (d.has("inverseBindMatrices")) { - skin.inverse_binds = _decode_accessor_as_xform(state, d["inverseBindMatrices"], false); - ERR_FAIL_COND_V(skin.inverse_binds.size() != joints.size(), ERR_PARSE_ERROR); - } - - for (int j = 0; j < joints.size(); j++) { - const GLTFNodeIndex node = joints[j]; - ERR_FAIL_INDEX_V(node, state.nodes.size(), ERR_PARSE_ERROR); - - skin.joints.push_back(node); - skin.joints_original.push_back(node); - - state.nodes[node]->joint = true; - } - - if (d.has("name")) { - skin.name = d["name"]; - } - - if (d.has("skeleton")) { - skin.skin_root = d["skeleton"]; - } - - state.skins.push_back(skin); - } - - for (GLTFSkinIndex i = 0; i < state.skins.size(); ++i) { - GLTFSkin &skin = state.skins.write[i]; - - // Expand the skin to capture all the extra non-joints that lie in between the actual joints, - // and expand the hierarchy to ensure multi-rooted trees lie on the same height level - ERR_FAIL_COND_V(_expand_skin(state, skin), ERR_PARSE_ERROR); - ERR_FAIL_COND_V(_verify_skin(state, skin), ERR_PARSE_ERROR); - } - - print_verbose("glTF: Total skins: " + itos(state.skins.size())); - - return OK; -} - -Error EditorSceneImporterGLTF::_determine_skeletons(GLTFState &state) { - // Using a disjoint set, we are going to potentially combine all skins that are actually branches - // of a main skeleton, or treat skins defining the same set of nodes as ONE skeleton. - // This is another unclear issue caused by the current glTF specification. - - DisjointSet<GLTFNodeIndex> skeleton_sets; - - for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) { - const GLTFSkin &skin = state.skins[skin_i]; - - Vector<GLTFNodeIndex> all_skin_nodes; - all_skin_nodes.append_array(skin.joints); - all_skin_nodes.append_array(skin.non_joints); - - for (int i = 0; i < all_skin_nodes.size(); ++i) { - const GLTFNodeIndex node_index = all_skin_nodes[i]; - const GLTFNodeIndex parent = state.nodes[node_index]->parent; - skeleton_sets.insert(node_index); - - if (all_skin_nodes.find(parent) >= 0) { - skeleton_sets.create_union(parent, node_index); - } - } - - // We are going to connect the separate skin subtrees in each skin together - // so that the final roots are entire sets of valid skin trees - for (int i = 1; i < skin.roots.size(); ++i) { - skeleton_sets.create_union(skin.roots[0], skin.roots[i]); - } - } - - { // attempt to joint all touching subsets (siblings/parent are part of another skin) - Vector<GLTFNodeIndex> groups_representatives; - skeleton_sets.get_representatives(groups_representatives); - - Vector<GLTFNodeIndex> highest_group_members; - Vector<Vector<GLTFNodeIndex>> groups; - for (int i = 0; i < groups_representatives.size(); ++i) { - Vector<GLTFNodeIndex> group; - skeleton_sets.get_members(group, groups_representatives[i]); - highest_group_members.push_back(_find_highest_node(state, group)); - groups.push_back(group); - } - - for (int i = 0; i < highest_group_members.size(); ++i) { - const GLTFNodeIndex node_i = highest_group_members[i]; - - // Attach any siblings together (this needs to be done n^2/2 times) - for (int j = i + 1; j < highest_group_members.size(); ++j) { - const GLTFNodeIndex node_j = highest_group_members[j]; - - // Even if they are siblings under the root! :) - if (state.nodes[node_i]->parent == state.nodes[node_j]->parent) { - skeleton_sets.create_union(node_i, node_j); - } - } - - // Attach any parenting going on together (we need to do this n^2 times) - const GLTFNodeIndex node_i_parent = state.nodes[node_i]->parent; - if (node_i_parent >= 0) { - for (int j = 0; j < groups.size() && i != j; ++j) { - const Vector<GLTFNodeIndex> &group = groups[j]; - - if (group.find(node_i_parent) >= 0) { - const GLTFNodeIndex node_j = highest_group_members[j]; - skeleton_sets.create_union(node_i, node_j); - } - } - } - } - } - - // At this point, the skeleton groups should be finalized - Vector<GLTFNodeIndex> skeleton_owners; - skeleton_sets.get_representatives(skeleton_owners); - - // Mark all the skins actual skeletons, after we have merged them - for (GLTFSkeletonIndex skel_i = 0; skel_i < skeleton_owners.size(); ++skel_i) { - const GLTFNodeIndex skeleton_owner = skeleton_owners[skel_i]; - GLTFSkeleton skeleton; - - Vector<GLTFNodeIndex> skeleton_nodes; - skeleton_sets.get_members(skeleton_nodes, skeleton_owner); - - for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) { - GLTFSkin &skin = state.skins.write[skin_i]; - - // If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton - for (int i = 0; i < skeleton_nodes.size(); ++i) { - GLTFNodeIndex skel_node_i = skeleton_nodes[i]; - if (skin.joints.find(skel_node_i) >= 0 || skin.non_joints.find(skel_node_i) >= 0) { - skin.skeleton = skel_i; - continue; - } - } - } - - Vector<GLTFNodeIndex> non_joints; - for (int i = 0; i < skeleton_nodes.size(); ++i) { - const GLTFNodeIndex node_i = skeleton_nodes[i]; - - if (state.nodes[node_i]->joint) { - skeleton.joints.push_back(node_i); - } else { - non_joints.push_back(node_i); - } - } - - state.skeletons.push_back(skeleton); - - _reparent_non_joint_skeleton_subtrees(state, state.skeletons.write[skel_i], non_joints); - } - - for (GLTFSkeletonIndex skel_i = 0; skel_i < state.skeletons.size(); ++skel_i) { - GLTFSkeleton &skeleton = state.skeletons.write[skel_i]; - - for (int i = 0; i < skeleton.joints.size(); ++i) { - const GLTFNodeIndex node_i = skeleton.joints[i]; - GLTFNode *node = state.nodes[node_i]; - - ERR_FAIL_COND_V(!node->joint, ERR_PARSE_ERROR); - ERR_FAIL_COND_V(node->skeleton >= 0, ERR_PARSE_ERROR); - node->skeleton = skel_i; - } - - ERR_FAIL_COND_V(_determine_skeleton_roots(state, skel_i), ERR_PARSE_ERROR); - } - - return OK; -} - -Error EditorSceneImporterGLTF::_reparent_non_joint_skeleton_subtrees(GLTFState &state, GLTFSkeleton &skeleton, const Vector<GLTFNodeIndex> &non_joints) { - DisjointSet<GLTFNodeIndex> subtree_set; - - // Populate the disjoint set with ONLY non joints that are in the skeleton hierarchy (non_joints vector) - // This way we can find any joints that lie in between joints, as the current glTF specification - // mentions nothing about non-joints being in between joints of the same skin. Hopefully one day we - // can remove this code. - - // skinD depicted here explains this issue: - // https://github.com/KhronosGroup/glTF-Asset-Generator/blob/master/Output/Positive/Animation_Skin - - for (int i = 0; i < non_joints.size(); ++i) { - const GLTFNodeIndex node_i = non_joints[i]; - - subtree_set.insert(node_i); - - const GLTFNodeIndex parent_i = state.nodes[node_i]->parent; - if (parent_i >= 0 && non_joints.find(parent_i) >= 0 && !state.nodes[parent_i]->joint) { - subtree_set.create_union(parent_i, node_i); - } - } - - // Find all the non joint subtrees and re-parent them to a new "fake" joint - - Vector<GLTFNodeIndex> non_joint_subtree_roots; - subtree_set.get_representatives(non_joint_subtree_roots); - - for (int root_i = 0; root_i < non_joint_subtree_roots.size(); ++root_i) { - const GLTFNodeIndex subtree_root = non_joint_subtree_roots[root_i]; - - Vector<GLTFNodeIndex> subtree_nodes; - subtree_set.get_members(subtree_nodes, subtree_root); - - for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) { - ERR_FAIL_COND_V(_reparent_to_fake_joint(state, skeleton, subtree_nodes[subtree_i]), FAILED); - - // We modified the tree, recompute all the heights - _compute_node_heights(state); - } - } - - return OK; -} - -Error EditorSceneImporterGLTF::_reparent_to_fake_joint(GLTFState &state, GLTFSkeleton &skeleton, const GLTFNodeIndex node_index) { - GLTFNode *node = state.nodes[node_index]; - - // Can we just "steal" this joint if it is just a spatial node? - if (node->skin < 0 && node->mesh < 0 && node->camera < 0) { - node->joint = true; - // Add the joint to the skeletons joints - skeleton.joints.push_back(node_index); - return OK; - } - - GLTFNode *fake_joint = memnew(GLTFNode); - const GLTFNodeIndex fake_joint_index = state.nodes.size(); - state.nodes.push_back(fake_joint); - - // We better not be a joint, or we messed up in our logic - if (node->joint) { - return FAILED; - } - - fake_joint->translation = node->translation; - fake_joint->rotation = node->rotation; - fake_joint->scale = node->scale; - fake_joint->xform = node->xform; - fake_joint->joint = true; - - // We can use the exact same name here, because the joint will be inside a skeleton and not the scene - fake_joint->name = node->name; - - // Clear the nodes transforms, since it will be parented to the fake joint - node->translation = Vector3(0, 0, 0); - node->rotation = Quat(); - node->scale = Vector3(1, 1, 1); - node->xform = Transform(); - - // Transfer the node children to the fake joint - for (int child_i = 0; child_i < node->children.size(); ++child_i) { - GLTFNode *child = state.nodes[node->children[child_i]]; - child->parent = fake_joint_index; - } - - fake_joint->children = node->children; - node->children.clear(); - - // add the fake joint to the parent and remove the original joint - if (node->parent >= 0) { - GLTFNode *parent = state.nodes[node->parent]; - parent->children.erase(node_index); - parent->children.push_back(fake_joint_index); - fake_joint->parent = node->parent; - } - - // Add the node to the fake joint - fake_joint->children.push_back(node_index); - node->parent = fake_joint_index; - node->fake_joint_parent = fake_joint_index; - - // Add the fake joint to the skeletons joints - skeleton.joints.push_back(fake_joint_index); - - // Replace skin_skeletons with fake joints if we must. - for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) { - GLTFSkin &skin = state.skins.write[skin_i]; - if (skin.skin_root == node_index) { - skin.skin_root = fake_joint_index; - } - } - - return OK; -} - -Error EditorSceneImporterGLTF::_determine_skeleton_roots(GLTFState &state, const GLTFSkeletonIndex skel_i) { - DisjointSet<GLTFNodeIndex> disjoint_set; - - for (GLTFNodeIndex i = 0; i < state.nodes.size(); ++i) { - const GLTFNode *node = state.nodes[i]; - - if (node->skeleton != skel_i) { - continue; - } - - disjoint_set.insert(i); - - if (node->parent >= 0 && state.nodes[node->parent]->skeleton == skel_i) { - disjoint_set.create_union(node->parent, i); - } - } - - GLTFSkeleton &skeleton = state.skeletons.write[skel_i]; - - Vector<GLTFNodeIndex> owners; - disjoint_set.get_representatives(owners); - - Vector<GLTFNodeIndex> roots; - - for (int i = 0; i < owners.size(); ++i) { - Vector<GLTFNodeIndex> set; - disjoint_set.get_members(set, owners[i]); - const GLTFNodeIndex root = _find_highest_node(state, set); - ERR_FAIL_COND_V(root < 0, FAILED); - roots.push_back(root); - } - - roots.sort(); - - skeleton.roots = roots; - - if (roots.size() == 0) { - return FAILED; - } else if (roots.size() == 1) { - return OK; - } - - // Check that the subtrees have the same parent root - const GLTFNodeIndex parent = state.nodes[roots[0]]->parent; - for (int i = 1; i < roots.size(); ++i) { - if (state.nodes[roots[i]]->parent != parent) { - return FAILED; - } - } - - return OK; -} - -Error EditorSceneImporterGLTF::_create_skeletons(GLTFState &state) { - for (GLTFSkeletonIndex skel_i = 0; skel_i < state.skeletons.size(); ++skel_i) { - GLTFSkeleton &gltf_skeleton = state.skeletons.write[skel_i]; - - Skeleton3D *skeleton = memnew(Skeleton3D); - gltf_skeleton.godot_skeleton = skeleton; - - // Make a unique name, no gltf node represents this skeleton - skeleton->set_name(_gen_unique_name(state, "Skeleton")); - - List<GLTFNodeIndex> bones; - - for (int i = 0; i < gltf_skeleton.roots.size(); ++i) { - bones.push_back(gltf_skeleton.roots[i]); - } - - // Make the skeleton creation deterministic by going through the roots in - // a sorted order, and DEPTH FIRST - bones.sort(); - - while (!bones.empty()) { - const GLTFNodeIndex node_i = bones.front()->get(); - bones.pop_front(); - - GLTFNode *node = state.nodes[node_i]; - ERR_FAIL_COND_V(node->skeleton != skel_i, FAILED); - - { // Add all child nodes to the stack (deterministically) - Vector<GLTFNodeIndex> child_nodes; - for (int i = 0; i < node->children.size(); ++i) { - const GLTFNodeIndex child_i = node->children[i]; - if (state.nodes[child_i]->skeleton == skel_i) { - child_nodes.push_back(child_i); - } - } - - // Depth first insertion - child_nodes.sort(); - for (int i = child_nodes.size() - 1; i >= 0; --i) { - bones.push_front(child_nodes[i]); - } - } - - const int bone_index = skeleton->get_bone_count(); - - if (node->name.empty()) { - node->name = "bone"; - } - - node->name = _gen_unique_bone_name(state, skel_i, node->name); - - skeleton->add_bone(node->name); - skeleton->set_bone_rest(bone_index, node->xform); - - if (node->parent >= 0 && state.nodes[node->parent]->skeleton == skel_i) { - const int bone_parent = skeleton->find_bone(state.nodes[node->parent]->name); - ERR_FAIL_COND_V(bone_parent < 0, FAILED); - skeleton->set_bone_parent(bone_index, skeleton->find_bone(state.nodes[node->parent]->name)); - } - - state.scene_nodes.insert(node_i, skeleton); - } - } - - ERR_FAIL_COND_V(_map_skin_joints_indices_to_skeleton_bone_indices(state), ERR_PARSE_ERROR); - - return OK; -} - -Error EditorSceneImporterGLTF::_map_skin_joints_indices_to_skeleton_bone_indices(GLTFState &state) { - for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) { - GLTFSkin &skin = state.skins.write[skin_i]; - - const GLTFSkeleton &skeleton = state.skeletons[skin.skeleton]; - - for (int joint_index = 0; joint_index < skin.joints_original.size(); ++joint_index) { - const GLTFNodeIndex node_i = skin.joints_original[joint_index]; - const GLTFNode *node = state.nodes[node_i]; - - skin.joint_i_to_name.insert(joint_index, node->name); - - const int bone_index = skeleton.godot_skeleton->find_bone(node->name); - ERR_FAIL_COND_V(bone_index < 0, FAILED); - - skin.joint_i_to_bone_i.insert(joint_index, bone_index); - } - } - - return OK; -} - -Error EditorSceneImporterGLTF::_create_skins(GLTFState &state) { - for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) { - GLTFSkin &gltf_skin = state.skins.write[skin_i]; - - Ref<Skin> skin; - skin.instance(); - - // Some skins don't have IBM's! What absolute monsters! - const bool has_ibms = !gltf_skin.inverse_binds.empty(); - - for (int joint_i = 0; joint_i < gltf_skin.joints_original.size(); ++joint_i) { - Transform xform; - if (has_ibms) { - xform = gltf_skin.inverse_binds[joint_i]; - } - - if (state.use_named_skin_binds) { - StringName name = gltf_skin.joint_i_to_name[joint_i]; - skin->add_named_bind(name, xform); - } else { - int bone_i = gltf_skin.joint_i_to_bone_i[joint_i]; - skin->add_bind(bone_i, xform); - } - } - - gltf_skin.godot_skin = skin; - } - - // Purge the duplicates! - _remove_duplicate_skins(state); - - // Create unique names now, after removing duplicates - for (GLTFSkinIndex skin_i = 0; skin_i < state.skins.size(); ++skin_i) { - Ref<Skin> skin = state.skins[skin_i].godot_skin; - if (skin->get_name().empty()) { - // Make a unique name, no gltf node represents this skin - skin->set_name(_gen_unique_name(state, "Skin")); - } - } - - return OK; -} - -bool EditorSceneImporterGLTF::_skins_are_same(const Ref<Skin> &skin_a, const Ref<Skin> &skin_b) { - if (skin_a->get_bind_count() != skin_b->get_bind_count()) { - return false; - } - - for (int i = 0; i < skin_a->get_bind_count(); ++i) { - if (skin_a->get_bind_bone(i) != skin_b->get_bind_bone(i)) { - return false; - } - - Transform a_xform = skin_a->get_bind_pose(i); - Transform b_xform = skin_b->get_bind_pose(i); - - if (a_xform != b_xform) { - return false; - } - } - - return true; -} - -void EditorSceneImporterGLTF::_remove_duplicate_skins(GLTFState &state) { - for (int i = 0; i < state.skins.size(); ++i) { - for (int j = i + 1; j < state.skins.size(); ++j) { - const Ref<Skin> &skin_i = state.skins[i].godot_skin; - const Ref<Skin> &skin_j = state.skins[j].godot_skin; - - if (_skins_are_same(skin_i, skin_j)) { - // replace it and delete the old - state.skins.write[j].godot_skin = skin_i; - } - } - } -} - -Error EditorSceneImporterGLTF::_parse_lights(GLTFState &state) { - if (!state.json.has("extensions")) { - return OK; - } - Dictionary extensions = state.json["extensions"]; - if (!extensions.has("KHR_lights_punctual")) { - return OK; - } - Dictionary lights_punctual = extensions["KHR_lights_punctual"]; - if (!lights_punctual.has("lights")) { - return OK; - } - - const Array &lights = lights_punctual["lights"]; - - for (GLTFLightIndex light_i = 0; light_i < lights.size(); light_i++) { - const Dictionary &d = lights[light_i]; - - GLTFLight light; - ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - const String &type = d["type"]; - light.type = type; - - if (d.has("color")) { - const Array &arr = d["color"]; - ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2]).to_srgb(); - light.color = c; - } - if (d.has("intensity")) { - light.intensity = d["intensity"]; - } - if (d.has("range")) { - light.range = d["range"]; - } - if (type == "spot") { - const Dictionary &spot = d["spot"]; - light.inner_cone_angle = spot["innerConeAngle"]; - light.outer_cone_angle = spot["outerConeAngle"]; - ERR_FAIL_COND_V_MSG(light.inner_cone_angle >= light.outer_cone_angle, ERR_PARSE_ERROR, "The inner angle must be smaller than the outer angle."); - } else if (type != "point" && type != "directional") { - ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Light type is unknown."); - } - - state.lights.push_back(light); - } - - print_verbose("glTF: Total lights: " + itos(state.lights.size())); - - return OK; -} - -Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) { - if (!state.json.has("cameras")) { - return OK; - } - - const Array &cameras = state.json["cameras"]; - - for (GLTFCameraIndex i = 0; i < cameras.size(); i++) { - const Dictionary &d = cameras[i]; - - GLTFCamera camera; - ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - const String &type = d["type"]; - if (type == "orthographic") { - camera.perspective = false; - if (d.has("orthographic")) { - const Dictionary &og = d["orthographic"]; - camera.fov_size = og["ymag"]; - camera.zfar = og["zfar"]; - camera.znear = og["znear"]; - } else { - camera.fov_size = 10; - } - - } else if (type == "perspective") { - camera.perspective = true; - if (d.has("perspective")) { - const Dictionary &ppt = d["perspective"]; - // GLTF spec is in radians, Godot's camera is in degrees. - camera.fov_size = (double)ppt["yfov"] * 180.0 / Math_PI; - camera.zfar = ppt["zfar"]; - camera.znear = ppt["znear"]; - } else { - camera.fov_size = 10; - } - } else { - ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera should be in 'orthographic' or 'perspective'"); - } - - state.cameras.push_back(camera); - } - - print_verbose("glTF: Total cameras: " + itos(state.cameras.size())); - - return OK; -} - -Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) { - if (!state.json.has("animations")) { - return OK; - } - - const Array &animations = state.json["animations"]; - - for (GLTFAnimationIndex i = 0; i < animations.size(); i++) { - const Dictionary &d = animations[i]; - - GLTFAnimation animation; - - if (!d.has("channels") || !d.has("samplers")) { - continue; - } - - Array channels = d["channels"]; - Array samplers = d["samplers"]; - - if (d.has("name")) { - String name = d["name"]; - if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) { - animation.loop = true; - } - animation.name = _sanitize_scene_name(name); - } - - for (int j = 0; j < channels.size(); j++) { - const Dictionary &c = channels[j]; - if (!c.has("target")) { - continue; - } - - const Dictionary &t = c["target"]; - if (!t.has("node") || !t.has("path")) { - continue; - } - - ERR_FAIL_COND_V(!c.has("sampler"), ERR_PARSE_ERROR); - const int sampler = c["sampler"]; - ERR_FAIL_INDEX_V(sampler, samplers.size(), ERR_PARSE_ERROR); - - GLTFNodeIndex node = t["node"]; - String path = t["path"]; - - ERR_FAIL_INDEX_V(node, state.nodes.size(), ERR_PARSE_ERROR); - - GLTFAnimation::Track *track = nullptr; - - if (!animation.tracks.has(node)) { - animation.tracks[node] = GLTFAnimation::Track(); - } - - track = &animation.tracks[node]; - - const Dictionary &s = samplers[sampler]; - - ERR_FAIL_COND_V(!s.has("input"), ERR_PARSE_ERROR); - ERR_FAIL_COND_V(!s.has("output"), ERR_PARSE_ERROR); - - const int input = s["input"]; - const int output = s["output"]; - - GLTFAnimation::Interpolation interp = GLTFAnimation::INTERP_LINEAR; - int output_count = 1; - if (s.has("interpolation")) { - const String &in = s["interpolation"]; - if (in == "STEP") { - interp = GLTFAnimation::INTERP_STEP; - } else if (in == "LINEAR") { - interp = GLTFAnimation::INTERP_LINEAR; - } else if (in == "CATMULLROMSPLINE") { - interp = GLTFAnimation::INTERP_CATMULLROMSPLINE; - output_count = 3; - } else if (in == "CUBICSPLINE") { - interp = GLTFAnimation::INTERP_CUBIC_SPLINE; - output_count = 3; - } - } - - const Vector<float> times = _decode_accessor_as_floats(state, input, false); - if (path == "translation") { - const Vector<Vector3> translations = _decode_accessor_as_vec3(state, output, false); - track->translation_track.interpolation = interp; - track->translation_track.times = Variant(times); //convert via variant - track->translation_track.values = Variant(translations); //convert via variant - } else if (path == "rotation") { - const Vector<Quat> rotations = _decode_accessor_as_quat(state, output, false); - track->rotation_track.interpolation = interp; - track->rotation_track.times = Variant(times); //convert via variant - track->rotation_track.values = rotations; //convert via variant - } else if (path == "scale") { - const Vector<Vector3> scales = _decode_accessor_as_vec3(state, output, false); - track->scale_track.interpolation = interp; - track->scale_track.times = Variant(times); //convert via variant - track->scale_track.values = Variant(scales); //convert via variant - } else if (path == "weights") { - const Vector<float> weights = _decode_accessor_as_floats(state, output, false); - - ERR_FAIL_INDEX_V(state.nodes[node]->mesh, state.meshes.size(), ERR_PARSE_ERROR); - const GLTFMesh *mesh = &state.meshes[state.nodes[node]->mesh]; - ERR_FAIL_COND_V(mesh->blend_weights.size() == 0, ERR_PARSE_ERROR); - const int wc = mesh->blend_weights.size(); - - track->weight_tracks.resize(wc); - - const int expected_value_count = times.size() * output_count * wc; - ERR_FAIL_COND_V_MSG(weights.size() != expected_value_count, ERR_PARSE_ERROR, "Invalid weight data, expected " + itos(expected_value_count) + " weight values, got " + itos(weights.size()) + " instead."); - - const int wlen = weights.size() / wc; - const float *r = weights.ptr(); - for (int k = 0; k < wc; k++) { //separate tracks, having them together is not such a good idea - GLTFAnimation::Channel<float> cf; - cf.interpolation = interp; - cf.times = Variant(times); - Vector<float> wdata; - wdata.resize(wlen); - for (int l = 0; l < wlen; l++) { - wdata.write[l] = r[l * wc + k]; - } - - cf.values = wdata; - track->weight_tracks.write[k] = cf; - } - } else { - WARN_PRINT("Invalid path '" + path + "'."); - } - } - - state.animations.push_back(animation); - } - - print_verbose("glTF: Total animations '" + itos(state.animations.size()) + "'."); - - return OK; -} - -void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) { - for (int i = 0; i < state.nodes.size(); i++) { - GLTFNode *n = state.nodes[i]; - - // Any joints get unique names generated when the skeleton is made, unique to the skeleton - if (n->skeleton >= 0) { - continue; - } - - if (n->name.empty()) { - if (n->mesh >= 0) { - n->name = "Mesh"; - } else if (n->camera >= 0) { - n->name = "Camera"; - } else { - n->name = "Node"; - } - } - - n->name = _gen_unique_name(state, n->name); - } -} - -BoneAttachment3D *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index) { - const GLTFNode *gltf_node = state.nodes[node_index]; - const GLTFNode *bone_node = state.nodes[gltf_node->parent]; - - BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D); - print_verbose("glTF: Creating bone attachment for: " + gltf_node->name); - - ERR_FAIL_COND_V(!bone_node->joint, nullptr); - - bone_attachment->set_bone_name(bone_node->name); - - return bone_attachment; -} - -EditorSceneImporterMeshNode *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { - const GLTFNode *gltf_node = state.nodes[node_index]; - - ERR_FAIL_INDEX_V(gltf_node->mesh, state.meshes.size(), nullptr); - - EditorSceneImporterMeshNode *mi = memnew(EditorSceneImporterMeshNode); - print_verbose("glTF: Creating mesh for: " + gltf_node->name); - - GLTFMesh &mesh = state.meshes.write[gltf_node->mesh]; - mi->set_mesh(mesh.mesh); - - if (mesh.mesh->get_name() == "") { - mesh.mesh->set_name(gltf_node->name); - } - - for (int i = 0; i < mesh.blend_weights.size(); i++) { - mi->set("blend_shapes/" + mesh.mesh->get_blend_shape_name(i), mesh.blend_weights[i]); - } - - return mi; -} - -Light3D *EditorSceneImporterGLTF::_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { - const GLTFNode *gltf_node = state.nodes[node_index]; - - ERR_FAIL_INDEX_V(gltf_node->light, state.lights.size(), nullptr); - - print_verbose("glTF: Creating light for: " + gltf_node->name); - - const GLTFLight &l = state.lights[gltf_node->light]; - - float intensity = l.intensity; - if (intensity > 10) { - // GLTF spec has the default around 1, but Blender defaults lights to 100. - // The only sane way to handle this is to check where it came from and - // handle it accordingly. If it's over 10, it probably came from Blender. - intensity /= 100; - } - - if (l.type == "directional") { - DirectionalLight3D *light = memnew(DirectionalLight3D); - light->set_param(Light3D::PARAM_ENERGY, intensity); - light->set_color(l.color); - return light; - } - - const float range = CLAMP(l.range, 0, 4096); - // Doubling the range will double the effective brightness, so we need double attenuation (half brightness). - // We want to have double intensity give double brightness, so we need half the attenuation. - const float attenuation = range / intensity; - if (l.type == "point") { - OmniLight3D *light = memnew(OmniLight3D); - light->set_param(OmniLight3D::PARAM_ATTENUATION, attenuation); - light->set_param(OmniLight3D::PARAM_RANGE, range); - light->set_color(l.color); - return light; - } - if (l.type == "spot") { - SpotLight3D *light = memnew(SpotLight3D); - light->set_param(SpotLight3D::PARAM_ATTENUATION, attenuation); - light->set_param(SpotLight3D::PARAM_RANGE, range); - light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad2deg(l.outer_cone_angle)); - light->set_color(l.color); - - // Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b - // The points in desmos are not exact, except for (1, infinity). - float angle_ratio = l.inner_cone_angle / l.outer_cone_angle; - float angle_attenuation = 0.2 / (1 - angle_ratio) - 0.1; - light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation); - return light; - } - return nullptr; -} - -Camera3D *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { - const GLTFNode *gltf_node = state.nodes[node_index]; - - ERR_FAIL_INDEX_V(gltf_node->camera, state.cameras.size(), nullptr); - - Camera3D *camera = memnew(Camera3D); - print_verbose("glTF: Creating camera for: " + gltf_node->name); - - const GLTFCamera &c = state.cameras[gltf_node->camera]; - if (c.perspective) { - camera->set_perspective(c.fov_size, c.znear, c.zfar); - } else { - camera->set_orthogonal(c.fov_size, c.znear, c.zfar); - } - - return camera; -} - -Node3D *EditorSceneImporterGLTF::_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { - const GLTFNode *gltf_node = state.nodes[node_index]; - - Node3D *spatial = memnew(Node3D); - print_verbose("glTF: Creating spatial for: " + gltf_node->name); - - return spatial; -} - -void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) { - const GLTFNode *gltf_node = state.nodes[node_index]; - - Node3D *current_node = nullptr; - - // Is our parent a skeleton - Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent); - - if (gltf_node->skeleton >= 0) { - Skeleton3D *skeleton = state.skeletons[gltf_node->skeleton].godot_skeleton; - - if (active_skeleton != skeleton) { - ERR_FAIL_COND_MSG(active_skeleton != nullptr, "glTF: Generating scene detected direct parented Skeletons"); - - // Add it to the scene if it has not already been added - if (skeleton->get_parent() == nullptr) { - scene_parent->add_child(skeleton); - skeleton->set_owner(scene_root); - } - } - - active_skeleton = skeleton; - current_node = skeleton; - } - - // If we have an active skeleton, and the node is node skinned, we need to create a bone attachment - if (current_node == nullptr && active_skeleton != nullptr && gltf_node->skin < 0) { - BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index); - - scene_parent->add_child(bone_attachment); - bone_attachment->set_owner(scene_root); - - // There is no gltf_node that represent this, so just directly create a unique name - bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment")); - - // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node - // and attach it to the bone_attachment - scene_parent = bone_attachment; - } - - // We still have not managed to make a node - if (current_node == nullptr) { - if (gltf_node->mesh >= 0) { - current_node = _generate_mesh_instance(state, scene_parent, node_index); - } else if (gltf_node->camera >= 0) { - current_node = _generate_camera(state, scene_parent, node_index); - } else if (gltf_node->light >= 0) { - current_node = _generate_light(state, scene_parent, node_index); - } else { - current_node = _generate_spatial(state, scene_parent, node_index); - } - - scene_parent->add_child(current_node); - current_node->set_owner(scene_root); - current_node->set_transform(gltf_node->xform); - current_node->set_name(gltf_node->name); - } - - state.scene_nodes.insert(node_index, current_node); - - for (int i = 0; i < gltf_node->children.size(); ++i) { - _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]); - } -} - -template <class T> -struct EditorSceneImporterGLTFInterpolate { - T lerp(const T &a, const T &b, float c) const { - return a + (b - a) * c; - } - - T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) { - const float t2 = t * t; - const float t3 = t2 * t; - - return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); - } - - T bezier(T start, T control_1, T control_2, T end, float t) { - /* Formula from Wikipedia article on Bezier curves. */ - const real_t omt = (1.0 - t); - const real_t omt2 = omt * omt; - const real_t omt3 = omt2 * omt; - const real_t t2 = t * t; - const real_t t3 = t2 * t; - - return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; - } -}; - -// thank you for existing, partial specialization -template <> -struct EditorSceneImporterGLTFInterpolate<Quat> { - Quat lerp(const Quat &a, const Quat &b, const float c) const { - ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quat(), "The quaternion \"a\" must be normalized."); - ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quat(), "The quaternion \"b\" must be normalized."); - - return a.slerp(b, c).normalized(); - } - - Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, const float c) { - ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quat(), "The quaternion \"p1\" must be normalized."); - ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quat(), "The quaternion \"p2\" must be normalized."); - - return p1.slerp(p2, c).normalized(); - } - - Quat bezier(const Quat start, const Quat control_1, const Quat control_2, const Quat end, const float t) { - ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quat(), "The end quaternion must be normalized."); - - return start.slerp(end, t).normalized(); - } -}; - -template <class T> -T EditorSceneImporterGLTF::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) { - //could use binary search, worth it? - int idx = -1; - for (int i = 0; i < p_times.size(); i++) { - if (p_times[i] > p_time) { - break; - } - idx++; - } - - EditorSceneImporterGLTFInterpolate<T> interp; - - switch (p_interp) { - case GLTFAnimation::INTERP_LINEAR: { - if (idx == -1) { - return p_values[0]; - } else if (idx >= p_times.size() - 1) { - return p_values[p_times.size() - 1]; - } - - const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - return interp.lerp(p_values[idx], p_values[idx + 1], c); - - } break; - case GLTFAnimation::INTERP_STEP: { - if (idx == -1) { - return p_values[0]; - } else if (idx >= p_times.size() - 1) { - return p_values[p_times.size() - 1]; - } - - return p_values[idx]; - - } break; - case GLTFAnimation::INTERP_CATMULLROMSPLINE: { - if (idx == -1) { - return p_values[1]; - } else if (idx >= p_times.size() - 1) { - return p_values[1 + p_times.size() - 1]; - } - - const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - return interp.catmull_rom(p_values[idx - 1], p_values[idx], p_values[idx + 1], p_values[idx + 3], c); - - } break; - case GLTFAnimation::INTERP_CUBIC_SPLINE: { - if (idx == -1) { - return p_values[1]; - } else if (idx >= p_times.size() - 1) { - return p_values[(p_times.size() - 1) * 3 + 1]; - } - - const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); - - const T from = p_values[idx * 3 + 1]; - const T c1 = from + p_values[idx * 3 + 2]; - const T to = p_values[idx * 3 + 4]; - const T c2 = to + p_values[idx * 3 + 3]; - - return interp.bezier(from, c1, c2, to, c); - - } break; - } - - ERR_FAIL_V(p_values[0]); -} - -void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps) { - const GLTFAnimation &anim = state.animations[index]; - - String name = anim.name; - if (name.empty()) { - // No node represent these, and they are not in the hierarchy, so just make a unique name - name = _gen_unique_name(state, "Animation"); - } - - Ref<Animation> animation; - animation.instance(); - animation->set_name(name); - - if (anim.loop) { - animation->set_loop(true); - } - - float length = 0; - - for (Map<int, GLTFAnimation::Track>::Element *E = anim.tracks.front(); E; E = E->next()) { - const GLTFAnimation::Track &track = E->get(); - //need to find the path - NodePath node_path; - - GLTFNodeIndex node_index = E->key(); - if (state.nodes[node_index]->fake_joint_parent >= 0) { - // Should be same as parent - node_index = state.nodes[node_index]->fake_joint_parent; - } - - const GLTFNode *node = state.nodes[E->key()]; - - if (node->skeleton >= 0) { - const Skeleton3D *sk = Object::cast_to<Skeleton3D>(state.scene_nodes.find(node_index)->get()); - ERR_FAIL_COND(sk == nullptr); - - const String path = ap->get_parent()->get_path_to(sk); - const String bone = node->name; - node_path = path + ":" + bone; - } else { - node_path = ap->get_parent()->get_path_to(state.scene_nodes.find(node_index)->get()); - } - - for (int i = 0; i < track.rotation_track.times.size(); i++) { - length = MAX(length, track.rotation_track.times[i]); - } - for (int i = 0; i < track.translation_track.times.size(); i++) { - length = MAX(length, track.translation_track.times[i]); - } - for (int i = 0; i < track.scale_track.times.size(); i++) { - length = MAX(length, track.scale_track.times[i]); - } - - for (int i = 0; i < track.weight_tracks.size(); i++) { - for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { - length = MAX(length, track.weight_tracks[i].times[j]); - } - } - - if (track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) { - //make transform track - int track_idx = animation->get_track_count(); - animation->add_track(Animation::TYPE_TRANSFORM); - animation->track_set_path(track_idx, node_path); - animation->track_set_imported(track_idx, true); - //first determine animation length - - const float increment = 1.0 / float(bake_fps); - float time = 0.0; - - Vector3 base_pos; - Quat base_rot; - Vector3 base_scale = Vector3(1, 1, 1); - - if (!track.rotation_track.values.size()) { - base_rot = state.nodes[E->key()]->rotation.normalized(); - } - - if (!track.translation_track.values.size()) { - base_pos = state.nodes[E->key()]->translation; - } - - if (!track.scale_track.values.size()) { - base_scale = state.nodes[E->key()]->scale; - } - - bool last = false; - while (true) { - Vector3 pos = base_pos; - Quat rot = base_rot; - Vector3 scale = base_scale; - - if (track.translation_track.times.size()) { - pos = _interpolate_track<Vector3>(track.translation_track.times, track.translation_track.values, time, track.translation_track.interpolation); - } - - if (track.rotation_track.times.size()) { - rot = _interpolate_track<Quat>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); - } - - if (track.scale_track.times.size()) { - scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation); - } - - if (node->skeleton >= 0) { - Transform xform; - xform.basis.set_quat_scale(rot, scale); - xform.origin = pos; - - const Skeleton3D *skeleton = state.skeletons[node->skeleton].godot_skeleton; - const int bone_idx = skeleton->find_bone(node->name); - xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform; - - rot = xform.basis.get_rotation_quat(); - rot.normalize(); - scale = xform.basis.get_scale(); - pos = xform.origin; - } - - animation->transform_track_insert_key(track_idx, time, pos, rot, scale); - - if (last) { - break; - } - time += increment; - if (time >= length) { - last = true; - time = length; - } - } - } - - for (int i = 0; i < track.weight_tracks.size(); i++) { - ERR_CONTINUE(node->mesh < 0 || node->mesh >= state.meshes.size()); - const GLTFMesh &mesh = state.meshes[node->mesh]; - const String prop = "blend_shapes/" + mesh.mesh->get_blend_shape_name(i); - - const String blend_path = String(node_path) + ":" + prop; - - const int track_idx = animation->get_track_count(); - animation->add_track(Animation::TYPE_VALUE); - animation->track_set_path(track_idx, blend_path); - - // Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation, - // the other modes have to be baked. - GLTFAnimation::Interpolation gltf_interp = track.weight_tracks[i].interpolation; - if (gltf_interp == GLTFAnimation::INTERP_LINEAR || gltf_interp == GLTFAnimation::INTERP_STEP) { - animation->track_set_interpolation_type(track_idx, gltf_interp == GLTFAnimation::INTERP_STEP ? Animation::INTERPOLATION_NEAREST : Animation::INTERPOLATION_LINEAR); - for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { - const float t = track.weight_tracks[i].times[j]; - const float w = track.weight_tracks[i].values[j]; - animation->track_insert_key(track_idx, t, w); - } - } else { - // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies. - const float increment = 1.0 / float(bake_fps); - float time = 0.0; - bool last = false; - while (true) { - _interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp); - if (last) { - break; - } - time += increment; - if (time >= length) { - last = true; - time = length; - } - } - } - } - } - - animation->set_length(length); - - ap->add_animation(name, animation); -} - -void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Node3D *scene_root) { - for (GLTFNodeIndex node_i = 0; node_i < state.nodes.size(); ++node_i) { - const GLTFNode *node = state.nodes[node_i]; - - if (node->skin >= 0 && node->mesh >= 0) { - const GLTFSkinIndex skin_i = node->skin; - - Map<GLTFNodeIndex, Node *>::Element *mi_element = state.scene_nodes.find(node_i); - EditorSceneImporterMeshNode *mi = Object::cast_to<EditorSceneImporterMeshNode>(mi_element->get()); - ERR_FAIL_COND(mi == nullptr); - - const GLTFSkeletonIndex skel_i = state.skins[node->skin].skeleton; - const GLTFSkeleton &gltf_skeleton = state.skeletons[skel_i]; - Skeleton3D *skeleton = gltf_skeleton.godot_skeleton; - ERR_FAIL_COND(skeleton == nullptr); - - mi->get_parent()->remove_child(mi); - skeleton->add_child(mi); - mi->set_owner(scene_root); - - mi->set_skin(state.skins[skin_i].godot_skin); - mi->set_skeleton_path(mi->get_path_to(skeleton)); - mi->set_transform(Transform()); - } - } -} - -Node3D *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, const int p_bake_fps) { - Node3D *root = memnew(Node3D); - - // scene_name is already unique - root->set_name(state.scene_name); - - for (int i = 0; i < state.root_nodes.size(); ++i) { - _generate_scene_node(state, root, root, state.root_nodes[i]); - } - - _process_mesh_instances(state, root); - - if (state.animations.size()) { - AnimationPlayer *ap = memnew(AnimationPlayer); - ap->set_name("AnimationPlayer"); - root->add_child(ap); - ap->set_owner(root); - - for (int i = 0; i < state.animations.size(); i++) { - _import_animation(state, ap, i, p_bake_fps); - } - } - - return root; -} - -Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { - print_verbose(vformat("glTF: Importing file %s as scene.", p_path)); - - GLTFState state; - - if (p_path.to_lower().ends_with("glb")) { - //binary file - //text file - Error err = _parse_glb(p_path, state); - if (err) { - return nullptr; - } - } else { - //text file - Error err = _parse_json(p_path, state); - if (err) { - return nullptr; - } - } - - ERR_FAIL_COND_V(!state.json.has("asset"), nullptr); - - Dictionary asset = state.json["asset"]; - - ERR_FAIL_COND_V(!asset.has("version"), nullptr); - - String version = asset["version"]; - - state.import_flags = p_flags; - state.major_version = version.get_slice(".", 0).to_int(); - state.minor_version = version.get_slice(".", 1).to_int(); - state.use_named_skin_binds = p_flags & IMPORT_USE_NAMED_SKIN_BINDS; - - /* STEP 0 PARSE SCENE */ - Error err = _parse_scenes(state); - if (err != OK) { - return nullptr; - } - - /* STEP 1 PARSE NODES */ - err = _parse_nodes(state); - if (err != OK) { - return nullptr; - } - - /* STEP 2 PARSE BUFFERS */ - err = _parse_buffers(state, p_path.get_base_dir()); - if (err != OK) { - return nullptr; - } - - /* STEP 3 PARSE BUFFER VIEWS */ - err = _parse_buffer_views(state); - if (err != OK) { - return nullptr; - } - - /* STEP 4 PARSE ACCESSORS */ - err = _parse_accessors(state); - if (err != OK) { - return nullptr; - } - - /* STEP 5 PARSE IMAGES */ - err = _parse_images(state, p_path.get_base_dir()); - if (err != OK) { - return nullptr; - } - - /* STEP 6 PARSE TEXTURES */ - err = _parse_textures(state); - if (err != OK) { - return nullptr; - } - - /* STEP 7 PARSE TEXTURES */ - err = _parse_materials(state); - if (err != OK) { - return nullptr; - } - - /* STEP 9 PARSE SKINS */ - err = _parse_skins(state); - if (err != OK) { - return nullptr; - } - - /* STEP 10 DETERMINE SKELETONS */ - err = _determine_skeletons(state); - if (err != OK) { - return nullptr; - } - - /* STEP 11 CREATE SKELETONS */ - err = _create_skeletons(state); - if (err != OK) { - return nullptr; - } - - /* STEP 12 CREATE SKINS */ - err = _create_skins(state); - if (err != OK) { - return nullptr; - } - - /* STEP 13 PARSE MESHES (we have enough info now) */ - err = _parse_meshes(state); - if (err != OK) { - return nullptr; - } - - /* STEP 14 PARSE LIGHTS */ - err = _parse_lights(state); - if (err != OK) { - return NULL; - } - - /* STEP 15 PARSE CAMERAS */ - err = _parse_cameras(state); - if (err != OK) { - return nullptr; - } - - /* STEP 16 PARSE ANIMATIONS */ - err = _parse_animations(state); - if (err != OK) { - return nullptr; - } - - /* STEP 17 ASSIGN SCENE NAMES */ - _assign_scene_names(state); - - /* STEP 18 MAKE SCENE! */ - Node3D *scene = _generate_scene(state, p_bake_fps); - - return scene; -} - -Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return Ref<Animation>(); -} - -EditorSceneImporterGLTF::EditorSceneImporterGLTF() { -} diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h deleted file mode 100644 index e6163a46be..0000000000 --- a/editor/import/editor_scene_importer_gltf.h +++ /dev/null @@ -1,384 +0,0 @@ -/*************************************************************************/ -/* editor_scene_importer_gltf.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 EDITOR_SCENE_IMPORTER_GLTF_H -#define EDITOR_SCENE_IMPORTER_GLTF_H - -#include "editor/import/resource_importer_scene.h" -#include "scene/3d/light_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" - -class AnimationPlayer; -class BoneAttachment3D; -class EditorSceneImporterMeshNode; - -class EditorSceneImporterGLTF : public EditorSceneImporter { - GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter); - - typedef int GLTFAccessorIndex; - typedef int GLTFAnimationIndex; - typedef int GLTFBufferIndex; - typedef int GLTFBufferViewIndex; - typedef int GLTFCameraIndex; - typedef int GLTFImageIndex; - typedef int GLTFMaterialIndex; - typedef int GLTFMeshIndex; - typedef int GLTFLightIndex; - typedef int GLTFNodeIndex; - typedef int GLTFSkeletonIndex; - typedef int GLTFSkinIndex; - typedef int GLTFTextureIndex; - - enum { - ARRAY_BUFFER = 34962, - ELEMENT_ARRAY_BUFFER = 34963, - - TYPE_BYTE = 5120, - TYPE_UNSIGNED_BYTE = 5121, - TYPE_SHORT = 5122, - TYPE_UNSIGNED_SHORT = 5123, - TYPE_UNSIGNED_INT = 5125, - TYPE_FLOAT = 5126, - - COMPONENT_TYPE_BYTE = 5120, - COMPONENT_TYPE_UNSIGNED_BYTE = 5121, - COMPONENT_TYPE_SHORT = 5122, - COMPONENT_TYPE_UNSIGNED_SHORT = 5123, - COMPONENT_TYPE_INT = 5125, - COMPONENT_TYPE_FLOAT = 5126, - - }; - - String _get_component_type_name(const uint32_t p_component); - int _get_component_type_size(const int component_type); - - enum GLTFType { - TYPE_SCALAR, - TYPE_VEC2, - TYPE_VEC3, - TYPE_VEC4, - TYPE_MAT2, - TYPE_MAT3, - TYPE_MAT4, - }; - - String _get_type_name(const GLTFType p_component); - - struct GLTFNode { - //matrices need to be transformed to this - GLTFNodeIndex parent = -1; - int height = -1; - - Transform xform; - String name; - - GLTFMeshIndex mesh = -1; - GLTFCameraIndex camera = -1; - GLTFSkinIndex skin = -1; - - GLTFSkeletonIndex skeleton = -1; - bool joint = false; - - Vector3 translation; - Quat rotation; - Vector3 scale = Vector3(1, 1, 1); - - Vector<int> children; - - GLTFNodeIndex fake_joint_parent = -1; - - GLTFLightIndex light = -1; - }; - - struct GLTFBufferView { - GLTFBufferIndex buffer = -1; - int byte_offset = 0; - int byte_length = 0; - int byte_stride = 0; - bool indices = false; - //matrices need to be transformed to this - }; - - struct GLTFAccessor { - GLTFBufferViewIndex buffer_view = 0; - int byte_offset = 0; - int component_type = 0; - bool normalized = false; - int count = 0; - GLTFType type = GLTFType::TYPE_SCALAR; - float min = 0; - float max = 0; - int sparse_count = 0; - int sparse_indices_buffer_view = 0; - int sparse_indices_byte_offset = 0; - int sparse_indices_component_type = 0; - int sparse_values_buffer_view = 0; - int sparse_values_byte_offset = 0; - }; - struct GLTFTexture { - GLTFImageIndex src_image; - }; - - struct GLTFSkeleton { - // The *synthesized* skeletons joints - Vector<GLTFNodeIndex> joints; - - // The roots of the skeleton. If there are multiple, each root must have the same parent - // (ie roots are siblings) - Vector<GLTFNodeIndex> roots; - - // The created Skeleton for the scene - Skeleton3D *godot_skeleton = nullptr; - - // Set of unique bone names for the skeleton - Set<String> unique_names; - }; - - struct GLTFSkin { - String name; - - // The "skeleton" property defined in the gltf spec. -1 = Scene Root - GLTFNodeIndex skin_root = -1; - - Vector<GLTFNodeIndex> joints_original; - Vector<Transform> inverse_binds; - - // Note: joints + non_joints should form a complete subtree, or subtrees with a common parent - - // All nodes that are skins that are caught in-between the original joints - // (inclusive of joints_original) - Vector<GLTFNodeIndex> joints; - - // All Nodes that are caught in-between skin joint nodes, and are not defined - // as joints by any skin - Vector<GLTFNodeIndex> non_joints; - - // The roots of the skin. In the case of multiple roots, their parent *must* - // be the same (the roots must be siblings) - Vector<GLTFNodeIndex> roots; - - // The GLTF Skeleton this Skin points to (after we determine skeletons) - GLTFSkeletonIndex skeleton = -1; - - // A mapping from the joint indices (in the order of joints_original) to the - // Godot Skeleton's bone_indices - Map<int, int> joint_i_to_bone_i; - Map<int, StringName> joint_i_to_name; - - // The Actual Skin that will be created as a mapping between the IBM's of this skin - // to the generated skeleton for the mesh instances. - Ref<Skin> godot_skin; - }; - - struct GLTFMesh { - Ref<EditorSceneImporterMesh> mesh; - Vector<float> blend_weights; - }; - - struct GLTFCamera { - bool perspective = true; - float fov_size = 75; - float zfar = 4000; - float znear = 0.05; - }; - - struct GLTFLight { - Color color = Color(1.0f, 1.0f, 1.0f); - float intensity = 1.0f; - String type = ""; - float range = Math_INF; - float inner_cone_angle = 0.0f; - float outer_cone_angle = Math_PI / 4.0; - }; - - struct GLTFAnimation { - bool loop = false; - - enum Interpolation { - INTERP_LINEAR, - INTERP_STEP, - INTERP_CATMULLROMSPLINE, - INTERP_CUBIC_SPLINE - }; - - template <class T> - struct Channel { - Interpolation interpolation; - Vector<float> times; - Vector<T> values; - }; - - struct Track { - Channel<Vector3> translation_track; - Channel<Quat> rotation_track; - Channel<Vector3> scale_track; - Vector<Channel<float>> weight_tracks; - }; - - String name; - - Map<int, Track> tracks; - }; - - struct GLTFState { - Dictionary json; - int major_version = 0; - int minor_version = 0; - Vector<uint8_t> glb_data; - - bool use_named_skin_binds = false; - - Vector<GLTFNode *> nodes; - Vector<Vector<uint8_t>> buffers; - Vector<GLTFBufferView> buffer_views; - Vector<GLTFAccessor> accessors; - - Vector<GLTFMesh> meshes; //meshes are loaded directly, no reason not to. - Vector<Ref<StandardMaterial3D>> materials; - - String scene_name; - Vector<int> root_nodes; - - Vector<GLTFTexture> textures; - Vector<Ref<Texture2D>> images; - - Vector<GLTFSkin> skins; - Vector<GLTFCamera> cameras; - Vector<GLTFLight> lights; - - Set<String> unique_names; - - Vector<GLTFSkeleton> skeletons; - Vector<GLTFAnimation> animations; - - Map<GLTFNodeIndex, Node *> scene_nodes; - - // EditorSceneImporter::ImportFlags - uint32_t import_flags; - - ~GLTFState() { - for (int i = 0; i < nodes.size(); i++) { - memdelete(nodes[i]); - } - } - }; - - String _sanitize_scene_name(const String &name); - String _gen_unique_name(GLTFState &state, const String &p_name); - - String _sanitize_bone_name(const String &name); - String _gen_unique_bone_name(GLTFState &state, const GLTFSkeletonIndex skel_i, const String &p_name); - - Ref<Texture2D> _get_texture(GLTFState &state, const GLTFTextureIndex p_texture); - - Error _parse_json(const String &p_path, GLTFState &state); - Error _parse_glb(const String &p_path, GLTFState &state); - - Error _parse_scenes(GLTFState &state); - Error _parse_nodes(GLTFState &state); - - void _compute_node_heights(GLTFState &state); - - Error _parse_buffers(GLTFState &state, const String &p_base_path); - Error _parse_buffer_views(GLTFState &state); - GLTFType _get_type_from_str(const String &p_string); - Error _parse_accessors(GLTFState &state); - Error _decode_buffer_view(GLTFState &state, double *dst, const GLTFBufferViewIndex p_buffer_view, const int skip_every, const int skip_bytes, const int element_size, const int count, const GLTFType type, const int component_count, const int component_type, const int component_size, const bool normalized, const int byte_offset, const bool for_vertex); - - Vector<double> _decode_accessor(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<float> _decode_accessor_as_floats(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<int> _decode_accessor_as_ints(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Vector2> _decode_accessor_as_vec2(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Vector3> _decode_accessor_as_vec3(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Color> _decode_accessor_as_color(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Quat> _decode_accessor_as_quat(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Transform2D> _decode_accessor_as_xform2d(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Basis> _decode_accessor_as_basis(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Transform> _decode_accessor_as_xform(GLTFState &state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - - Error _parse_meshes(GLTFState &state); - Error _parse_images(GLTFState &state, const String &p_base_path); - Error _parse_textures(GLTFState &state); - - Error _parse_materials(GLTFState &state); - - GLTFNodeIndex _find_highest_node(GLTFState &state, const Vector<GLTFNodeIndex> &subset); - - bool _capture_nodes_in_skin(GLTFState &state, GLTFSkin &skin, const GLTFNodeIndex node_index); - void _capture_nodes_for_multirooted_skin(GLTFState &state, GLTFSkin &skin); - Error _expand_skin(GLTFState &state, GLTFSkin &skin); - Error _verify_skin(GLTFState &state, GLTFSkin &skin); - Error _parse_skins(GLTFState &state); - - Error _determine_skeletons(GLTFState &state); - Error _reparent_non_joint_skeleton_subtrees(GLTFState &state, GLTFSkeleton &skeleton, const Vector<GLTFNodeIndex> &non_joints); - Error _reparent_to_fake_joint(GLTFState &state, GLTFSkeleton &skeleton, const GLTFNodeIndex node_index); - Error _determine_skeleton_roots(GLTFState &state, const GLTFSkeletonIndex skel_i); - - Error _create_skeletons(GLTFState &state); - Error _map_skin_joints_indices_to_skeleton_bone_indices(GLTFState &state); - - Error _create_skins(GLTFState &state); - bool _skins_are_same(const Ref<Skin> &skin_a, const Ref<Skin> &skin_b); - void _remove_duplicate_skins(GLTFState &state); - - Error _parse_cameras(GLTFState &state); - Error _parse_lights(GLTFState &state); - Error _parse_animations(GLTFState &state); - - BoneAttachment3D *_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index); - EditorSceneImporterMeshNode *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); - Camera3D *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); - Light3D *_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); - Node3D *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); - - void _generate_scene_node(GLTFState &state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index); - Node3D *_generate_scene(GLTFState &state, const int p_bake_fps); - - void _process_mesh_instances(GLTFState &state, Node3D *scene_root); - - void _assign_scene_names(GLTFState &state); - - template <class T> - T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp); - - void _import_animation(GLTFState &state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps); - -public: - virtual uint32_t get_import_flags() const override; - virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; - - EditorSceneImporterGLTF(); -}; - -#endif // EDITOR_SCENE_IMPORTER_GLTF_H diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index ac068c05cf..6166b83ae0 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -373,7 +373,7 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const int x = slice_w * j; int y = slice_h * i; Ref<Image> slice = image->get_rect(Rect2(x, y, slice_w, slice_h)); - ERR_CONTINUE(slice.is_null() || slice->empty()); + ERR_CONTINUE(slice.is_null() || slice->is_empty()); if (slice->get_width() != slice_w || slice->get_height() != slice_h) { slice->resize(slice_w, slice_h); } diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 30c7b2920a..e7170ef61c 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -32,6 +32,8 @@ #include "core/io/resource_saver.h" #include "core/os/file_access.h" +#include "editor/import/scene_importer_mesh.h" +#include "editor/import/scene_importer_mesh_node_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/node_3d.h" #include "scene/resources/mesh.h" @@ -444,7 +446,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i)); } - EditorSceneImporterMeshNode *mi = memnew(EditorSceneImporterMeshNode); + EditorSceneImporterMeshNode3D *mi = memnew(EditorSceneImporterMeshNode3D); mi->set_mesh(mesh); mi->set_name(E->get()->get_name()); scene->add_child(mi); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index b591627660..ea16551f18 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -32,6 +32,7 @@ #include "core/io/resource_saver.h" #include "editor/editor_node.h" +#include "editor/import/scene_importer_mesh_node_3d.h" #include "scene/3d/collision_shape_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/navigation_3d.h" @@ -120,345 +121,6 @@ void EditorSceneImporter::_bind_methods() { BIND_CONSTANT(IMPORT_USE_COMPRESSION); } -//////////////////////////////////////////////// - -void EditorSceneImporterMesh::add_blend_shape(const String &p_name) { - ERR_FAIL_COND(surfaces.size() > 0); - blend_shapes.push_back(p_name); -} - -int EditorSceneImporterMesh::get_blend_shape_count() const { - return blend_shapes.size(); -} - -String EditorSceneImporterMesh::get_blend_shape_name(int p_blend_shape) const { - ERR_FAIL_INDEX_V(p_blend_shape, blend_shapes.size(), String()); - return blend_shapes[p_blend_shape]; -} - -void EditorSceneImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) { - blend_shape_mode = p_blend_shape_mode; -} -Mesh::BlendShapeMode EditorSceneImporterMesh::get_blend_shape_mode() const { - return blend_shape_mode; -} - -void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name) { - ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size()); - ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX); - Surface s; - s.primitive = p_primitive; - s.arrays = p_arrays; - s.name = p_name; - - for (int i = 0; i < blend_shapes.size(); i++) { - Array bsdata = p_blend_shapes[i]; - ERR_FAIL_COND(bsdata.size() != Mesh::ARRAY_MAX); - Surface::BlendShape bs; - bs.arrays = bsdata; - s.blend_shape_data.push_back(bs); - } - - List<Variant> lods; - p_lods.get_key_list(&lods); - for (List<Variant>::Element *E = lods.front(); E; E = E->next()) { - ERR_CONTINUE(!E->get().is_num()); - Surface::LOD lod; - lod.distance = E->get(); - lod.indices = p_lods[E->get()]; - ERR_CONTINUE(lod.indices.size() == 0); - s.lods.push_back(lod); - } - - s.material = p_material; - - surfaces.push_back(s); - mesh.unref(); -} -int EditorSceneImporterMesh::get_surface_count() const { - return surfaces.size(); -} - -Mesh::PrimitiveType EditorSceneImporterMesh::get_surface_primitive_type(int p_surface) { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Mesh::PRIMITIVE_MAX); - return surfaces[p_surface].primitive; -} -Array EditorSceneImporterMesh::get_surface_arrays(int p_surface) const { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); - return surfaces[p_surface].arrays; -} -String EditorSceneImporterMesh::get_surface_name(int p_surface) const { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), String()); - return surfaces[p_surface].name; -} -Array EditorSceneImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); - ERR_FAIL_INDEX_V(p_blend_shape, surfaces[p_surface].blend_shape_data.size(), Array()); - return surfaces[p_surface].blend_shape_data[p_blend_shape].arrays; -} -int EditorSceneImporterMesh::get_surface_lod_count(int p_surface) const { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); - return surfaces[p_surface].lods.size(); -} -Vector<int> EditorSceneImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Vector<int>()); - ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), Vector<int>()); - - return surfaces[p_surface].lods[p_lod].indices; -} - -float EditorSceneImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); - ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), 0); - return surfaces[p_surface].lods[p_lod].distance; -} - -Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Ref<Material>()); - return surfaces[p_surface].material; -} - -void EditorSceneImporterMesh::generate_lods() { - if (!SurfaceTool::simplify_func) { - return; - } - - for (int i = 0; i < surfaces.size(); i++) { - if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) { - continue; - } - - surfaces.write[i].lods.clear(); - Vector<Vector3> vertices = surfaces[i].arrays[RS::ARRAY_VERTEX]; - Vector<int> indices = surfaces[i].arrays[RS::ARRAY_INDEX]; - if (indices.size() == 0) { - continue; //no lods if no indices - } - uint32_t vertex_count = vertices.size(); - const Vector3 *vertices_ptr = vertices.ptr(); - - int min_indices = 10; - int index_target = indices.size() / 2; - print_line("total: " + itos(indices.size())); - while (index_target > min_indices) { - float error; - Vector<int> new_indices; - new_indices.resize(indices.size()); - size_t new_len = SurfaceTool::simplify_func((unsigned int *)new_indices.ptrw(), (const unsigned int *)indices.ptr(), indices.size(), (const float *)vertices_ptr, vertex_count, sizeof(Vector3), index_target, 1e20, &error); - print_line("shoot for " + itos(index_target) + ", got " + itos(new_len) + " distance " + rtos(error)); - if ((int)new_len > (index_target * 120 / 100)) { - break; // 20 percent tolerance - } - new_indices.resize(new_len); - Surface::LOD lod; - lod.distance = error; - lod.indices = new_indices; - surfaces.write[i].lods.push_back(lod); - index_target /= 2; - } - } -} - -bool EditorSceneImporterMesh::has_mesh() const { - return mesh.is_valid(); -} - -Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() { - ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>()); - - if (mesh.is_null()) { - mesh.instance(); - for (int i = 0; i < blend_shapes.size(); i++) { - mesh->add_blend_shape(blend_shapes[i]); - } - mesh->set_blend_shape_mode(blend_shape_mode); - for (int i = 0; i < surfaces.size(); i++) { - Array bs_data; - if (surfaces[i].blend_shape_data.size()) { - for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) { - bs_data.push_back(surfaces[i].blend_shape_data[j].arrays); - } - } - Dictionary lods; - if (surfaces[i].lods.size()) { - for (int j = 0; j < surfaces[i].lods.size(); j++) { - lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices; - } - } - - mesh->add_surface_from_arrays(surfaces[i].primitive, surfaces[i].arrays, bs_data, lods); - if (surfaces[i].material.is_valid()) { - mesh->surface_set_material(mesh->get_surface_count() - 1, surfaces[i].material); - } - if (surfaces[i].name != String()) { - mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name); - } - } - } - - return mesh; -} - -void EditorSceneImporterMesh::clear() { - surfaces.clear(); - blend_shapes.clear(); - mesh.unref(); -} - -void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) { - clear(); - if (p_data.has("blend_shape_names")) { - blend_shapes = p_data["blend_shape_names"]; - } - if (p_data.has("surfaces")) { - Array surface_arr = p_data["surfaces"]; - for (int i = 0; i < surface_arr.size(); i++) { - Dictionary s = surface_arr[i]; - ERR_CONTINUE(!s.has("primitive")); - ERR_CONTINUE(!s.has("arrays")); - Mesh::PrimitiveType prim = Mesh::PrimitiveType(int(s["primitive"])); - ERR_CONTINUE(prim >= Mesh::PRIMITIVE_MAX); - Array arr = s["arrays"]; - Dictionary lods; - String name; - if (s.has("name")) { - name = s["name"]; - } - if (s.has("lods")) { - lods = s["lods"]; - } - Array blend_shapes; - if (s.has("blend_shapes")) { - blend_shapes = s["blend_shapes"]; - } - Ref<Material> material; - if (s.has("material")) { - material = s["material"]; - } - add_surface(prim, arr, blend_shapes, lods, material, name); - } - } -} -Dictionary EditorSceneImporterMesh::_get_data() const { - Dictionary data; - if (blend_shapes.size()) { - data["blend_shape_names"] = blend_shapes; - } - Array surface_arr; - for (int i = 0; i < surfaces.size(); i++) { - Dictionary d; - d["primitive"] = surfaces[i].primitive; - d["arrays"] = surfaces[i].arrays; - if (surfaces[i].blend_shape_data.size()) { - Array bs_data; - for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) { - bs_data.push_back(surfaces[i].blend_shape_data[j].arrays); - } - d["blend_shapes"] = bs_data; - } - if (surfaces[i].lods.size()) { - Dictionary lods; - for (int j = 0; j < surfaces[i].lods.size(); j++) { - lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices; - } - d["lods"] = lods; - } - - if (surfaces[i].material.is_valid()) { - d["material"] = surfaces[i].material; - } - - if (surfaces[i].name != String()) { - d["name"] = surfaces[i].name; - } - - surface_arr.push_back(d); - } - data["surfaces"] = surface_arr; - return data; -} - -void EditorSceneImporterMesh::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape); - ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count); - ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &EditorSceneImporterMesh::get_blend_shape_name); - - ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode); - ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode); - - ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String())); - - ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count); - ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type); - ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &EditorSceneImporterMesh::get_surface_name); - ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &EditorSceneImporterMesh::get_surface_arrays); - ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &EditorSceneImporterMesh::get_surface_blend_shape_arrays); - ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &EditorSceneImporterMesh::get_surface_lod_count); - ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_size); - ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_indices); - ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &EditorSceneImporterMesh::get_surface_material); - - ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMesh::get_mesh); - ClassDB::bind_method(D_METHOD("clear"), &EditorSceneImporterMesh::clear); - - ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data); - ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data); - - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data"); -} - -void EditorSceneImporterMeshNode::set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh) { - mesh = p_mesh; -} -Ref<EditorSceneImporterMesh> EditorSceneImporterMeshNode::get_mesh() const { - return mesh; -} - -void EditorSceneImporterMeshNode::set_skin(const Ref<Skin> &p_skin) { - skin = p_skin; -} -Ref<Skin> EditorSceneImporterMeshNode::get_skin() const { - return skin; -} - -void EditorSceneImporterMeshNode::set_surface_material(int p_idx, const Ref<Material> &p_material) { - ERR_FAIL_COND(p_idx < 0); - if (p_idx >= surface_materials.size()) { - surface_materials.resize(p_idx + 1); - } - - surface_materials.write[p_idx] = p_material; -} -Ref<Material> EditorSceneImporterMeshNode::get_surface_material(int p_idx) const { - ERR_FAIL_COND_V(p_idx < 0, Ref<Material>()); - if (p_idx >= surface_materials.size()) { - return Ref<Material>(); - } - return surface_materials[p_idx]; -} - -void EditorSceneImporterMeshNode::set_skeleton_path(const NodePath &p_path) { - skeleton_path = p_path; -} -NodePath EditorSceneImporterMeshNode::get_skeleton_path() const { - return skeleton_path; -} - -void EditorSceneImporterMeshNode::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &EditorSceneImporterMeshNode::set_mesh); - ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMeshNode::get_mesh); - - ClassDB::bind_method(D_METHOD("set_skin", "skin"), &EditorSceneImporterMeshNode::set_skin); - ClassDB::bind_method(D_METHOD("get_skin"), &EditorSceneImporterMeshNode::get_skin); - - ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &EditorSceneImporterMeshNode::set_skeleton_path); - ClassDB::bind_method(D_METHOD("get_skeleton_path"), &EditorSceneImporterMeshNode::get_skeleton_path); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "EditorSceneImporterMesh"), "set_mesh", "get_mesh"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); -} - ///////////////////////////////// void EditorScenePostImport::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene"))); @@ -1560,27 +1222,30 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito } void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods) { - EditorSceneImporterMeshNode *src_mesh = Object::cast_to<EditorSceneImporterMeshNode>(p_node); - if (src_mesh != nullptr) { + EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node); + if (src_mesh_node) { //is mesh MeshInstance3D *mesh_node = memnew(MeshInstance3D); - mesh_node->set_transform(src_mesh->get_transform()); - mesh_node->set_skin(src_mesh->get_skin()); - mesh_node->set_skeleton_path(src_mesh->get_skeleton_path()); - - Ref<ArrayMesh> mesh; - if (!src_mesh->get_mesh()->has_mesh()) { - if (p_generate_lods) { - src_mesh->get_mesh()->generate_lods(); + mesh_node->set_name(src_mesh_node->get_name()); + mesh_node->set_transform(src_mesh_node->get_transform()); + mesh_node->set_skin(src_mesh_node->get_skin()); + mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path()); + if (src_mesh_node->get_mesh().is_valid()) { + Ref<ArrayMesh> mesh; + if (!src_mesh_node->get_mesh()->has_mesh()) { + //do mesh processing + if (p_generate_lods) { + src_mesh_node->get_mesh()->generate_lods(); + } + } + mesh = src_mesh_node->get_mesh()->get_mesh(); + if (mesh.is_valid()) { + mesh_node->set_mesh(mesh); + for (int i = 0; i < mesh->get_surface_count(); i++) { + mesh_node->set_surface_material(i, src_mesh_node->get_surface_material(i)); + } } - //do mesh processing - } - mesh = src_mesh->get_mesh()->get_mesh(); - mesh_node->set_mesh(mesh); - for (int i = 0; i < mesh->get_surface_count(); i++) { - mesh_node->set_surface_material(i, src_mesh->get_surface_material(i)); } - p_node->replace_by(mesh_node); memdelete(p_node); p_node = mesh_node; @@ -1803,7 +1468,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p if (!ret_used_cache) { // Cache was not used, add the generated entry to the current cache - if (cache_data.empty()) { + if (cache_data.is_empty()) { cache_data.resize(4 + ret_cache_size); int *data = (int *)cache_data.ptrw(); data[0] = 1; diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index aef6c0ac50..5b70f5bd81 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -90,92 +90,6 @@ public: EditorScenePostImport(); }; -// The following classes are used by importers instead of ArrayMesh and MeshInstance3D -// so the data is not reginstered (hence, quality loss), importing happens faster and -// its easier to modify before saving - -class EditorSceneImporterMesh : public Resource { - GDCLASS(EditorSceneImporterMesh, Resource) - - struct Surface { - Mesh::PrimitiveType primitive; - Array arrays; - struct BlendShape { - Array arrays; - }; - Vector<BlendShape> blend_shape_data; - struct LOD { - Vector<int> indices; - float distance; - }; - Vector<LOD> lods; - Ref<Material> material; - String name; - }; - Vector<Surface> surfaces; - Vector<String> blend_shapes; - Mesh::BlendShapeMode blend_shape_mode = Mesh::BLEND_SHAPE_MODE_NORMALIZED; - - Ref<ArrayMesh> mesh; - -protected: - void _set_data(const Dictionary &p_data); - Dictionary _get_data() const; - - static void _bind_methods(); - -public: - void add_blend_shape(const String &p_name); - int get_blend_shape_count() const; - String get_blend_shape_name(int p_blend_shape) const; - - void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String()); - int get_surface_count() const; - - void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode); - Mesh::BlendShapeMode get_blend_shape_mode() const; - - Mesh::PrimitiveType get_surface_primitive_type(int p_surface); - String get_surface_name(int p_surface) const; - Array get_surface_arrays(int p_surface) const; - Array get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const; - int get_surface_lod_count(int p_surface) const; - Vector<int> get_surface_lod_indices(int p_surface, int p_lod) const; - float get_surface_lod_size(int p_surface, int p_lod) const; - Ref<Material> get_surface_material(int p_surface) const; - - void generate_lods(); - - bool has_mesh() const; - Ref<ArrayMesh> get_mesh(); - void clear(); -}; - -class EditorSceneImporterMeshNode : public Node3D { - GDCLASS(EditorSceneImporterMeshNode, Node3D) - - Ref<EditorSceneImporterMesh> mesh; - Ref<Skin> skin; - NodePath skeleton_path; - Vector<Ref<Material>> surface_materials; - -protected: - static void _bind_methods(); - -public: - void set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh); - Ref<EditorSceneImporterMesh> get_mesh() const; - - void set_skin(const Ref<Skin> &p_skin); - Ref<Skin> get_skin() const; - - void set_surface_material(int p_idx, const Ref<Material> &p_material); - Ref<Material> get_surface_material(int p_idx) const; - - void set_skeleton_path(const NodePath &p_path); - NodePath get_skeleton_path() const; -}; - class ResourceImporterScene : public ResourceImporter { GDCLASS(ResourceImporterScene, ResourceImporter); diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index c8dae53722..0bffc4a2d0 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -82,7 +82,7 @@ void ResourceImporterTexture::update_imports() { MutexLock lock(mutex); Vector<String> to_reimport; { - if (make_flags.empty()) { + if (make_flags.is_empty()) { return; } diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp new file mode 100644 index 0000000000..d7c3b60d5a --- /dev/null +++ b/editor/import/scene_importer_mesh.cpp @@ -0,0 +1,326 @@ +/*************************************************************************/ +/* scene_importer_mesh.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "scene_importer_mesh.h" + +#include "scene/resources/surface_tool.h" + +void EditorSceneImporterMesh::add_blend_shape(const String &p_name) { + ERR_FAIL_COND(surfaces.size() > 0); + blend_shapes.push_back(p_name); +} + +int EditorSceneImporterMesh::get_blend_shape_count() const { + return blend_shapes.size(); +} + +String EditorSceneImporterMesh::get_blend_shape_name(int p_blend_shape) const { + ERR_FAIL_INDEX_V(p_blend_shape, blend_shapes.size(), String()); + return blend_shapes[p_blend_shape]; +} + +void EditorSceneImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) { + blend_shape_mode = p_blend_shape_mode; +} + +Mesh::BlendShapeMode EditorSceneImporterMesh::get_blend_shape_mode() const { + return blend_shape_mode; +} + +void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name) { + ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size()); + ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX); + Surface s; + s.primitive = p_primitive; + s.arrays = p_arrays; + s.name = p_name; + + Vector<Vector3> vertex_array = p_arrays[Mesh::ARRAY_VERTEX]; + int vertex_count = vertex_array.size(); + ERR_FAIL_COND(vertex_count == 0); + + for (int i = 0; i < blend_shapes.size(); i++) { + Array bsdata = p_blend_shapes[i]; + ERR_FAIL_COND(bsdata.size() != Mesh::ARRAY_MAX); + Vector<Vector3> vertex_data = bsdata[Mesh::ARRAY_VERTEX]; + ERR_FAIL_COND(vertex_data.size() != vertex_count); + Surface::BlendShape bs; + bs.arrays = bsdata; + s.blend_shape_data.push_back(bs); + } + + List<Variant> lods; + p_lods.get_key_list(&lods); + for (List<Variant>::Element *E = lods.front(); E; E = E->next()) { + ERR_CONTINUE(!E->get().is_num()); + Surface::LOD lod; + lod.distance = E->get(); + lod.indices = p_lods[E->get()]; + ERR_CONTINUE(lod.indices.size() == 0); + s.lods.push_back(lod); + } + + s.material = p_material; + + surfaces.push_back(s); + mesh.unref(); +} + +int EditorSceneImporterMesh::get_surface_count() const { + return surfaces.size(); +} + +Mesh::PrimitiveType EditorSceneImporterMesh::get_surface_primitive_type(int p_surface) { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Mesh::PRIMITIVE_MAX); + return surfaces[p_surface].primitive; +} +Array EditorSceneImporterMesh::get_surface_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); + return surfaces[p_surface].arrays; +} +String EditorSceneImporterMesh::get_surface_name(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), String()); + return surfaces[p_surface].name; +} +Array EditorSceneImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); + ERR_FAIL_INDEX_V(p_blend_shape, surfaces[p_surface].blend_shape_data.size(), Array()); + return surfaces[p_surface].blend_shape_data[p_blend_shape].arrays; +} +int EditorSceneImporterMesh::get_surface_lod_count(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); + return surfaces[p_surface].lods.size(); +} +Vector<int> EditorSceneImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Vector<int>()); + ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), Vector<int>()); + + return surfaces[p_surface].lods[p_lod].indices; +} + +float EditorSceneImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); + ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), 0); + return surfaces[p_surface].lods[p_lod].distance; +} + +Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Ref<Material>()); + return surfaces[p_surface].material; +} + +void EditorSceneImporterMesh::generate_lods() { + if (!SurfaceTool::simplify_func) { + return; + } + + for (int i = 0; i < surfaces.size(); i++) { + if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) { + continue; + } + + surfaces.write[i].lods.clear(); + Vector<Vector3> vertices = surfaces[i].arrays[RS::ARRAY_VERTEX]; + Vector<int> indices = surfaces[i].arrays[RS::ARRAY_INDEX]; + if (indices.size() == 0) { + continue; //no lods if no indices + } + uint32_t vertex_count = vertices.size(); + const Vector3 *vertices_ptr = vertices.ptr(); + + int min_indices = 10; + int index_target = indices.size() / 2; + print_line("total: " + itos(indices.size())); + while (index_target > min_indices) { + float error; + Vector<int> new_indices; + new_indices.resize(indices.size()); + size_t new_len = SurfaceTool::simplify_func((unsigned int *)new_indices.ptrw(), (const unsigned int *)indices.ptr(), indices.size(), (const float *)vertices_ptr, vertex_count, sizeof(Vector3), index_target, 1e20, &error); + print_line("shoot for " + itos(index_target) + ", got " + itos(new_len) + " distance " + rtos(error)); + if ((int)new_len > (index_target * 120 / 100)) { + break; // 20 percent tolerance + } + new_indices.resize(new_len); + Surface::LOD lod; + lod.distance = error; + lod.indices = new_indices; + surfaces.write[i].lods.push_back(lod); + index_target /= 2; + } + } +} + +bool EditorSceneImporterMesh::has_mesh() const { + return mesh.is_valid(); +} + +Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() { + ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>()); + + if (mesh.is_null()) { + mesh.instance(); + for (int i = 0; i < blend_shapes.size(); i++) { + mesh->add_blend_shape(blend_shapes[i]); + } + mesh->set_blend_shape_mode(blend_shape_mode); + for (int i = 0; i < surfaces.size(); i++) { + Array bs_data; + if (surfaces[i].blend_shape_data.size()) { + for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) { + bs_data.push_back(surfaces[i].blend_shape_data[j].arrays); + } + } + Dictionary lods; + if (surfaces[i].lods.size()) { + for (int j = 0; j < surfaces[i].lods.size(); j++) { + lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices; + } + } + + mesh->add_surface_from_arrays(surfaces[i].primitive, surfaces[i].arrays, bs_data, lods); + if (surfaces[i].material.is_valid()) { + mesh->surface_set_material(mesh->get_surface_count() - 1, surfaces[i].material); + } + if (surfaces[i].name != String()) { + mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name); + } + } + } + + return mesh; +} + +void EditorSceneImporterMesh::clear() { + surfaces.clear(); + blend_shapes.clear(); + mesh.unref(); +} + +void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) { + clear(); + if (p_data.has("blend_shape_names")) { + blend_shapes = p_data["blend_shape_names"]; + } + if (p_data.has("surfaces")) { + Array surface_arr = p_data["surfaces"]; + for (int i = 0; i < surface_arr.size(); i++) { + Dictionary s = surface_arr[i]; + ERR_CONTINUE(!s.has("primitive")); + ERR_CONTINUE(!s.has("arrays")); + Mesh::PrimitiveType prim = Mesh::PrimitiveType(int(s["primitive"])); + ERR_CONTINUE(prim >= Mesh::PRIMITIVE_MAX); + Array arr = s["arrays"]; + Dictionary lods; + String name; + if (s.has("name")) { + name = s["name"]; + } + if (s.has("lods")) { + lods = s["lods"]; + } + Array blend_shapes; + if (s.has("blend_shapes")) { + blend_shapes = s["blend_shapes"]; + } + Ref<Material> material; + if (s.has("material")) { + material = s["material"]; + } + add_surface(prim, arr, blend_shapes, lods, material, name); + } + } +} +Dictionary EditorSceneImporterMesh::_get_data() const { + Dictionary data; + if (blend_shapes.size()) { + data["blend_shape_names"] = blend_shapes; + } + Array surface_arr; + for (int i = 0; i < surfaces.size(); i++) { + Dictionary d; + d["primitive"] = surfaces[i].primitive; + d["arrays"] = surfaces[i].arrays; + if (surfaces[i].blend_shape_data.size()) { + Array bs_data; + for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) { + bs_data.push_back(surfaces[i].blend_shape_data[j].arrays); + } + d["blend_shapes"] = bs_data; + } + if (surfaces[i].lods.size()) { + Dictionary lods; + for (int j = 0; j < surfaces[i].lods.size(); j++) { + lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices; + } + d["lods"] = lods; + } + + if (surfaces[i].material.is_valid()) { + d["material"] = surfaces[i].material; + } + + if (surfaces[i].name != String()) { + d["name"] = surfaces[i].name; + } + + surface_arr.push_back(d); + } + data["surfaces"] = surface_arr; + return data; +} + +void EditorSceneImporterMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape); + ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count); + ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &EditorSceneImporterMesh::get_blend_shape_name); + + ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode); + ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode); + + ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String())); + + ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count); + ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type); + ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &EditorSceneImporterMesh::get_surface_name); + ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &EditorSceneImporterMesh::get_surface_arrays); + ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &EditorSceneImporterMesh::get_surface_blend_shape_arrays); + ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &EditorSceneImporterMesh::get_surface_lod_count); + ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_size); + ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_indices); + ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &EditorSceneImporterMesh::get_surface_material); + + ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMesh::get_mesh); + ClassDB::bind_method(D_METHOD("clear"), &EditorSceneImporterMesh::clear); + + ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data"); +} diff --git a/editor/import/scene_importer_mesh.h b/editor/import/scene_importer_mesh.h new file mode 100644 index 0000000000..7efe2f2ffb --- /dev/null +++ b/editor/import/scene_importer_mesh.h @@ -0,0 +1,96 @@ +/*************************************************************************/ +/* scene_importer_mesh.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 EDITOR_SCENE_IMPORTER_MESH_H +#define EDITOR_SCENE_IMPORTER_MESH_H + +#include "core/io/resource.h" +#include "scene/resources/mesh.h" +// The following classes are used by importers instead of ArrayMesh and MeshInstance3D +// so the data is not registered (hence, quality loss), importing happens faster and +// its easier to modify before saving + +class EditorSceneImporterMesh : public Resource { + GDCLASS(EditorSceneImporterMesh, Resource) + + struct Surface { + Mesh::PrimitiveType primitive; + Array arrays; + struct BlendShape { + Array arrays; + }; + Vector<BlendShape> blend_shape_data; + struct LOD { + Vector<int> indices; + float distance; + }; + Vector<LOD> lods; + Ref<Material> material; + String name; + }; + Vector<Surface> surfaces; + Vector<String> blend_shapes; + Mesh::BlendShapeMode blend_shape_mode = Mesh::BLEND_SHAPE_MODE_NORMALIZED; + + Ref<ArrayMesh> mesh; + +protected: + void _set_data(const Dictionary &p_data); + Dictionary _get_data() const; + + static void _bind_methods(); + +public: + void add_blend_shape(const String &p_name); + int get_blend_shape_count() const; + String get_blend_shape_name(int p_blend_shape) const; + + void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String()); + int get_surface_count() const; + + void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode); + Mesh::BlendShapeMode get_blend_shape_mode() const; + + Mesh::PrimitiveType get_surface_primitive_type(int p_surface); + String get_surface_name(int p_surface) const; + Array get_surface_arrays(int p_surface) const; + Array get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const; + int get_surface_lod_count(int p_surface) const; + Vector<int> get_surface_lod_indices(int p_surface, int p_lod) const; + float get_surface_lod_size(int p_surface, int p_lod) const; + Ref<Material> get_surface_material(int p_surface) const; + + void generate_lods(); + + bool has_mesh() const; + Ref<ArrayMesh> get_mesh(); + void clear(); +}; +#endif // EDITOR_SCENE_IMPORTER_MESH_H diff --git a/editor/import/scene_importer_mesh_node_3d.cpp b/editor/import/scene_importer_mesh_node_3d.cpp new file mode 100644 index 0000000000..53929f77b0 --- /dev/null +++ b/editor/import/scene_importer_mesh_node_3d.cpp @@ -0,0 +1,83 @@ +/*************************************************************************/ +/* scene_importer_mesh_node_3d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "scene_importer_mesh_node_3d.h" + +void EditorSceneImporterMeshNode3D::set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh) { + mesh = p_mesh; +} +Ref<EditorSceneImporterMesh> EditorSceneImporterMeshNode3D::get_mesh() const { + return mesh; +} + +void EditorSceneImporterMeshNode3D::set_skin(const Ref<Skin> &p_skin) { + skin = p_skin; +} +Ref<Skin> EditorSceneImporterMeshNode3D::get_skin() const { + return skin; +} + +void EditorSceneImporterMeshNode3D::set_surface_material(int p_idx, const Ref<Material> &p_material) { + ERR_FAIL_COND(p_idx < 0); + if (p_idx >= surface_materials.size()) { + surface_materials.resize(p_idx + 1); + } + + surface_materials.write[p_idx] = p_material; +} +Ref<Material> EditorSceneImporterMeshNode3D::get_surface_material(int p_idx) const { + ERR_FAIL_COND_V(p_idx < 0, Ref<Material>()); + if (p_idx >= surface_materials.size()) { + return Ref<Material>(); + } + return surface_materials[p_idx]; +} + +void EditorSceneImporterMeshNode3D::set_skeleton_path(const NodePath &p_path) { + skeleton_path = p_path; +} +NodePath EditorSceneImporterMeshNode3D::get_skeleton_path() const { + return skeleton_path; +} + +void EditorSceneImporterMeshNode3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &EditorSceneImporterMeshNode3D::set_mesh); + ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMeshNode3D::get_mesh); + + ClassDB::bind_method(D_METHOD("set_skin", "skin"), &EditorSceneImporterMeshNode3D::set_skin); + ClassDB::bind_method(D_METHOD("get_skin"), &EditorSceneImporterMeshNode3D::get_skin); + + ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &EditorSceneImporterMeshNode3D::set_skeleton_path); + ClassDB::bind_method(D_METHOD("get_skeleton_path"), &EditorSceneImporterMeshNode3D::get_skeleton_path); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "EditorSceneImporterMesh"), "set_mesh", "get_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); +} diff --git a/editor/import/scene_importer_mesh_node_3d.h b/editor/import/scene_importer_mesh_node_3d.h new file mode 100644 index 0000000000..9540e3b886 --- /dev/null +++ b/editor/import/scene_importer_mesh_node_3d.h @@ -0,0 +1,64 @@ +/*************************************************************************/ +/* scene_importer_mesh_node_3d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 EDITOR_SCENE_IMPORTER_MESH_NODE_3D_H +#define EDITOR_SCENE_IMPORTER_MESH_NODE_3D_H + +#include "editor/import/scene_importer_mesh.h" +#include "scene/3d/node_3d.h" +#include "scene/resources/skin.h" + +class EditorSceneImporterMesh; + +class EditorSceneImporterMeshNode3D : public Node3D { + GDCLASS(EditorSceneImporterMeshNode3D, Node3D) + + Ref<EditorSceneImporterMesh> mesh; + Ref<Skin> skin; + NodePath skeleton_path; + Vector<Ref<Material>> surface_materials; + +protected: + static void _bind_methods(); + +public: + void set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh); + Ref<EditorSceneImporterMesh> get_mesh() const; + + void set_skin(const Ref<Skin> &p_skin); + Ref<Skin> get_skin() const; + + void set_surface_material(int p_idx, const Ref<Material> &p_material); + Ref<Material> get_surface_material(int p_idx) const; + + void set_skeleton_path(const NodePath &p_path); + NodePath get_skeleton_path() const; +}; +#endif diff --git a/editor/input_map_editor.cpp b/editor/input_map_editor.cpp index 83adccb752..249b9770b1 100644 --- a/editor/input_map_editor.cpp +++ b/editor/input_map_editor.cpp @@ -921,10 +921,10 @@ InputMapEditor::InputMapEditor() { inputmap_changed = "inputmap_changed"; VBoxContainer *vbc = memnew(VBoxContainer); - vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 0); - vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, 0); - vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 0); - vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, 0); + vbc->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_BEGIN, 0); + vbc->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, 0); + vbc->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 0); + vbc->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, 0); add_child(vbc); HBoxContainer *hbc = memnew(HBoxContainer); @@ -986,10 +986,10 @@ InputMapEditor::InputMapEditor() { l = memnew(Label); l->set_text(TTR("Press a Key...")); - l->set_anchors_and_margins_preset(Control::PRESET_WIDE); + l->set_anchors_and_offsets_preset(Control::PRESET_WIDE); l->set_align(Label::ALIGN_CENTER); - l->set_margin(MARGIN_TOP, 20); - l->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_BEGIN, 30); + l->set_offset(SIDE_TOP, 20); + l->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_BEGIN, 30); press_a_key->add_child(l); press_a_key_label = l; diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index e0ba50fe4f..0620d572e3 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -452,7 +452,7 @@ void InspectorDock::update(Object *p_object) { List<MethodInfo> methods; p_object->get_method_list(&methods); - if (!methods.empty()) { + if (!methods.is_empty()) { bool found = false; List<MethodInfo>::Element *I = methods.front(); int i = 0; diff --git a/editor/node_3d_editor_gizmos.cpp b/editor/node_3d_editor_gizmos.cpp index 45fea20594..71ceff7fee 100644 --- a/editor/node_3d_editor_gizmos.cpp +++ b/editor/node_3d_editor_gizmos.cpp @@ -198,7 +198,7 @@ void EditorNode3DGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, } void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard, const Color &p_modulate) { - if (p_lines.empty()) { + if (p_lines.is_empty()) { return; } @@ -4205,7 +4205,7 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { } } - if (faces.empty()) { + if (faces.is_empty()) { return; } @@ -4521,7 +4521,7 @@ Joint3DGizmoPlugin::Joint3DGizmoPlugin() { } void Joint3DGizmoPlugin::incremental_update_gizmos() { - if (!current_gizmos.empty()) { + if (!current_gizmos.is_empty()) { update_idx++; update_idx = update_idx % current_gizmos.size(); redraw(current_gizmos[update_idx]); diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index a780750633..c63f51c512 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -126,7 +126,7 @@ void PluginConfigDialog::_on_cancelled() { void PluginConfigDialog::_on_required_text_changed(const String &) { int lang_idx = script_option_edit->get_selected(); String ext = ScriptServer::get_language(lang_idx)->get_extension(); - get_ok_button()->set_disabled(script_edit->get_text().get_basename().empty() || script_edit->get_text().get_extension() != ext || name_edit->get_text().empty()); + get_ok_button()->set_disabled(script_edit->get_text().get_basename().is_empty() || script_edit->get_text().get_extension() != ext || name_edit->get_text().is_empty()); } void PluginConfigDialog::_notification(int p_what) { diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 38648b5f0a..d301e8ff7b 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -127,7 +127,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { Ref<AnimationNode> agnode = blend_tree->get_node(E->get()); - node->set_offset(blend_tree->get_node_position(E->get()) * EDSCALE); + node->set_position_offset(blend_tree->get_node_position(E->get()) * EDSCALE); node->set_title(agnode->get_caption()); node->set_name(E->get()); @@ -416,7 +416,7 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request() { } } - if (to_erase.empty()) { + if (to_erase.is_empty()) { return; } @@ -537,7 +537,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano default: { } break; } - if (!track_type_name.empty()) { + if (!track_type_name.is_empty()) { types[track_path].insert(track_type_name); } } diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 7e376eee57..491aab1258 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -116,6 +116,19 @@ void AnimationPlayerEditor::_notification(int p_what) { play_bw_from->set_icon(get_theme_icon("PlayBackwards", "EditorIcons")); autoplay_icon = get_theme_icon("AutoPlay", "EditorIcons"); + reset_icon = get_theme_icon("Reload", "EditorIcons"); + { + Ref<Image> autoplay_img = autoplay_icon->get_data(); + Ref<Image> reset_img = reset_icon->get_data(); + Ref<Image> autoplay_reset_img; + Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height()); + autoplay_reset_img.instance(); + autoplay_reset_img->create(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format()); + autoplay_reset_img->blit_rect(autoplay_img, Rect2(Point2(), icon_size), Point2()); + autoplay_reset_img->blit_rect(reset_img, Rect2(Point2(), icon_size), Point2(icon_size.x, 0)); + autoplay_reset_icon.instance(); + autoplay_reset_icon->create_from_image(autoplay_reset_img); + } stop->set_icon(get_theme_icon("Stop", "EditorIcons")); onion_toggle->set_icon(get_theme_icon("Onion", "EditorIcons")); @@ -667,7 +680,7 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { if (p_state.has("animation")) { String anim = p_state["animation"]; - if (!anim.empty() && player->has_animation(anim)) { + if (!anim.is_empty() && player->has_animation(anim)) { _select_anim_by_name(anim); _animation_edit(); } @@ -817,11 +830,17 @@ void AnimationPlayerEditor::_update_player() { int active_idx = -1; for (List<StringName>::Element *E = animlist.front(); E; E = E->next()) { - if (player->get_autoplay() == E->get()) { - animation->add_icon_item(autoplay_icon, E->get()); - } else { - animation->add_item(E->get()); + Ref<Texture2D> icon; + if (E->get() == player->get_autoplay()) { + if (E->get() == "RESET") { + icon = autoplay_reset_icon; + } else { + icon = autoplay_icon; + } + } else if (E->get() == "RESET") { + icon = reset_icon; } + animation->add_icon_item(icon, E->get()); if (player->get_assigned_animation() == E->get()) { active_idx = animation->get_item_count() - 1; @@ -1375,7 +1394,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { } // Backup current animation state. - AnimatedValuesBackup values_backup = player->backup_animated_values(); + Ref<AnimatedValuesBackup> values_backup = player->backup_animated_values(); float cpos = player->get_current_animation_position(); // Render every past/future step with the capture shader. @@ -1405,7 +1424,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { if (valid) { player->seek(pos, true); get_tree()->flush_transform_notifications(); // Needed for transforms of Node3Ds. - values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D). + values_backup->update_skeletons(); // Needed for Skeletons (2D & 3D). RS::get_singleton()->viewport_set_active(onion.captures[cidx], true); RS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); @@ -1425,7 +1444,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { // (Seeking with update=true wouldn't do the trick because the current value of the properties // may not match their value for the current point in the animation). player->seek(cpos, false); - player->restore_animated_values(values_backup); + values_backup->restore(); // Restore state of main editors. if (Node3DEditor::get_singleton()->is_visible()) { diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 17e554ee0d..ab3feb115f 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -105,6 +105,8 @@ class AnimationPlayerEditor : public VBoxContainer { Label *name_title; UndoRedo *undo_redo; Ref<Texture2D> autoplay_icon; + Ref<Texture2D> reset_icon; + Ref<ImageTexture> autoplay_reset_icon; bool last_active; float timeline_position; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index c59e056f4f..6fa1792c67 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1291,18 +1291,18 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { state_machine_play_pos = memnew(Control); state_machine_draw->add_child(state_machine_play_pos); state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent - state_machine_play_pos->set_anchors_and_margins_preset(PRESET_WIDE); + state_machine_play_pos->set_anchors_and_offsets_preset(PRESET_WIDE); state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw)); v_scroll = memnew(VScrollBar); state_machine_draw->add_child(v_scroll); - v_scroll->set_anchors_and_margins_preset(PRESET_RIGHT_WIDE); + v_scroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE); v_scroll->connect("value_changed", callable_mp(this, &AnimationNodeStateMachineEditor::_scroll_changed)); h_scroll = memnew(HScrollBar); state_machine_draw->add_child(h_scroll); - h_scroll->set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE); - h_scroll->set_margin(MARGIN_RIGHT, -v_scroll->get_size().x * EDSCALE); + h_scroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); + h_scroll->set_offset(SIDE_RIGHT, -v_scroll->get_size().x * EDSCALE); h_scroll->connect("value_changed", callable_mp(this, &AnimationNodeStateMachineEditor::_scroll_changed)); error_panel = memnew(PanelContainer); @@ -1328,7 +1328,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { add_child(name_edit_popup); name_edit = memnew(LineEdit); name_edit_popup->add_child(name_edit); - name_edit->set_anchors_and_margins_preset(PRESET_WIDE); + name_edit->set_anchors_and_offsets_preset(PRESET_WIDE); name_edit->connect("text_entered", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited)); name_edit->connect("focus_exited", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited_focus_out)); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index ba798a7826..6420a28d50 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -87,10 +87,10 @@ void EditorAssetLibraryItem::_bind_methods() { EditorAssetLibraryItem::EditorAssetLibraryItem() { Ref<StyleBoxEmpty> border; border.instance(); - border->set_default_margin(MARGIN_LEFT, 5 * EDSCALE); - border->set_default_margin(MARGIN_RIGHT, 5 * EDSCALE); - border->set_default_margin(MARGIN_BOTTOM, 5 * EDSCALE); - border->set_default_margin(MARGIN_TOP, 5 * EDSCALE); + border->set_default_margin(SIDE_LEFT, 5 * EDSCALE); + border->set_default_margin(SIDE_RIGHT, 5 * EDSCALE); + border->set_default_margin(SIDE_BOTTOM, 5 * EDSCALE); + border->set_default_margin(SIDE_TOP, 5 * EDSCALE); add_theme_style_override("panel", border); HBoxContainer *hb = memnew(HBoxContainer); @@ -702,7 +702,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB } } - if (!image->empty()) { + if (!image->is_empty()) { switch (image_queue[p_queue_id].image_type) { case IMAGE_QUEUE_ICON: @@ -1151,7 +1151,7 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const asset_bottom_page = _make_pages(page, pages, page_len, total_items, result.size()); library_vb->add_child(asset_bottom_page); - if (result.empty()) { + if (result.is_empty()) { if (filter->get_text() != String()) { library_error->set_text( vformat(TTR("No results for \"%s\"."), filter->get_text())); @@ -1188,7 +1188,7 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const } } - if (!result.empty()) { + if (!result.is_empty()) { library_scroll->set_v_scroll(0); } } break; @@ -1400,10 +1400,10 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { Ref<StyleBoxEmpty> border2; border2.instance(); - border2->set_default_margin(MARGIN_LEFT, 15 * EDSCALE); - border2->set_default_margin(MARGIN_RIGHT, 35 * EDSCALE); - border2->set_default_margin(MARGIN_BOTTOM, 15 * EDSCALE); - border2->set_default_margin(MARGIN_TOP, 15 * EDSCALE); + border2->set_default_margin(SIDE_LEFT, 15 * EDSCALE); + border2->set_default_margin(SIDE_RIGHT, 35 * EDSCALE); + border2->set_default_margin(SIDE_BOTTOM, 15 * EDSCALE); + border2->set_default_margin(SIDE_TOP, 15 * EDSCALE); PanelContainer *library_vb_border = memnew(PanelContainer); library_scroll->add_child(library_vb_border); @@ -1493,7 +1493,7 @@ AssetLibraryEditorPlugin::AssetLibraryEditorPlugin(EditorNode *p_node) { addon_library = memnew(EditorAssetLibrary); addon_library->set_v_size_flags(Control::SIZE_EXPAND_FILL); editor->get_viewport()->add_child(addon_library); - addon_library->set_anchors_and_margins_preset(Control::PRESET_WIDE); + addon_library->set_anchors_and_offsets_preset(Control::PRESET_WIDE); addon_library->hide(); } diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp index 998916349c..5041cf9f32 100644 --- a/editor/plugins/audio_stream_editor_plugin.cpp +++ b/editor/plugins/audio_stream_editor_plugin.cpp @@ -202,7 +202,7 @@ AudioStreamEditor::AudioStreamEditor() { add_child(_player); VBoxContainer *vbox = memnew(VBoxContainer); - vbox->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_MINSIZE, 0); + vbox->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_MINSIZE, 0); add_child(vbox); _preview = memnew(ColorRect); @@ -211,7 +211,7 @@ AudioStreamEditor::AudioStreamEditor() { vbox->add_child(_preview); _indicator = memnew(Control); - _indicator->set_anchors_and_margins_preset(PRESET_WIDE); + _indicator->set_anchors_and_offsets_preset(PRESET_WIDE); _indicator->connect("draw", callable_mp(this, &AudioStreamEditor::_draw_indicator)); _indicator->connect("gui_input", callable_mp(this, &AudioStreamEditor::_on_input_indicator)); _preview->add_child(_indicator); diff --git a/editor/plugins/camera_3d_editor_plugin.cpp b/editor/plugins/camera_3d_editor_plugin.cpp index 48f9f208a5..9a5cfd35cd 100644 --- a/editor/plugins/camera_3d_editor_plugin.cpp +++ b/editor/plugins/camera_3d_editor_plugin.cpp @@ -69,12 +69,12 @@ Camera3DEditor::Camera3DEditor() { preview->set_text(TTR("Preview")); preview->set_toggle_mode(true); - preview->set_anchor(MARGIN_LEFT, Control::ANCHOR_END); - preview->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END); - preview->set_margin(MARGIN_LEFT, -60); - preview->set_margin(MARGIN_RIGHT, 0); - preview->set_margin(MARGIN_TOP, 0); - preview->set_margin(MARGIN_BOTTOM, 10); + preview->set_anchor(SIDE_LEFT, Control::ANCHOR_END); + preview->set_anchor(SIDE_RIGHT, Control::ANCHOR_END); + preview->set_offset(SIDE_LEFT, -60); + preview->set_offset(SIDE_RIGHT, 0); + preview->set_offset(SIDE_TOP, 0); + preview->set_offset(SIDE_BOTTOM, 10); preview->connect("pressed", callable_mp(this, &Camera3DEditor::_pressed)); } @@ -100,12 +100,12 @@ Camera3DEditorPlugin::Camera3DEditorPlugin(EditorNode *p_node) { /* camera_editor = memnew( CameraEditor ); editor->get_viewport()->add_child(camera_editor); - camera_editor->set_anchor(MARGIN_LEFT,Control::ANCHOR_END); - camera_editor->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END); - camera_editor->set_margin(MARGIN_LEFT,60); - camera_editor->set_margin(MARGIN_RIGHT,0); - camera_editor->set_margin(MARGIN_TOP,0); - camera_editor->set_margin(MARGIN_BOTTOM,10); + camera_editor->set_anchor(SIDE_LEFT,Control::ANCHOR_END); + camera_editor->set_anchor(SIDE_RIGHT,Control::ANCHOR_END); + camera_editor->set_offset(SIDE_LEFT,60); + camera_editor->set_offset(SIDE_RIGHT,0); + camera_editor->set_offset(SIDE_TOP,0); + camera_editor->set_offset(SIDE_BOTTOM,10); camera_editor->hide(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 2a4cc691c3..ecd0a20c1a 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -366,8 +366,8 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig // Self anchors if ((is_snap_active && snap_node_anchors && (p_modes & SNAP_NODE_ANCHORS)) || (p_forced_modes & SNAP_NODE_ANCHORS)) { if (const Control *c = Object::cast_to<Control>(p_self_canvas_item)) { - Point2 begin = p_self_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_LEFT), c->get_anchor(MARGIN_TOP)))); - Point2 end = p_self_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_RIGHT), c->get_anchor(MARGIN_BOTTOM)))); + Point2 begin = p_self_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(SIDE_LEFT), c->get_anchor(SIDE_TOP)))); + Point2 end = p_self_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(SIDE_RIGHT), c->get_anchor(SIDE_BOTTOM)))); _snap_if_closer_point(p_target, output, snap_target, begin, SNAP_TARGET_SELF_ANCHORS, rotation); _snap_if_closer_point(p_target, output, snap_target, end, SNAP_TARGET_SELF_ANCHORS, rotation); } @@ -518,7 +518,7 @@ void CanvasItemEditor::_keying_changed() { } Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_list) { - ERR_FAIL_COND_V(p_list.empty(), Rect2()); + ERR_FAIL_COND_V(p_list.is_empty(), Rect2()); // Handles the first element CanvasItem *canvas_item = p_list.front()->get(); @@ -1147,7 +1147,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve if (dragged_guide_index >= 0) { vguides.remove(dragged_guide_index); undo_redo->create_action(TTR("Remove Vertical Guide")); - if (vguides.empty()) { + if (vguides.is_empty()) { undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "remove_meta", "_edit_vertical_guides_"); } else { undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); @@ -1180,7 +1180,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve if (dragged_guide_index >= 0) { hguides.remove(dragged_guide_index); undo_redo->create_action(TTR("Remove Horizontal Guide")); - if (hguides.empty()) { + if (hguides.is_empty()) { undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "remove_meta", "_edit_horizontal_guides_"); } else { undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); @@ -1628,10 +1628,10 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { Control *control = Object::cast_to<Control>(selection[0]); if (control && _is_node_movable(control)) { Vector2 anchor_pos[4]; - anchor_pos[0] = Vector2(control->get_anchor(MARGIN_LEFT), control->get_anchor(MARGIN_TOP)); - anchor_pos[1] = Vector2(control->get_anchor(MARGIN_RIGHT), control->get_anchor(MARGIN_TOP)); - anchor_pos[2] = Vector2(control->get_anchor(MARGIN_RIGHT), control->get_anchor(MARGIN_BOTTOM)); - anchor_pos[3] = Vector2(control->get_anchor(MARGIN_LEFT), control->get_anchor(MARGIN_BOTTOM)); + anchor_pos[0] = Vector2(control->get_anchor(SIDE_LEFT), control->get_anchor(SIDE_TOP)); + anchor_pos[1] = Vector2(control->get_anchor(SIDE_RIGHT), control->get_anchor(SIDE_TOP)); + anchor_pos[2] = Vector2(control->get_anchor(SIDE_RIGHT), control->get_anchor(SIDE_BOTTOM)); + anchor_pos[3] = Vector2(control->get_anchor(SIDE_LEFT), control->get_anchor(SIDE_BOTTOM)); Rect2 anchor_rects[4]; for (int i = 0; i < 4; i++) { @@ -1681,8 +1681,8 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { Transform2D xform = control->get_global_transform_with_canvas().affine_inverse(); Point2 previous_anchor; - previous_anchor.x = (drag_type == DRAG_ANCHOR_TOP_LEFT || drag_type == DRAG_ANCHOR_BOTTOM_LEFT) ? control->get_anchor(MARGIN_LEFT) : control->get_anchor(MARGIN_RIGHT); - previous_anchor.y = (drag_type == DRAG_ANCHOR_TOP_LEFT || drag_type == DRAG_ANCHOR_TOP_RIGHT) ? control->get_anchor(MARGIN_TOP) : control->get_anchor(MARGIN_BOTTOM); + previous_anchor.x = (drag_type == DRAG_ANCHOR_TOP_LEFT || drag_type == DRAG_ANCHOR_BOTTOM_LEFT) ? control->get_anchor(SIDE_LEFT) : control->get_anchor(SIDE_RIGHT); + previous_anchor.y = (drag_type == DRAG_ANCHOR_TOP_LEFT || drag_type == DRAG_ANCHOR_TOP_RIGHT) ? control->get_anchor(SIDE_TOP) : control->get_anchor(SIDE_BOTTOM); previous_anchor = xform.affine_inverse().xform(_anchor_to_position(control, previous_anchor)); Vector2 new_anchor = xform.xform(snap_point(previous_anchor + (drag_to - drag_from), SNAP_GRID | SNAP_OTHER_NODES, SNAP_NODE_PARENT | SNAP_NODE_SIDES | SNAP_NODE_CENTER, control)); @@ -1695,44 +1695,44 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { switch (drag_type) { case DRAG_ANCHOR_TOP_LEFT: if (!use_single_axis || !use_y) { - control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false); + control->set_anchor(SIDE_LEFT, new_anchor.x, false, false); } if (!use_single_axis || use_y) { - control->set_anchor(MARGIN_TOP, new_anchor.y, false, false); + control->set_anchor(SIDE_TOP, new_anchor.y, false, false); } break; case DRAG_ANCHOR_TOP_RIGHT: if (!use_single_axis || !use_y) { - control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false); + control->set_anchor(SIDE_RIGHT, new_anchor.x, false, false); } if (!use_single_axis || use_y) { - control->set_anchor(MARGIN_TOP, new_anchor.y, false, false); + control->set_anchor(SIDE_TOP, new_anchor.y, false, false); } break; case DRAG_ANCHOR_BOTTOM_RIGHT: if (!use_single_axis || !use_y) { - control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false); + control->set_anchor(SIDE_RIGHT, new_anchor.x, false, false); } if (!use_single_axis || use_y) { - control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false); + control->set_anchor(SIDE_BOTTOM, new_anchor.y, false, false); } break; case DRAG_ANCHOR_BOTTOM_LEFT: if (!use_single_axis || !use_y) { - control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false); + control->set_anchor(SIDE_LEFT, new_anchor.x, false, false); } if (!use_single_axis || use_y) { - control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false); + control->set_anchor(SIDE_BOTTOM, new_anchor.y, false, false); } break; case DRAG_ANCHOR_ALL: if (!use_single_axis || !use_y) { - control->set_anchor(MARGIN_LEFT, new_anchor.x, false, true); - control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, true); + control->set_anchor(SIDE_LEFT, new_anchor.x, false, true); + control->set_anchor(SIDE_RIGHT, new_anchor.x, false, true); } if (!use_single_axis || use_y) { - control->set_anchor(MARGIN_TOP, new_anchor.y, false, true); - control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, true); + control->set_anchor(SIDE_TOP, new_anchor.y, false, true); + control->set_anchor(SIDE_BOTTOM, new_anchor.y, false, true); } break; default: @@ -2400,7 +2400,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { _select_click_on_item(item, click, b->get_shift()); return true; - } else if (!selection_results.empty()) { + } else if (!selection_results.is_empty()) { // Sorts items according the their z-index selection_results.sort(); @@ -2463,13 +2463,13 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { // Retrieve the bones Vector<_SelectResult> selection = Vector<_SelectResult>(); _get_bones_at_pos(click, selection); - if (!selection.empty()) { + if (!selection.is_empty()) { canvas_item = selection[0].item; } else { // Retrieve the canvas items selection = Vector<_SelectResult>(); _get_canvas_items_at_pos(click, selection); - if (!selection.empty()) { + if (!selection.is_empty()) { canvas_item = selection[0].item; } } @@ -2780,37 +2780,37 @@ void CanvasItemEditor::_update_cursor() { viewport->set_default_cursor_shape(c); } -void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Margin p_side) { +void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Side p_side) { Color color = get_theme_color("font_color", "Editor"); color.a = 0.8; Ref<Font> font = get_theme_font("font", "Label"); int font_size = get_theme_font_size("font_size", "Label"); Size2 text_size = font->get_string_size(p_string, font_size); switch (p_side) { - case MARGIN_LEFT: + case SIDE_LEFT: p_position += Vector2(-text_size.x - 5, text_size.y / 2); break; - case MARGIN_TOP: + case SIDE_TOP: p_position += Vector2(-text_size.x / 2, -5); break; - case MARGIN_RIGHT: + case SIDE_RIGHT: p_position += Vector2(5, text_size.y / 2); break; - case MARGIN_BOTTOM: + case SIDE_BOTTOM: p_position += Vector2(-text_size.x / 2, text_size.y + 5); break; } viewport->draw_string(font, p_position, p_string, HALIGN_LEFT, -1, font_size, color); } -void CanvasItemEditor::_draw_margin_at_position(int p_value, Point2 p_position, Margin p_side) { +void CanvasItemEditor::_draw_margin_at_position(int p_value, Point2 p_position, Side p_side) { String str = TS->format_number(vformat("%d " + TTR("px"), p_value)); if (p_value != 0) { _draw_text_at_position(p_position, str, p_side); } } -void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_position, Margin p_side) { +void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_position, Side p_side) { String str = TS->format_number(vformat("%.1f ", p_value * 100.0)) + TS->percent_sign(); if (p_value != 0) { _draw_text_at_position(p_position, str, p_side); @@ -2935,7 +2935,7 @@ void CanvasItemEditor::_draw_rulers() { // Draw top ruler viewport->draw_rect(Rect2(Point2(RULER_WIDTH, 0), Size2(viewport->get_size().x, RULER_WIDTH)), bg_color); for (int i = Math::ceil(first.x); i < last.x; i++) { - Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)); + Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).round(); if (i % (major_subdivision * minor_subdivision) == 0) { viewport->draw_line(Point2(position.x, 0), Point2(position.x, RULER_WIDTH), graduation_color, Math::round(EDSCALE)); float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).x; @@ -2952,7 +2952,7 @@ void CanvasItemEditor::_draw_rulers() { // Draw left ruler viewport->draw_rect(Rect2(Point2(0, RULER_WIDTH), Size2(RULER_WIDTH, viewport->get_size().y)), bg_color); for (int i = Math::ceil(first.y); i < last.y; i++) { - Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)); + Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).round(); if (i % (major_subdivision * minor_subdivision) == 0) { viewport->draw_line(Point2(0, position.y), Point2(RULER_WIDTH, position.y), graduation_color, Math::round(EDSCALE)); float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).y; @@ -3185,10 +3185,10 @@ void CanvasItemEditor::_draw_control_anchors(Control *control) { if (tool == TOOL_SELECT && !Object::cast_to<Container>(control->get_parent())) { // Compute the anchors float anchors_values[4]; - anchors_values[0] = control->get_anchor(MARGIN_LEFT); - anchors_values[1] = control->get_anchor(MARGIN_TOP); - anchors_values[2] = control->get_anchor(MARGIN_RIGHT); - anchors_values[3] = control->get_anchor(MARGIN_BOTTOM); + anchors_values[0] = control->get_anchor(SIDE_LEFT); + anchors_values[1] = control->get_anchor(SIDE_TOP); + anchors_values[2] = control->get_anchor(SIDE_RIGHT); + anchors_values[3] = control->get_anchor(SIDE_BOTTOM); Vector2 anchors_pos[4]; for (int i = 0; i < 4; i++) { @@ -3224,10 +3224,10 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { // Compute the anchors float anchors_values[4]; - anchors_values[0] = control->get_anchor(MARGIN_LEFT); - anchors_values[1] = control->get_anchor(MARGIN_TOP); - anchors_values[2] = control->get_anchor(MARGIN_RIGHT); - anchors_values[3] = control->get_anchor(MARGIN_BOTTOM); + anchors_values[0] = control->get_anchor(SIDE_LEFT); + anchors_values[1] = control->get_anchor(SIDE_TOP); + anchors_values[2] = control->get_anchor(SIDE_RIGHT); + anchors_values[3] = control->get_anchor(SIDE_BOTTOM); Vector2 anchors[4]; Vector2 anchors_pos[4]; @@ -3280,19 +3280,19 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { float percent_val; percent_val = anchors_values[(dragged_anchor + 2) % 4] - anchors_values[dragged_anchor]; percent_val = (dragged_anchor >= 2) ? -percent_val : percent_val; - _draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 1) % 4]) / 2, (Margin)((dragged_anchor + 1) % 4)); + _draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 1) % 4]) / 2, (Side)((dragged_anchor + 1) % 4)); percent_val = anchors_values[(dragged_anchor + 3) % 4] - anchors_values[(dragged_anchor + 1) % 4]; percent_val = ((dragged_anchor + 1) % 4 >= 2) ? -percent_val : percent_val; - _draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 3) % 4]) / 2, (Margin)(dragged_anchor)); + _draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 3) % 4]) / 2, (Side)(dragged_anchor)); percent_val = anchors_values[(dragged_anchor + 1) % 4]; percent_val = ((dragged_anchor + 1) % 4 >= 2) ? ANCHOR_END - percent_val : percent_val; - _draw_percentage_at_position(percent_val, (line_starts[dragged_anchor] + anchors_pos[dragged_anchor]) / 2, (Margin)(dragged_anchor)); + _draw_percentage_at_position(percent_val, (line_starts[dragged_anchor] + anchors_pos[dragged_anchor]) / 2, (Side)(dragged_anchor)); percent_val = anchors_values[dragged_anchor]; percent_val = (dragged_anchor >= 2) ? ANCHOR_END - percent_val : percent_val; - _draw_percentage_at_position(percent_val, (line_ends[(dragged_anchor + 1) % 4] + anchors_pos[dragged_anchor]) / 2, (Margin)((dragged_anchor + 1) % 4)); + _draw_percentage_at_position(percent_val, (line_ends[(dragged_anchor + 1) % 4] + anchors_pos[dragged_anchor]) / 2, (Side)((dragged_anchor + 1) % 4)); } // Draw the margin values and the node width/height when dragging control side @@ -3302,22 +3302,22 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { Rect2 parent_rect = control->get_parent_anchorable_rect(); - node_pos_in_parent[0] = control->get_anchor(MARGIN_LEFT) * parent_rect.size.width + control->get_margin(MARGIN_LEFT) + parent_rect.position.x; - node_pos_in_parent[1] = control->get_anchor(MARGIN_TOP) * parent_rect.size.height + control->get_margin(MARGIN_TOP) + parent_rect.position.y; - node_pos_in_parent[2] = control->get_anchor(MARGIN_RIGHT) * parent_rect.size.width + control->get_margin(MARGIN_RIGHT) + parent_rect.position.x; - node_pos_in_parent[3] = control->get_anchor(MARGIN_BOTTOM) * parent_rect.size.height + control->get_margin(MARGIN_BOTTOM) + parent_rect.position.y; + node_pos_in_parent[0] = control->get_anchor(SIDE_LEFT) * parent_rect.size.width + control->get_offset(SIDE_LEFT) + parent_rect.position.x; + node_pos_in_parent[1] = control->get_anchor(SIDE_TOP) * parent_rect.size.height + control->get_offset(SIDE_TOP) + parent_rect.position.y; + node_pos_in_parent[2] = control->get_anchor(SIDE_RIGHT) * parent_rect.size.width + control->get_offset(SIDE_RIGHT) + parent_rect.position.x; + node_pos_in_parent[3] = control->get_anchor(SIDE_BOTTOM) * parent_rect.size.height + control->get_offset(SIDE_BOTTOM) + parent_rect.position.y; Point2 start, end; switch (drag_type) { case DRAG_LEFT: case DRAG_TOP_LEFT: case DRAG_BOTTOM_LEFT: - _draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM); + _draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), SIDE_BOTTOM); [[fallthrough]]; case DRAG_MOVE: start = Vector2(node_pos_in_parent[0], Math::lerp(node_pos_in_parent[1], node_pos_in_parent[3], ratio)); - end = start - Vector2(control->get_margin(MARGIN_LEFT), 0); - _draw_margin_at_position(control->get_margin(MARGIN_LEFT), parent_transform.xform((start + end) / 2), MARGIN_TOP); + end = start - Vector2(control->get_offset(SIDE_LEFT), 0); + _draw_margin_at_position(control->get_offset(SIDE_LEFT), parent_transform.xform((start + end) / 2), SIDE_TOP); viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, Math::round(EDSCALE)); break; default: @@ -3327,12 +3327,12 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { case DRAG_RIGHT: case DRAG_TOP_RIGHT: case DRAG_BOTTOM_RIGHT: - _draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM); + _draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), SIDE_BOTTOM); [[fallthrough]]; case DRAG_MOVE: start = Vector2(node_pos_in_parent[2], Math::lerp(node_pos_in_parent[3], node_pos_in_parent[1], ratio)); - end = start - Vector2(control->get_margin(MARGIN_RIGHT), 0); - _draw_margin_at_position(control->get_margin(MARGIN_RIGHT), parent_transform.xform((start + end) / 2), MARGIN_BOTTOM); + end = start - Vector2(control->get_offset(SIDE_RIGHT), 0); + _draw_margin_at_position(control->get_offset(SIDE_RIGHT), parent_transform.xform((start + end) / 2), SIDE_BOTTOM); viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, Math::round(EDSCALE)); break; default: @@ -3342,12 +3342,12 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { case DRAG_TOP: case DRAG_TOP_LEFT: case DRAG_TOP_RIGHT: - _draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2)) + Vector2(5, 0), MARGIN_RIGHT); + _draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2)) + Vector2(5, 0), SIDE_RIGHT); [[fallthrough]]; case DRAG_MOVE: start = Vector2(Math::lerp(node_pos_in_parent[0], node_pos_in_parent[2], ratio), node_pos_in_parent[1]); - end = start - Vector2(0, control->get_margin(MARGIN_TOP)); - _draw_margin_at_position(control->get_margin(MARGIN_TOP), parent_transform.xform((start + end) / 2), MARGIN_LEFT); + end = start - Vector2(0, control->get_offset(SIDE_TOP)); + _draw_margin_at_position(control->get_offset(SIDE_TOP), parent_transform.xform((start + end) / 2), SIDE_LEFT); viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, Math::round(EDSCALE)); break; default: @@ -3357,12 +3357,12 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { case DRAG_BOTTOM: case DRAG_BOTTOM_LEFT: case DRAG_BOTTOM_RIGHT: - _draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2) + Vector2(5, 0)), MARGIN_RIGHT); + _draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2) + Vector2(5, 0)), SIDE_RIGHT); [[fallthrough]]; case DRAG_MOVE: start = Vector2(Math::lerp(node_pos_in_parent[2], node_pos_in_parent[0], ratio), node_pos_in_parent[3]); - end = start - Vector2(0, control->get_margin(MARGIN_BOTTOM)); - _draw_margin_at_position(control->get_margin(MARGIN_BOTTOM), parent_transform.xform((start + end) / 2), MARGIN_RIGHT); + end = start - Vector2(0, control->get_offset(SIDE_BOTTOM)); + _draw_margin_at_position(control->get_offset(SIDE_BOTTOM), parent_transform.xform((start + end) / 2), SIDE_RIGHT); viewport->draw_line(parent_transform.xform(start), parent_transform.xform(end), color_base, Math::round(EDSCALE)); break; default: @@ -3916,7 +3916,7 @@ void CanvasItemEditor::_draw_viewport() { bool all_locked = true; bool all_group = true; List<Node *> selection = editor_selection->get_selected_node_list(); - if (selection.empty()) { + if (selection.is_empty()) { all_locked = false; all_group = false; } else { @@ -3935,13 +3935,13 @@ void CanvasItemEditor::_draw_viewport() { } lock_button->set_visible(!all_locked); - lock_button->set_disabled(selection.empty()); + lock_button->set_disabled(selection.is_empty()); unlock_button->set_visible(all_locked); group_button->set_visible(!all_group); - group_button->set_disabled(selection.empty()); + group_button->set_disabled(selection.is_empty()); ungroup_button->set_visible(all_group); - info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); + info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); _draw_grid(); _draw_ruler_tool(); @@ -3956,11 +3956,11 @@ void CanvasItemEditor::_draw_viewport() { RenderingServer::get_singleton()->canvas_item_add_set_transform(ci, Transform2D()); EditorPluginList *over_plugin_list = editor->get_editor_plugins_over(); - if (!over_plugin_list->empty()) { + if (!over_plugin_list->is_empty()) { over_plugin_list->forward_canvas_draw_over_viewport(viewport); } EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over(); - if (!force_over_plugin_list->empty()) { + if (!force_over_plugin_list->is_empty()) { force_over_plugin_list->forward_canvas_force_draw_over_viewport(viewport); } @@ -4019,17 +4019,17 @@ void CanvasItemEditor::_notification(int p_what) { Vector2 pivot; pivot = control->get_pivot_offset(); - anchors[MARGIN_LEFT] = control->get_anchor(MARGIN_LEFT); - anchors[MARGIN_RIGHT] = control->get_anchor(MARGIN_RIGHT); - anchors[MARGIN_TOP] = control->get_anchor(MARGIN_TOP); - anchors[MARGIN_BOTTOM] = control->get_anchor(MARGIN_BOTTOM); + anchors[SIDE_LEFT] = control->get_anchor(SIDE_LEFT); + anchors[SIDE_RIGHT] = control->get_anchor(SIDE_RIGHT); + anchors[SIDE_TOP] = control->get_anchor(SIDE_TOP); + anchors[SIDE_BOTTOM] = control->get_anchor(SIDE_BOTTOM); - if (pivot != se->prev_pivot || anchors[MARGIN_LEFT] != se->prev_anchors[MARGIN_LEFT] || anchors[MARGIN_RIGHT] != se->prev_anchors[MARGIN_RIGHT] || anchors[MARGIN_TOP] != se->prev_anchors[MARGIN_TOP] || anchors[MARGIN_BOTTOM] != se->prev_anchors[MARGIN_BOTTOM]) { + if (pivot != se->prev_pivot || anchors[SIDE_LEFT] != se->prev_anchors[SIDE_LEFT] || anchors[SIDE_RIGHT] != se->prev_anchors[SIDE_RIGHT] || anchors[SIDE_TOP] != se->prev_anchors[SIDE_TOP] || anchors[SIDE_BOTTOM] != se->prev_anchors[SIDE_BOTTOM]) { se->prev_pivot = pivot; - se->prev_anchors[MARGIN_LEFT] = anchors[MARGIN_LEFT]; - se->prev_anchors[MARGIN_RIGHT] = anchors[MARGIN_RIGHT]; - se->prev_anchors[MARGIN_TOP] = anchors[MARGIN_TOP]; - se->prev_anchors[MARGIN_BOTTOM] = anchors[MARGIN_BOTTOM]; + se->prev_anchors[SIDE_LEFT] = anchors[SIDE_LEFT]; + se->prev_anchors[SIDE_RIGHT] = anchors[SIDE_RIGHT]; + se->prev_anchors[SIDE_TOP] = anchors[SIDE_TOP]; + se->prev_anchors[SIDE_BOTTOM] = anchors[SIDE_BOTTOM]; viewport->update(); } nb_control++; @@ -4100,8 +4100,8 @@ void CanvasItemEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { select_sb->set_texture(get_theme_icon("EditorRect2D", "EditorIcons")); for (int i = 0; i < 4; i++) { - select_sb->set_margin_size(Margin(i), 4); - select_sb->set_default_margin(Margin(i), 4); + select_sb->set_margin_size(Side(i), 4); + select_sb->set_default_margin(Side(i), 4); } AnimationPlayerEditor::singleton->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed)); @@ -4158,26 +4158,26 @@ void CanvasItemEditor::_notification(int p_what) { PopupMenu *p = presets_menu->get_popup(); p->clear(); - p->add_icon_item(get_theme_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_AND_MARGINS_PRESET_TOP_LEFT); - p->add_icon_item(get_theme_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT); - p->add_icon_item(get_theme_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT); - p->add_icon_item(get_theme_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT); + p->add_icon_item(get_theme_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT); + p->add_icon_item(get_theme_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT); + p->add_icon_item(get_theme_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT); + p->add_icon_item(get_theme_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT); p->add_separator(); - p->add_icon_item(get_theme_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT); - p->add_icon_item(get_theme_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_AND_MARGINS_PRESET_CENTER_TOP); - p->add_icon_item(get_theme_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT); - p->add_icon_item(get_theme_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM); - p->add_icon_item(get_theme_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_AND_MARGINS_PRESET_CENTER); + p->add_icon_item(get_theme_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT); + p->add_icon_item(get_theme_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP); + p->add_icon_item(get_theme_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT); + p->add_icon_item(get_theme_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM); + p->add_icon_item(get_theme_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_AND_OFFSETS_PRESET_CENTER); p->add_separator(); - p->add_icon_item(get_theme_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE); - p->add_icon_item(get_theme_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_AND_MARGINS_PRESET_TOP_WIDE); - p->add_icon_item(get_theme_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE); - p->add_icon_item(get_theme_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE); - p->add_icon_item(get_theme_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE); - p->add_icon_item(get_theme_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE); + p->add_icon_item(get_theme_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE); + p->add_icon_item(get_theme_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE); + p->add_icon_item(get_theme_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE); + p->add_icon_item(get_theme_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE); + p->add_icon_item(get_theme_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE); + p->add_icon_item(get_theme_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE); p->add_separator(); - p->add_icon_item(get_theme_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_AND_MARGINS_PRESET_WIDE); - p->add_icon_item(get_theme_icon("Anchor", "EditorIcons"), TTR("Keep Ratio"), ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO); + p->add_icon_item(get_theme_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_AND_OFFSETS_PRESET_WIDE); + p->add_icon_item(get_theme_icon("Anchor", "EditorIcons"), TTR("Keep Ratio"), ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO); p->add_separator(); p->add_submenu_item(TTR("Anchors only"), "Anchors"); p->set_item_icon(21, get_theme_icon("Anchor", "EditorIcons")); @@ -4396,7 +4396,7 @@ void CanvasItemEditor::_popup_warning_depop(Control *p_control) { timer->queue_delete(); p_control->hide(); popup_temporarily_timers.erase(p_control); - info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); + info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); } void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const float p_duration) { @@ -4414,7 +4414,7 @@ void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const floa timer->start(p_duration); p_control->show(); - info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); + info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); } void CanvasItemEditor::_update_scroll(float) { @@ -4427,10 +4427,10 @@ void CanvasItemEditor::_update_scroll(float) { viewport->update(); } -void CanvasItemEditor::_set_anchors_and_margins_preset(Control::LayoutPreset p_preset) { +void CanvasItemEditor::_set_anchors_and_offsets_preset(Control::LayoutPreset p_preset) { List<Node *> selection = editor_selection->get_selected_node_list(); - undo_redo->create_action(TTR("Change Anchors and Margins")); + undo_redo->create_action(TTR("Change Anchors and Offsets")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { Control *control = Object::cast_to<Control>(E->get()); @@ -4446,7 +4446,7 @@ void CanvasItemEditor::_set_anchors_and_margins_preset(Control::LayoutPreset p_p case PRESET_CENTER_RIGHT: case PRESET_CENTER_BOTTOM: case PRESET_CENTER: - undo_redo->add_do_method(control, "set_margins_preset", p_preset, Control::PRESET_MODE_KEEP_SIZE); + undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_KEEP_SIZE); break; case PRESET_LEFT_WIDE: case PRESET_TOP_WIDE: @@ -4455,7 +4455,7 @@ void CanvasItemEditor::_set_anchors_and_margins_preset(Control::LayoutPreset p_p case PRESET_VCENTER_WIDE: case PRESET_HCENTER_WIDE: case PRESET_WIDE: - undo_redo->add_do_method(control, "set_margins_preset", p_preset, Control::PRESET_MODE_MINSIZE); + undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_MINSIZE); break; } undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state()); @@ -4468,20 +4468,20 @@ void CanvasItemEditor::_set_anchors_and_margins_preset(Control::LayoutPreset p_p anchor_mode_button->set_pressed(anchors_mode); } -void CanvasItemEditor::_set_anchors_and_margins_to_keep_ratio() { +void CanvasItemEditor::_set_anchors_and_offsets_to_keep_ratio() { List<Node *> selection = editor_selection->get_selected_node_list(); - undo_redo->create_action(TTR("Change Anchors and Margins")); + undo_redo->create_action(TTR("Change Anchors and Offsets")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { Control *control = Object::cast_to<Control>(E->get()); if (control) { Point2 top_left_anchor = _position_to_anchor(control, Point2()); Point2 bottom_right_anchor = _position_to_anchor(control, control->get_size()); - undo_redo->add_do_method(control, "set_anchor", MARGIN_LEFT, top_left_anchor.x, false, true); - undo_redo->add_do_method(control, "set_anchor", MARGIN_RIGHT, bottom_right_anchor.x, false, true); - undo_redo->add_do_method(control, "set_anchor", MARGIN_TOP, top_left_anchor.y, false, true); - undo_redo->add_do_method(control, "set_anchor", MARGIN_BOTTOM, bottom_right_anchor.y, false, true); + undo_redo->add_do_method(control, "set_anchor", SIDE_LEFT, top_left_anchor.x, false, true); + undo_redo->add_do_method(control, "set_anchor", SIDE_RIGHT, bottom_right_anchor.x, false, true); + undo_redo->add_do_method(control, "set_anchor", SIDE_TOP, top_left_anchor.y, false, true); + undo_redo->add_do_method(control, "set_anchor", SIDE_BOTTOM, bottom_right_anchor.y, false, true); undo_redo->add_do_method(control, "set_meta", "_edit_use_anchors_", true); bool use_anchors = control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_"); @@ -4934,56 +4934,56 @@ void CanvasItemEditor::_popup_callback(int p_op) { undo_redo->add_undo_method(viewport, "update", Variant()); undo_redo->commit_action(); } break; - case ANCHORS_AND_MARGINS_PRESET_TOP_LEFT: { - _set_anchors_and_margins_preset(PRESET_TOP_LEFT); + case ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT: { + _set_anchors_and_offsets_preset(PRESET_TOP_LEFT); } break; - case ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT: { - _set_anchors_and_margins_preset(PRESET_TOP_RIGHT); + case ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT: { + _set_anchors_and_offsets_preset(PRESET_TOP_RIGHT); } break; - case ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT: { - _set_anchors_and_margins_preset(PRESET_BOTTOM_LEFT); + case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT: { + _set_anchors_and_offsets_preset(PRESET_BOTTOM_LEFT); } break; - case ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT: { - _set_anchors_and_margins_preset(PRESET_BOTTOM_RIGHT); + case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT: { + _set_anchors_and_offsets_preset(PRESET_BOTTOM_RIGHT); } break; - case ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT: { - _set_anchors_and_margins_preset(PRESET_CENTER_LEFT); + case ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT: { + _set_anchors_and_offsets_preset(PRESET_CENTER_LEFT); } break; - case ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT: { - _set_anchors_and_margins_preset(PRESET_CENTER_RIGHT); + case ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT: { + _set_anchors_and_offsets_preset(PRESET_CENTER_RIGHT); } break; - case ANCHORS_AND_MARGINS_PRESET_CENTER_TOP: { - _set_anchors_and_margins_preset(PRESET_CENTER_TOP); + case ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP: { + _set_anchors_and_offsets_preset(PRESET_CENTER_TOP); } break; - case ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM: { - _set_anchors_and_margins_preset(PRESET_CENTER_BOTTOM); + case ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM: { + _set_anchors_and_offsets_preset(PRESET_CENTER_BOTTOM); } break; - case ANCHORS_AND_MARGINS_PRESET_CENTER: { - _set_anchors_and_margins_preset(PRESET_CENTER); + case ANCHORS_AND_OFFSETS_PRESET_CENTER: { + _set_anchors_and_offsets_preset(PRESET_CENTER); } break; - case ANCHORS_AND_MARGINS_PRESET_TOP_WIDE: { - _set_anchors_and_margins_preset(PRESET_TOP_WIDE); + case ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE: { + _set_anchors_and_offsets_preset(PRESET_TOP_WIDE); } break; - case ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE: { - _set_anchors_and_margins_preset(PRESET_LEFT_WIDE); + case ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE: { + _set_anchors_and_offsets_preset(PRESET_LEFT_WIDE); } break; - case ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE: { - _set_anchors_and_margins_preset(PRESET_RIGHT_WIDE); + case ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE: { + _set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE); } break; - case ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE: { - _set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE); + case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE: { + _set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); } break; - case ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE: { - _set_anchors_and_margins_preset(PRESET_VCENTER_WIDE); + case ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE: { + _set_anchors_and_offsets_preset(PRESET_VCENTER_WIDE); } break; - case ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE: { - _set_anchors_and_margins_preset(PRESET_HCENTER_WIDE); + case ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE: { + _set_anchors_and_offsets_preset(PRESET_HCENTER_WIDE); } break; - case ANCHORS_AND_MARGINS_PRESET_WIDE: { - _set_anchors_and_margins_preset(Control::PRESET_WIDE); + case ANCHORS_AND_OFFSETS_PRESET_WIDE: { + _set_anchors_and_offsets_preset(Control::PRESET_WIDE); } break; - case ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO: { - _set_anchors_and_margins_to_keep_ratio(); + case ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO: { + _set_anchors_and_offsets_to_keep_ratio(); } break; case ANCHORS_PRESET_TOP_LEFT: { @@ -5572,12 +5572,12 @@ void CanvasItemEditor::add_control_to_info_overlay(Control *p_control) { p_control->set_h_size_flags(p_control->get_h_size_flags() & ~Control::SIZE_EXPAND_FILL); info_overlay->add_child(p_control); - info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); + info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); } void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) { info_overlay->remove_child(p_control); - info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); + info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); } void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) { @@ -5674,7 +5674,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { hb = memnew(HBoxContainer); add_child(hb); - hb->set_anchors_and_margins_preset(Control::PRESET_WIDE); + hb->set_anchors_and_offsets_preset(Control::PRESET_WIDE); bottom_split = memnew(VSplitContainer); add_child(bottom_split); @@ -5695,7 +5695,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { SubViewportContainer *scene_tree = memnew(SubViewportContainer); viewport_scrollable->add_child(scene_tree); scene_tree->set_stretch(true); - scene_tree->set_anchors_and_margins_preset(Control::PRESET_WIDE); + scene_tree->set_anchors_and_offsets_preset(Control::PRESET_WIDE); scene_tree->add_child(p_editor->get_scene_root()); controls_vb = memnew(VBoxContainer); @@ -5709,16 +5709,16 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { viewport = memnew(CanvasItemEditorViewport(p_editor, this)); viewport_scrollable->add_child(viewport); viewport->set_mouse_filter(MOUSE_FILTER_PASS); - viewport->set_anchors_and_margins_preset(Control::PRESET_WIDE); + viewport->set_anchors_and_offsets_preset(Control::PRESET_WIDE); viewport->set_clip_contents(true); viewport->set_focus_mode(FOCUS_ALL); viewport->connect("draw", callable_mp(this, &CanvasItemEditor::_draw_viewport)); viewport->connect("gui_input", callable_mp(this, &CanvasItemEditor::_gui_input_viewport)); info_overlay = memnew(VBoxContainer); - info_overlay->set_anchors_and_margins_preset(Control::PRESET_BOTTOM_LEFT); - info_overlay->set_margin(MARGIN_LEFT, 10); - info_overlay->set_margin(MARGIN_BOTTOM, -15); + info_overlay->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_LEFT); + info_overlay->set_offset(SIDE_LEFT, 10); + info_overlay->set_offset(SIDE_BOTTOM, -15); info_overlay->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN); info_overlay->add_theme_constant_override("separation", 10); viewport_scrollable->add_child(info_overlay); @@ -6140,7 +6140,7 @@ CanvasItemEditorPlugin::CanvasItemEditorPlugin(EditorNode *p_node) { canvas_item_editor = memnew(CanvasItemEditor(editor)); canvas_item_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); editor->get_viewport()->add_child(canvas_item_editor); - canvas_item_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + canvas_item_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE); canvas_item_editor->hide(); } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index c4a1dca593..f5da953810 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -119,23 +119,23 @@ private: UNLOCK_SELECTED, GROUP_SELECTED, UNGROUP_SELECTED, - ANCHORS_AND_MARGINS_PRESET_TOP_LEFT, - ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT, - ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT, - ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT, - ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT, - ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT, - ANCHORS_AND_MARGINS_PRESET_CENTER_TOP, - ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM, - ANCHORS_AND_MARGINS_PRESET_CENTER, - ANCHORS_AND_MARGINS_PRESET_TOP_WIDE, - ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE, - ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE, - ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE, - ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE, - ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE, - ANCHORS_AND_MARGINS_PRESET_WIDE, - ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO, + ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT, + ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT, + ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT, + ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT, + ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT, + ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT, + ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP, + ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM, + ANCHORS_AND_OFFSETS_PRESET_CENTER, + ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE, + ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE, + ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE, + ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE, + ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE, + ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE, + ANCHORS_AND_OFFSETS_PRESET_WIDE, + ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO, ANCHORS_PRESET_TOP_LEFT, ANCHORS_PRESET_TOP_RIGHT, ANCHORS_PRESET_BOTTOM_LEFT, @@ -152,22 +152,22 @@ private: ANCHORS_PRESET_VCENTER_WIDE, ANCHORS_PRESET_HCENTER_WIDE, ANCHORS_PRESET_WIDE, - MARGINS_PRESET_TOP_LEFT, - MARGINS_PRESET_TOP_RIGHT, - MARGINS_PRESET_BOTTOM_LEFT, - MARGINS_PRESET_BOTTOM_RIGHT, - MARGINS_PRESET_CENTER_LEFT, - MARGINS_PRESET_CENTER_RIGHT, - MARGINS_PRESET_CENTER_TOP, - MARGINS_PRESET_CENTER_BOTTOM, - MARGINS_PRESET_CENTER, - MARGINS_PRESET_TOP_WIDE, - MARGINS_PRESET_LEFT_WIDE, - MARGINS_PRESET_RIGHT_WIDE, - MARGINS_PRESET_BOTTOM_WIDE, - MARGINS_PRESET_VCENTER_WIDE, - MARGINS_PRESET_HCENTER_WIDE, - MARGINS_PRESET_WIDE, + OFFSETS_PRESET_TOP_LEFT, + OFFSETS_PRESET_TOP_RIGHT, + OFFSETS_PRESET_BOTTOM_LEFT, + OFFSETS_PRESET_BOTTOM_RIGHT, + OFFSETS_PRESET_CENTER_LEFT, + OFFSETS_PRESET_CENTER_RIGHT, + OFFSETS_PRESET_CENTER_TOP, + OFFSETS_PRESET_CENTER_BOTTOM, + OFFSETS_PRESET_CENTER, + OFFSETS_PRESET_TOP_WIDE, + OFFSETS_PRESET_LEFT_WIDE, + OFFSETS_PRESET_RIGHT_WIDE, + OFFSETS_PRESET_BOTTOM_WIDE, + OFFSETS_PRESET_VCENTER_WIDE, + OFFSETS_PRESET_HCENTER_WIDE, + OFFSETS_PRESET_WIDE, ANIM_INSERT_KEY, ANIM_INSERT_KEY_EXISTING, ANIM_INSERT_POS, @@ -454,9 +454,9 @@ private: void _unhandled_key_input(const Ref<InputEvent> &p_ev); - void _draw_text_at_position(Point2 p_position, String p_string, Margin p_side); - void _draw_margin_at_position(int p_value, Point2 p_position, Margin p_side); - void _draw_percentage_at_position(float p_value, Point2 p_position, Margin p_side); + void _draw_text_at_position(Point2 p_position, String p_string, Side p_side); + void _draw_margin_at_position(int p_value, Point2 p_position, Side p_side); + void _draw_percentage_at_position(float p_value, Point2 p_position, Side p_side); void _draw_straight_line(Point2 p_from, Point2 p_to, Color p_color); void _draw_smart_snapping(); @@ -519,9 +519,9 @@ private: const Node *p_current); void _set_anchors_preset(Control::LayoutPreset p_preset); - void _set_margins_preset(Control::LayoutPreset p_preset); - void _set_anchors_and_margins_preset(Control::LayoutPreset p_preset); - void _set_anchors_and_margins_to_keep_ratio(); + void _set_offsets_preset(Control::LayoutPreset p_preset); + void _set_anchors_and_offsets_preset(Control::LayoutPreset p_preset); + void _set_anchors_and_offsets_to_keep_ratio(); void _button_toggle_anchor_mode(bool p_status); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 2fc0e35f82..7c3b393cd5 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -106,7 +106,7 @@ Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Siz } } - if (img.is_null() || img->empty()) { + if (img.is_null() || img->is_empty()) { return Ref<Texture2D>(); } @@ -150,7 +150,7 @@ bool EditorImagePreviewPlugin::handles(const String &p_type) const { Ref<Texture2D> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { Ref<Image> img = p_from; - if (img.is_null() || img->empty()) { + if (img.is_null() || img->is_empty()) { return Ref<Image>(); } diff --git a/editor/plugins/font_editor_plugin.cpp b/editor/plugins/font_editor_plugin.cpp index a82547182c..55419e1042 100644 --- a/editor/plugins/font_editor_plugin.cpp +++ b/editor/plugins/font_editor_plugin.cpp @@ -216,7 +216,7 @@ void FontDataEditor::init_script_edit() { void FontDataEditor::add_lang() { FontData *fd = Object::cast_to<FontData>(get_edited_object()); - if (fd != nullptr && !le->get_text().empty()) { + if (fd != nullptr && !le->get_text().is_empty()) { fd->set_language_support_override(le->get_text(), chk->is_pressed()); le->set_text(""); chk->set_pressed(false); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index e49cfd51f7..e45344b427 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -108,7 +108,7 @@ MaterialEditor::MaterialEditor() { vc = memnew(SubViewportContainer); vc->set_stretch(true); add_child(vc); - vc->set_anchors_and_margins_preset(PRESET_WIDE); + vc->set_anchors_and_offsets_preset(PRESET_WIDE); viewport = memnew(SubViewport); Ref<World3D> world_3d; world_3d.instance(); @@ -155,7 +155,7 @@ MaterialEditor::MaterialEditor() { HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); - hb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2); + hb->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2); VBoxContainer *vb_shape = memnew(VBoxContainer); hb->add_child(vb_shape); diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 9d396467c3..79dbf7d522 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -137,7 +137,7 @@ MeshEditor::MeshEditor() { HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); - hb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2); + hb->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2); hb->add_spacer(); diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 2a08e3a8b5..c8a85267ac 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -63,7 +63,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { List<Node *> selection = editor_selection->get_selected_node_list(); - if (selection.empty()) { + if (selection.is_empty()) { Ref<Shape3D> shape = mesh->create_trimesh_shape(); if (shape.is_null()) { err_dialog->set_text(TTR("Couldn't create a Trimesh collision shape.")); diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index b11a07365c..fb34f4064a 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -298,7 +298,7 @@ MeshLibraryEditorPlugin::MeshLibraryEditorPlugin(EditorNode *p_node) { mesh_library_editor = memnew(MeshLibraryEditor(p_node)); p_node->get_viewport()->add_child(mesh_library_editor); - mesh_library_editor->set_anchors_and_margins_preset(Control::PRESET_TOP_WIDE); + mesh_library_editor->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE); mesh_library_editor->set_end(Point2(0, 22)); mesh_library_editor->hide(); diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index b8a4f7bc5a..59ab622994 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -337,7 +337,7 @@ MultiMeshEditor::MultiMeshEditor() { vbc->add_margin_child(TTR("Scale:"), populate_scale); populate_amount = memnew(SpinBox); - populate_amount->set_anchor(MARGIN_RIGHT, ANCHOR_END); + populate_amount->set_anchor(SIDE_RIGHT, ANCHOR_END); populate_amount->set_begin(Point2(20, 232)); populate_amount->set_end(Point2(-5, 237)); populate_amount->set_min(1); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index fcbca8ced0..c88c6f488e 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -612,7 +612,7 @@ void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_inclu results.push_back(res); } - if (results.empty()) { + if (results.is_empty()) { return; } @@ -1045,7 +1045,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) { clicked = ObjectID(); } - } else if (!selection_results.empty()) { + } else if (!selection_results.is_empty()) { NodePath root_path = get_tree()->get_edited_scene_root()->get_path(); StringName root_name = root_path.get_name(root_path.get_name_count() - 1); @@ -1097,7 +1097,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { { EditorNode *en = editor; EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding(); - if (!force_input_forwarding_list->empty()) { + if (!force_input_forwarding_list->is_empty()) { bool discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true); if (discard) { return; @@ -1107,7 +1107,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { { EditorNode *en = editor; EditorPluginList *over_plugin_list = en->get_editor_plugins_over(); - if (!over_plugin_list->empty()) { + if (!over_plugin_list->is_empty()) { bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false); if (discard) { return; @@ -2543,12 +2543,12 @@ void Node3DEditorViewport::_notification(int p_what) { cinema_label->set_visible(show_cinema); if (show_cinema) { float cinema_half_width = cinema_label->get_size().width / 2.0f; - cinema_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -cinema_half_width); + cinema_label->set_anchor_and_offset(SIDE_LEFT, 0.5f, -cinema_half_width); } if (lock_rotation) { float locked_half_width = locked_label->get_size().width / 2.0f; - locked_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -locked_half_width); + locked_label->set_anchor_and_offset(SIDE_LEFT, 0.5f, -locked_half_width); } } @@ -2615,12 +2615,12 @@ static void draw_indicator_bar(Control &surface, real_t fill, const Ref<Texture2 void Node3DEditorViewport::_draw() { EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over(); - if (!over_plugin_list->empty()) { + if (!over_plugin_list->is_empty()) { over_plugin_list->forward_spatial_draw_over_viewport(surface); } EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over(); - if (!force_over_plugin_list->empty()) { + if (!force_over_plugin_list->is_empty()) { force_over_plugin_list->forward_spatial_force_draw_over_viewport(surface); } @@ -2674,7 +2674,8 @@ void Node3DEditorViewport::_draw() { break; } handle_color.a = 1.0; - handle_color *= Color(1.3, 1.3, 1.3, 1.0); + const float brightness = 1.3; + handle_color *= Color(brightness, brightness, brightness); RenderingServer::get_singleton()->canvas_item_add_line( ci, @@ -3890,7 +3891,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito subviewport_container = c; c->set_stretch(true); add_child(c); - c->set_anchors_and_margins_preset(Control::PRESET_WIDE); + c->set_anchors_and_offsets_preset(Control::PRESET_WIDE); viewport = memnew(SubViewport); viewport->set_disable_input(true); @@ -3898,7 +3899,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito surface = memnew(Control); surface->set_drag_forwarding(this); add_child(surface); - surface->set_anchors_and_margins_preset(Control::PRESET_WIDE); + surface->set_anchors_and_offsets_preset(Control::PRESET_WIDE); surface->set_clip_contents(true); camera = memnew(Camera3D); camera->set_disable_gizmo(true); @@ -4033,19 +4034,19 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito preview_node = nullptr; info_label = memnew(Label); - info_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE); - info_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -90 * EDSCALE); - info_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE); - info_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE); + info_label->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -90 * EDSCALE); + info_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -90 * EDSCALE); + info_label->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -10 * EDSCALE); + info_label->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -10 * EDSCALE); info_label->set_h_grow_direction(GROW_DIRECTION_BEGIN); info_label->set_v_grow_direction(GROW_DIRECTION_BEGIN); surface->add_child(info_label); info_label->hide(); fps_label = memnew(Label); - fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE); - fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE); - fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE); + fps_label->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -90 * EDSCALE); + fps_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 10 * EDSCALE); + fps_label->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -10 * EDSCALE); fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN); fps_label->set_tooltip(TTR("Note: The FPS is estimated on a 60hz refresh rate.")); fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show. @@ -4053,7 +4054,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito fps_label->hide(); cinema_label = memnew(Label); - cinema_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE); + cinema_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 10 * EDSCALE); cinema_label->set_h_grow_direction(GROW_DIRECTION_END); cinema_label->set_align(Label::ALIGN_CENTER); surface->add_child(cinema_label); @@ -4062,8 +4063,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito previewing_cinema = false; locked_label = memnew(Label); - locked_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -20 * EDSCALE); - locked_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE); + locked_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -20 * EDSCALE); + locked_label->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -10 * EDSCALE); locked_label->set_h_grow_direction(GROW_DIRECTION_END); locked_label->set_v_grow_direction(GROW_DIRECTION_BEGIN); locked_label->set_align(Label::ALIGN_CENTER); @@ -4072,7 +4073,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito locked_label->hide(); top_right_vbox = memnew(VBoxContainer); - top_right_vbox->set_anchors_and_margins_preset(PRESET_TOP_RIGHT, PRESET_MODE_MINSIZE, 2.0 * EDSCALE); + top_right_vbox->set_anchors_and_offsets_preset(PRESET_TOP_RIGHT, PRESET_MODE_MINSIZE, 2.0 * EDSCALE); top_right_vbox->set_h_grow_direction(GROW_DIRECTION_BEGIN); rotation_control = memnew(ViewportRotationControl); @@ -4082,9 +4083,9 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito top_right_vbox->add_child(rotation_control); fps_label = memnew(Label); - fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE); - fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE); - fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE); + fps_label->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -90 * EDSCALE); + fps_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 10 * EDSCALE); + fps_label->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -10 * EDSCALE); fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN); fps_label->set_tooltip(TTR("Note: The FPS value displayed is the editor's framerate.\nIt cannot be used as a reliable indication of in-game performance.")); fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show. @@ -5252,7 +5253,9 @@ void Node3DEditor::_init_indicators() { gizmo_color[i] = mat; Ref<StandardMaterial3D> mat_hl = mat->duplicate(); - mat_hl->set_albedo(Color(col.r * 1.3, col.g * 1.3, col.b * 1.3, 1.0)); + const float brightness = 1.3; + const Color albedo = Color(col.r * brightness, col.g * brightness, col.b * brightness); + mat_hl->set_albedo(albedo); gizmo_color_hl[i] = mat_hl; Vector3 ivec; @@ -5347,7 +5350,7 @@ void Node3DEditor::_init_indicators() { surftool->commit(move_plane_gizmo[i]); Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate(); - plane_mat_hl->set_albedo(Color(col.r * 1.3, col.g * 1.3, col.b * 1.3, 1.0)); + plane_mat_hl->set_albedo(albedo); plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides } @@ -5430,7 +5433,7 @@ void Node3DEditor::_init_indicators() { rotate_gizmo[i]->surface_set_material(0, rotate_mat); Ref<ShaderMaterial> rotate_mat_hl = rotate_mat->duplicate(); - rotate_mat_hl->set_shader_param("albedo", Color(col.r * 1.3, col.g * 1.3, col.b * 1.3, 1.0)); + rotate_mat_hl->set_shader_param("albedo", albedo); rotate_gizmo_color_hl[i] = rotate_mat_hl; if (i == 2) { // Rotation white outline @@ -5557,7 +5560,7 @@ void Node3DEditor::_init_indicators() { surftool->commit(scale_plane_gizmo[i]); Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate(); - plane_mat_hl->set_albedo(Color(col.r * 1.3, col.g * 1.3, col.b * 1.3, 1.0)); + plane_mat_hl->set_albedo(Color(col.r * 1.3, col.g * 1.3, col.b * 1.3)); plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides } } @@ -5775,7 +5778,7 @@ void Node3DEditor::_refresh_menu_icons() { List<Node *> &selection = editor_selection->get_selected_node_list(); - if (selection.empty()) { + if (selection.is_empty()) { all_locked = false; all_grouped = false; } else { @@ -5794,11 +5797,11 @@ void Node3DEditor::_refresh_menu_icons() { } tool_button[TOOL_LOCK_SELECTED]->set_visible(!all_locked); - tool_button[TOOL_LOCK_SELECTED]->set_disabled(selection.empty()); + tool_button[TOOL_LOCK_SELECTED]->set_disabled(selection.is_empty()); tool_button[TOOL_UNLOCK_SELECTED]->set_visible(all_locked); tool_button[TOOL_GROUP_SELECTED]->set_visible(!all_grouped); - tool_button[TOOL_GROUP_SELECTED]->set_disabled(selection.empty()); + tool_button[TOOL_GROUP_SELECTED]->set_disabled(selection.is_empty()); tool_button[TOOL_UNGROUP_SELECTED]->set_visible(all_grouped); } @@ -6109,7 +6112,7 @@ void Node3DEditor::_toggle_maximize_view(Object *p_viewport) { if (!maximized) { for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { if (i == (uint32_t)index) { - viewports[i]->set_anchors_and_margins_preset(Control::PRESET_WIDE); + viewports[i]->set_anchors_and_offsets_preset(Control::PRESET_WIDE); } else { viewports[i]->hide(); } diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp index 608b5c3104..09d2303359 100644 --- a/editor/plugins/packed_scene_translation_parser_plugin.cpp +++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp @@ -81,14 +81,14 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> str_values = property_value; for (int k = 0; k < str_values.size(); k++) { String desc = str_values[k].get_slice(";", 1).strip_edges(); - if (!desc.empty()) { + if (!desc.is_empty()) { parsed_strings.push_back(desc); } } } else if (property_value.get_type() == Variant::STRING) { String str_value = String(property_value); // Prevent reading text containing only spaces. - if (!str_value.strip_edges().empty()) { + if (!str_value.strip_edges().is_empty()) { parsed_strings.push_back(str_value); } } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 0ccca7e06c..0584ee894b 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -86,8 +86,8 @@ void Polygon2DEditor::_notification(int p_what) { b_snap_enable->set_icon(get_theme_icon("SnapGrid", "EditorIcons")); uv_icon_zoom->set_texture(get_theme_icon("Zoom", "EditorIcons")); - uv_vscroll->set_anchors_and_margins_preset(PRESET_RIGHT_WIDE); - uv_hscroll->set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE); + uv_vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE); + uv_hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); } break; case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible()) { @@ -1189,8 +1189,8 @@ void Polygon2DEditor::_uv_draw() { Size2 vmin = uv_vscroll->get_combined_minimum_size(); // Avoid scrollbar overlapping. - uv_hscroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, uv_vscroll->is_visible() ? -vmin.width : 0); - uv_vscroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, uv_hscroll->is_visible() ? -hmin.height : 0); + uv_hscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, uv_vscroll->is_visible() ? -vmin.width : 0); + uv_vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, uv_hscroll->is_visible() ? -hmin.height : 0); updating_uv_scroll = false; } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index e0a6fe16f7..10bd7cc952 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -587,7 +587,7 @@ void ScriptEditor::_go_to_tab(int p_idx) { } void ScriptEditor::_add_recent_script(String p_path) { - if (p_path.empty()) { + if (p_path.is_empty()) { return; } @@ -702,7 +702,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { } } if (script.is_valid()) { - if (!script->get_path().empty()) { + if (!script->get_path().is_empty()) { // Only saved scripts can be restored. previous_scripts.push_back(script->get_path()); } @@ -1129,7 +1129,7 @@ void ScriptEditor::_menu_option(int p_option) { return; } break; case FILE_REOPEN_CLOSED: { - if (previous_scripts.empty()) { + if (previous_scripts.is_empty()) { return; } @@ -1381,7 +1381,7 @@ void ScriptEditor::_menu_option(int p_option) { case SHOW_IN_FILE_SYSTEM: { const RES script = current->get_edited_resource(); const String path = script->get_path(); - if (!path.empty()) { + if (!path.is_empty()) { FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock(); file_system_dock->navigate_to_path(path); // Ensure that the FileSystem dock is visible. @@ -1887,7 +1887,7 @@ void ScriptEditor::_update_script_names() { if (se) { Ref<Texture2D> icon = se->get_theme_icon(); String path = se->get_edited_resource()->get_path(); - bool saved = !path.empty(); + bool saved = !path.is_empty(); if (saved) { // The script might be deleted, moved, or renamed, so make sure // to update original path to previously edited resource. @@ -1934,7 +1934,7 @@ void ScriptEditor::_update_script_names() { sd.name = name; } break; case DISPLAY_DIR_AND_NAME: { - if (!path.get_base_dir().get_file().empty()) { + if (!path.get_base_dir().get_file().is_empty()) { sd.name = path.get_base_dir().get_file().plus_file(name); } else { sd.name = name; @@ -1954,7 +1954,7 @@ void ScriptEditor::_update_script_names() { Vector<String> disambiguated_script_names; Vector<String> full_script_paths; for (int j = 0; j < sedata.size(); j++) { - disambiguated_script_names.append(sedata[j].name.replace("(*)", "")); + disambiguated_script_names.append(sedata[j].name.replace("(*)", "").get_file()); full_script_paths.append(sedata[j].tooltip); } @@ -1988,7 +1988,7 @@ void ScriptEditor::_update_script_names() { } } - if (_sort_list_on_update && !sedata.empty()) { + if (_sort_list_on_update && !sedata.is_empty()) { sedata.sort(); // change actual order of tab_container so that the order can be rearranged by user @@ -2052,7 +2052,7 @@ void ScriptEditor::_update_script_names() { _update_help_overview_visibility(); _update_script_colors(); - file_menu->get_popup()->set_item_disabled(file_menu->get_popup()->get_item_index(FILE_REOPEN_CLOSED), previous_scripts.empty()); + file_menu->get_popup()->set_item_disabled(file_menu->get_popup()->get_item_index(FILE_REOPEN_CLOSED), previous_scripts.is_empty()); } void ScriptEditor::_update_script_connections() { @@ -2806,7 +2806,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { String path = scripts[i]; Dictionary script_info = scripts[i]; - if (!script_info.empty()) { + if (!script_info.is_empty()) { path = script_info["path"]; } @@ -2833,7 +2833,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { } } - if (!script_info.empty()) { + if (!script_info.is_empty()) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(tab_container->get_tab_count() - 1)); if (se) { se->set_edit_state(script_info["state"]); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index e854ed4fb3..f34224ab95 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -84,10 +84,10 @@ ConnectionInfoDialog::ConnectionInfoDialog() { set_title(TTR("Connections to method:")); VBoxContainer *vbc = memnew(VBoxContainer); - vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE); add_child(vbc); method = memnew(Label); @@ -349,7 +349,7 @@ void ScriptTextEditor::update_settings() { bool ScriptTextEditor::is_unsaved() { const bool unsaved = code_editor->get_text_editor()->get_version() != code_editor->get_text_editor()->get_saved_version() || - script->get_path().empty(); // In memory. + script->get_path().is_empty(); // In memory. return unsaved; } @@ -427,7 +427,7 @@ String ScriptTextEditor::get_name() { if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { name = script->get_path().get_file(); if (is_unsaved()) { - if (script->get_path().empty()) { + if (script->get_path().is_empty()) { name = TTR("[unsaved]"); } name += "(*)"; @@ -551,7 +551,7 @@ void ScriptTextEditor::_validate_script() { if (safe_lines.has(i + 1)) { te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color); last_is_safe = true; - } else if (last_is_safe && (te->is_line_comment(i) || te->get_line(i).strip_edges().empty())) { + } else if (last_is_safe && (te->is_line_comment(i) || te->get_line(i).strip_edges().is_empty())) { te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color); } else { te->set_line_gutter_item_color(i, line_number_gutter, default_line_number_color); @@ -1679,7 +1679,7 @@ void ScriptTextEditor::_enable_code_editor() { VSplitContainer *editor_box = memnew(VSplitContainer); add_child(editor_box); - editor_box->set_anchors_and_margins_preset(Control::PRESET_WIDE); + editor_box->set_anchors_and_offsets_preset(Control::PRESET_WIDE); editor_box->set_v_size_flags(SIZE_EXPAND_FILL); editor_box->add_child(code_editor); @@ -1809,7 +1809,7 @@ void ScriptTextEditor::_enable_code_editor() { ScriptTextEditor::ScriptTextEditor() { code_editor = memnew(CodeTextEditor); code_editor->add_theme_constant_override("separation", 2); - code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE); code_editor->set_code_complete_func(_code_complete_scripts, this); code_editor->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index d24dcdef83..9bb34f4489 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -558,7 +558,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { shader_editor = memnew(ShaderTextEditor); shader_editor->set_v_size_flags(SIZE_EXPAND_FILL); shader_editor->add_theme_constant_override("separation", 0); - shader_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + shader_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE); shader_editor->connect("script_changed", callable_mp(this, &ShaderEditor::apply_shaders)); EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ShaderEditor::_editor_settings_changed)); diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp index f15a801530..f6ce3f7958 100644 --- a/editor/plugins/shader_file_editor_plugin.cpp +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -59,7 +59,7 @@ void ShaderFileEditor::_version_selected(int p_option) { ERR_FAIL_COND(bytecode.is_null()); for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { - if (bytecode->get_stage_bytecode(RD::ShaderStage(i)).empty() && bytecode->get_stage_compile_error(RD::ShaderStage(i)) == String()) { + if (bytecode->get_stage_bytecode(RD::ShaderStage(i)).is_empty() && bytecode->get_stage_compile_error(RD::ShaderStage(i)) == String()) { stages[i]->set_icon(Ref<Texture2D>()); continue; } @@ -182,7 +182,7 @@ void ShaderFileEditor::_update_options() { for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { Vector<uint8_t> bc = bytecode->get_stage_bytecode(RD::ShaderStage(i)); String error = bytecode->get_stage_compile_error(RD::ShaderStage(i)); - bool disable = error == String() && bc.empty(); + bool disable = error == String() && bc.is_empty(); stages[i]->set_disabled(disable); if (!disable) { if (stages[i]->is_pressed()) { diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 22f50c0689..d22157fda7 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -293,7 +293,7 @@ void BoneTransformEditor::_key_button_pressed() { const BoneId bone_id = property.get_slicec('/', 1).to_int(); const String name = skeleton->get_bone_name(bone_id); - if (name.empty()) + if (name.is_empty()) return; // Need to normalize the basis before you key it diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 1be6b979b1..0bfd9e0c36 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -340,7 +340,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() { } void Sprite2DEditor::_convert_to_polygon_2d_node() { - if (computed_outline_lines.empty()) { + if (computed_outline_lines.is_empty()) { err_dialog->set_text(TTR("Invalid geometry, can't create polygon.")); err_dialog->popup_centered(); return; @@ -398,7 +398,7 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() { } void Sprite2DEditor::_create_collision_polygon_2d_node() { - if (computed_outline_lines.empty()) { + if (computed_outline_lines.is_empty()) { err_dialog->set_text(TTR("Invalid geometry, can't create collision polygon.")); err_dialog->popup_centered(); return; @@ -420,7 +420,7 @@ void Sprite2DEditor::_create_collision_polygon_2d_node() { } void Sprite2DEditor::_create_light_occluder_2d_node() { - if (computed_outline_lines.empty()) { + if (computed_outline_lines.is_empty()) { err_dialog->set_text(TTR("Invalid geometry, can't create light occluder.")); err_dialog->popup_centered(); return; diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index b79d829c34..099f2c8a7f 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -318,7 +318,7 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_ resources.push_back(resource); } - if (resources.empty()) { + if (resources.is_empty()) { return; } diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 9894d0e1b0..37899293d5 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -119,7 +119,7 @@ String TextEditor::get_name() { if (text_file->get_path().find("local://") == -1 && text_file->get_path().find("::") == -1) { name = text_file->get_path().get_file(); if (is_unsaved()) { - if (text_file->get_path().empty()) { + if (text_file->get_path().is_empty()) { name = TTR("[unsaved]"); } name += "(*)"; @@ -242,7 +242,7 @@ void TextEditor::apply_code() { bool TextEditor::is_unsaved() { const bool unsaved = code_editor->get_text_editor()->get_version() != code_editor->get_text_editor()->get_saved_version() || - text_file->get_path().empty(); // In memory. + text_file->get_path().is_empty(); // In memory. return unsaved; } @@ -548,7 +548,7 @@ TextEditor::TextEditor() { code_editor->add_theme_constant_override("separation", 0); code_editor->connect("load_theme_settings", callable_mp(this, &TextEditor::_load_theme_settings)); code_editor->connect("validate_script", callable_mp(this, &TextEditor::_validate_script)); - code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE); code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); update_settings(); diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index 8447a2346f..d13a865534 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -160,16 +160,16 @@ Texture3DEditor::Texture3DEditor() { layer->set_step(1); layer->set_max(100); add_child(layer); - layer->set_anchor(MARGIN_RIGHT, 1); - layer->set_anchor(MARGIN_LEFT, 1); + layer->set_anchor(SIDE_RIGHT, 1); + layer->set_anchor(SIDE_LEFT, 1); layer->set_h_grow_direction(GROW_DIRECTION_BEGIN); layer->set_modulate(Color(1, 1, 1, 0.8)); info = memnew(Label); add_child(info); - info->set_anchor(MARGIN_RIGHT, 1); - info->set_anchor(MARGIN_LEFT, 1); - info->set_anchor(MARGIN_BOTTOM, 1); - info->set_anchor(MARGIN_TOP, 1); + info->set_anchor(SIDE_RIGHT, 1); + info->set_anchor(SIDE_LEFT, 1); + info->set_anchor(SIDE_BOTTOM, 1); + info->set_anchor(SIDE_TOP, 1); info->set_h_grow_direction(GROW_DIRECTION_BEGIN); info->set_v_grow_direction(GROW_DIRECTION_BEGIN); info->add_theme_color_override("font_color", Color(1, 1, 1, 1)); diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index eafe4d546b..a807e8e99b 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -225,16 +225,16 @@ TextureLayeredEditor::TextureLayeredEditor() { layer->set_step(1); layer->set_max(100); add_child(layer); - layer->set_anchor(MARGIN_RIGHT, 1); - layer->set_anchor(MARGIN_LEFT, 1); + layer->set_anchor(SIDE_RIGHT, 1); + layer->set_anchor(SIDE_LEFT, 1); layer->set_h_grow_direction(GROW_DIRECTION_BEGIN); layer->set_modulate(Color(1, 1, 1, 0.8)); info = memnew(Label); add_child(info); - info->set_anchor(MARGIN_RIGHT, 1); - info->set_anchor(MARGIN_LEFT, 1); - info->set_anchor(MARGIN_BOTTOM, 1); - info->set_anchor(MARGIN_TOP, 1); + info->set_anchor(SIDE_RIGHT, 1); + info->set_anchor(SIDE_LEFT, 1); + info->set_anchor(SIDE_BOTTOM, 1); + info->set_anchor(SIDE_TOP, 1); info->set_h_grow_direction(GROW_DIRECTION_BEGIN); info->set_v_grow_direction(GROW_DIRECTION_BEGIN); info->add_theme_color_override("font_color", Color(1, 1, 1, 1)); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index f599b94428..15d5c615bd 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -217,23 +217,23 @@ void TextureRegionEditor::_region_draw() { Size2 vmin = vscroll->get_combined_minimum_size(); // Avoid scrollbar overlapping. - hscroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, vscroll->is_visible() ? -vmin.width : 0); - vscroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, hscroll->is_visible() ? -hmin.height : 0); + hscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, vscroll->is_visible() ? -vmin.width : 0); + vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, hscroll->is_visible() ? -hmin.height : 0); updating_scroll = false; if (node_ninepatch || obj_styleBox.is_valid()) { float margins[4] = { 0 }; if (node_ninepatch) { - margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP); - margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM); - margins[2] = node_ninepatch->get_patch_margin(MARGIN_LEFT); - margins[3] = node_ninepatch->get_patch_margin(MARGIN_RIGHT); + margins[0] = node_ninepatch->get_patch_margin(SIDE_TOP); + margins[1] = node_ninepatch->get_patch_margin(SIDE_BOTTOM); + margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT); + margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT); } else if (obj_styleBox.is_valid()) { - margins[0] = obj_styleBox->get_margin_size(MARGIN_TOP); - margins[1] = obj_styleBox->get_margin_size(MARGIN_BOTTOM); - margins[2] = obj_styleBox->get_margin_size(MARGIN_LEFT); - margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT); + margins[0] = obj_styleBox->get_margin_size(SIDE_TOP); + margins[1] = obj_styleBox->get_margin_size(SIDE_BOTTOM); + margins[2] = obj_styleBox->get_margin_size(SIDE_LEFT); + margins[3] = obj_styleBox->get_margin_size(SIDE_RIGHT); } Vector2 pos[4] = { @@ -278,15 +278,15 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { edited_margin = -1; float margins[4] = { 0 }; if (node_ninepatch) { - margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP); - margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM); - margins[2] = node_ninepatch->get_patch_margin(MARGIN_LEFT); - margins[3] = node_ninepatch->get_patch_margin(MARGIN_RIGHT); + margins[0] = node_ninepatch->get_patch_margin(SIDE_TOP); + margins[1] = node_ninepatch->get_patch_margin(SIDE_BOTTOM); + margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT); + margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT); } else if (obj_styleBox.is_valid()) { - margins[0] = obj_styleBox->get_margin_size(MARGIN_TOP); - margins[1] = obj_styleBox->get_margin_size(MARGIN_BOTTOM); - margins[2] = obj_styleBox->get_margin_size(MARGIN_LEFT); - margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT); + margins[0] = obj_styleBox->get_margin_size(SIDE_TOP); + margins[1] = obj_styleBox->get_margin_size(SIDE_BOTTOM); + margins[2] = obj_styleBox->get_margin_size(SIDE_LEFT); + margins[3] = obj_styleBox->get_margin_size(SIDE_RIGHT); } Vector2 pos[4] = { @@ -395,13 +395,13 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } else if (drag) { if (edited_margin >= 0) { undo_redo->create_action(TTR("Set Margin")); - static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT }; + static Side side[4] = { SIDE_TOP, SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT }; if (node_ninepatch) { - undo_redo->add_do_method(node_ninepatch, "set_patch_margin", m[edited_margin], node_ninepatch->get_patch_margin(m[edited_margin])); - undo_redo->add_undo_method(node_ninepatch, "set_patch_margin", m[edited_margin], prev_margin); + undo_redo->add_do_method(node_ninepatch, "set_patch_margin", side[edited_margin], node_ninepatch->get_patch_margin(side[edited_margin])); + undo_redo->add_undo_method(node_ninepatch, "set_patch_margin", side[edited_margin], prev_margin); } else if (obj_styleBox.is_valid()) { - undo_redo->add_do_method(obj_styleBox.ptr(), "set_margin_size", m[edited_margin], obj_styleBox->get_margin_size(m[edited_margin])); - undo_redo->add_undo_method(obj_styleBox.ptr(), "set_margin_size", m[edited_margin], prev_margin); + undo_redo->add_do_method(obj_styleBox.ptr(), "set_margin_size", side[edited_margin], obj_styleBox->get_margin_size(side[edited_margin])); + undo_redo->add_undo_method(obj_styleBox.ptr(), "set_margin_size", side[edited_margin], prev_margin); obj_styleBox->emit_signal(CoreStringNames::get_singleton()->changed); } edited_margin = -1; @@ -438,12 +438,12 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { if (drag) { drag = false; if (edited_margin >= 0) { - static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT }; + static Side side[4] = { SIDE_TOP, SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT }; if (node_ninepatch) { - node_ninepatch->set_patch_margin(m[edited_margin], prev_margin); + node_ninepatch->set_patch_margin(side[edited_margin], prev_margin); } if (obj_styleBox.is_valid()) { - obj_styleBox->set_margin_size(m[edited_margin], prev_margin); + obj_styleBox->set_margin_size(side[edited_margin], prev_margin); } edited_margin = -1; } else { @@ -486,12 +486,12 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { if (new_margin < 0) { new_margin = 0; } - static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT }; + static Side side[4] = { SIDE_TOP, SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT }; if (node_ninepatch) { - node_ninepatch->set_patch_margin(m[edited_margin], new_margin); + node_ninepatch->set_patch_margin(side[edited_margin], new_margin); } if (obj_styleBox.is_valid()) { - obj_styleBox->set_margin_size(m[edited_margin], new_margin); + obj_styleBox->set_margin_size(side[edited_margin], new_margin); } } else { Vector2 new_pos = mtx.affine_inverse().xform(mm->get_position()); @@ -772,8 +772,8 @@ void TextureRegionEditor::_notification(int p_what) { zoom_reset->set_icon(get_theme_icon("ZoomReset", "EditorIcons")); zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons")); - vscroll->set_anchors_and_margins_preset(PRESET_RIGHT_WIDE); - hscroll->set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE); + vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE); + hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); } break; case NOTIFICATION_VISIBILITY_CHANGED: { if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) { diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 189e5ec442..860b974632 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -262,7 +262,7 @@ Vector<int> TileMapEditor::get_selected_tiles() const { } void TileMapEditor::set_selected_tiles(Vector<int> p_tiles) { - palette->unselect_all(); + palette->deselect_all(); for (int i = p_tiles.size() - 1; i >= 0; i--) { int idx = palette->find_metadata(p_tiles[i]); @@ -449,7 +449,7 @@ void TileMapEditor::_update_palette() { List<int> tiles; tileset->get_tile_list(&tiles); - if (tiles.empty()) { + if (tiles.is_empty()) { return; } @@ -1779,7 +1779,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { return; } - if (paint_undo.empty()) { + if (paint_undo.is_empty()) { return; } @@ -1810,7 +1810,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { } } } else if (tool == TOOL_PASTING) { - if (copydata.empty()) { + if (copydata.is_empty()) { return; } @@ -2085,7 +2085,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { info_message->set_align(Label::ALIGN_CENTER); info_message->set_autowrap(true); info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); palette->add_child(info_message); // Add autotile override palette. diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 64647b51ba..7747c740df 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -119,19 +119,13 @@ void VersionControlEditorPlugin::_initialize_vcs() { } void VersionControlEditorPlugin::_send_commit_msg() { - String msg = commit_message->get_text(); - if (msg == "") { - commit_status->set_text(TTR("No commit message was provided")); - return; - } - if (EditorVCSInterface::get_singleton()) { if (staged_files_count == 0) { commit_status->set_text(TTR("No files added to stage")); return; } - EditorVCSInterface::get_singleton()->commit(msg); + EditorVCSInterface::get_singleton()->commit(commit_message->get_text()); commit_message->set_text(""); version_control_dock_button->set_pressed(false); @@ -294,6 +288,10 @@ void VersionControlEditorPlugin::_update_commit_status() { staged_files_count = 0; } +void VersionControlEditorPlugin::_update_commit_button() { + commit_button->set_disabled(commit_message->get_text().strip_edges() == ""); +} + void VersionControlEditorPlugin::register_editor() { if (!EditorVCSInterface::get_singleton()) { EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock); @@ -463,10 +461,12 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { commit_message->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END); commit_message->set_custom_minimum_size(Size2(200, 100)); commit_message->set_wrap_enabled(true); + commit_message->connect("text_changed", callable_mp(this, &VersionControlEditorPlugin::_update_commit_button)); commit_box_vbc->add_child(commit_message); commit_button = memnew(Button); commit_button->set_text(TTR("Commit Changes")); + commit_button->set_disabled(true); commit_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_send_commit_msg)); commit_box_vbc->add_child(commit_button); diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h index 34643e85e4..3f107ddffb 100644 --- a/editor/plugins/version_control_editor_plugin.h +++ b/editor/plugins/version_control_editor_plugin.h @@ -110,6 +110,7 @@ private: void _clear_file_diff(); void _update_stage_status(); void _update_commit_status(); + void _update_commit_button(); friend class EditorVCSInterface; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index da664109dc..ec1de43b6f 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -83,10 +83,10 @@ void VisualShaderNodePlugin::_bind_methods() { static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty)); - style->set_default_margin(MARGIN_LEFT, p_margin_left * EDSCALE); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * EDSCALE); - style->set_default_margin(MARGIN_BOTTOM, p_margin_bottom * EDSCALE); - style->set_default_margin(MARGIN_TOP, p_margin_top * EDSCALE); + style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE); + style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE); + style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE); return style; } @@ -283,7 +283,7 @@ VisualShader::Type VisualShaderGraphPlugin::get_shader_type() const { void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position) { if (visual_shader->get_shader_type() == p_type && links.has(p_id)) { - links[p_id].graph_node->set_offset(p_position); + links[p_id].graph_node->set_position_offset(p_position); } } @@ -365,7 +365,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { expression = expression_node->get_expression(); } - node->set_offset(visual_shader->get_node_position(p_type, p_id)); + node->set_position_offset(visual_shader->get_node_position(p_type, p_id)); node->set_title(vsnode->get_caption()); node->set_name(itos(p_id)); @@ -1015,7 +1015,7 @@ void VisualShaderEditor::_update_options_menu() { TreeItem *root = members->create_item(); String filter = node_filter->get_text().strip_edges(); - bool use_filter = !filter.empty(); + bool use_filter = !filter.is_empty(); bool is_first_item = true; @@ -1580,9 +1580,9 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p box_size.x = gn->get_size().x; } } - box_size.x -= text_box->get_margin(MARGIN_LEFT); + box_size.x -= text_box->get_offset(SIDE_LEFT); box_size.x -= 28 * EDSCALE; - box_size.y -= text_box->get_margin(MARGIN_TOP); + box_size.y -= text_box->get_offset(SIDE_TOP); box_size.y -= 28 * EDSCALE; text_box->set_custom_minimum_size(Size2(box_size.x, box_size.y)); text_box->set_size(Size2(1, 1)); @@ -2108,7 +2108,7 @@ void VisualShaderEditor::_delete_nodes_request() { } } - if (to_erase.empty()) { + if (to_erase.is_empty()) { return; } @@ -2145,13 +2145,13 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) { } } } - if (to_change.empty() && copy_nodes_buffer.empty()) { + if (to_change.is_empty() && copy_nodes_buffer.is_empty()) { _show_members_dialog(true); } else { - popup_menu->set_item_disabled(NodeMenuOptions::COPY, to_change.empty()); - popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_nodes_buffer.empty()); - popup_menu->set_item_disabled(NodeMenuOptions::DELETE, to_change.empty()); - popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, to_change.empty()); + popup_menu->set_item_disabled(NodeMenuOptions::COPY, to_change.is_empty()); + popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_nodes_buffer.is_empty()); + popup_menu->set_item_disabled(NodeMenuOptions::DELETE, to_change.is_empty()); + popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, to_change.is_empty()); menu_point = graph->get_local_mouse_position(); Point2 gpos = Input::get_singleton()->get_mouse_position(); popup_menu->set_position(gpos); @@ -2445,7 +2445,7 @@ void VisualShaderEditor::_duplicate_nodes() { _dup_copy_nodes(type, nodes, excluded); - if (nodes.empty()) { + if (nodes.is_empty()) { return; } @@ -2463,7 +2463,7 @@ void VisualShaderEditor::_copy_nodes() { } void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2 &p_custom_position) { - if (copy_nodes_buffer.empty()) { + if (copy_nodes_buffer.is_empty()) { return; } @@ -2997,12 +2997,12 @@ VisualShaderEditor::VisualShaderEditor() { popup_menu = memnew(PopupMenu); add_child(popup_menu); - popup_menu->add_item("Add Node", NodeMenuOptions::ADD); + popup_menu->add_item(TTR("Add Node"), NodeMenuOptions::ADD); popup_menu->add_separator(); - popup_menu->add_item("Copy", NodeMenuOptions::COPY); - popup_menu->add_item("Paste", NodeMenuOptions::PASTE); - popup_menu->add_item("Delete", NodeMenuOptions::DELETE); - popup_menu->add_item("Duplicate", NodeMenuOptions::DUPLICATE); + popup_menu->add_item(TTR("Copy"), NodeMenuOptions::COPY); + popup_menu->add_item(TTR("Paste"), NodeMenuOptions::PASTE); + popup_menu->add_item(TTR("Delete"), NodeMenuOptions::DELETE); + popup_menu->add_item(TTR("Duplicate"), NodeMenuOptions::DUPLICATE); popup_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_node_menu_id_pressed)); /////////////////////////////////////// diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp index 9b3227ad28..789d0e6ba5 100644 --- a/editor/pot_generator.cpp +++ b/editor/pot_generator.cpp @@ -135,7 +135,7 @@ void POTGenerator::_write_to_pot(const String &p_file) { } // Write context. - if (!context.empty()) { + if (!context.is_empty()) { file->store_line("msgctxt \"" + context + "\""); } @@ -143,7 +143,7 @@ void POTGenerator::_write_to_pot(const String &p_file) { _write_msgid(file, msgid, false); // Write msgid_plural - if (!plural.empty()) { + if (!plural.is_empty()) { _write_msgid(file, plural, true); file->store_line("msgstr[0] \"\""); file->store_line("msgstr[1] \"\"\n"); @@ -185,7 +185,7 @@ void POTGenerator::_add_new_msgid(const String &p_msgid, const String &p_context Vector<MsgidData> &v_mdata = all_translation_strings[p_msgid]; for (int i = 0; i < v_mdata.size(); i++) { if (v_mdata[i].ctx == p_context) { - if (!v_mdata[i].plural.empty() && !p_plural.empty() && v_mdata[i].plural != p_plural) { + if (!v_mdata[i].plural.is_empty() && !p_plural.is_empty() && v_mdata[i].plural != p_plural) { WARN_PRINT("Redefinition of plural message (msgid_plural), under the same message (msgid) and context (msgctxt)"); } v_mdata.write[i].locations.insert(p_location); diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp index 46a656e0af..d6d8e5789e 100644 --- a/editor/progress_dialog.cpp +++ b/editor/progress_dialog.cpp @@ -50,7 +50,7 @@ void BackgroundProgress::_add_task(const String &p_task, const String &p_label, Control *ec = memnew(Control); ec->set_h_size_flags(SIZE_EXPAND_FILL); ec->set_v_size_flags(SIZE_EXPAND_FILL); - t.progress->set_anchors_and_margins_preset(Control::PRESET_WIDE); + t.progress->set_anchors_and_offsets_preset(Control::PRESET_WIDE); ec->add_child(t.progress); ec->set_custom_minimum_size(Size2(80, 5) * EDSCALE); t.hb->add_child(ec); @@ -111,7 +111,7 @@ void BackgroundProgress::task_step(const String &p_task, int p_step) { bool no_updates = true; { _THREAD_SAFE_METHOD_ - no_updates = updates.empty(); + no_updates = updates.is_empty(); } if (no_updates) { @@ -141,10 +141,10 @@ void ProgressDialog::_popup() { Ref<StyleBox> style = main->get_theme_stylebox("panel", "PopupMenu"); ms += style->get_minimum_size(); - main->set_margin(MARGIN_LEFT, style->get_margin(MARGIN_LEFT)); - main->set_margin(MARGIN_RIGHT, -style->get_margin(MARGIN_RIGHT)); - main->set_margin(MARGIN_TOP, style->get_margin(MARGIN_TOP)); - main->set_margin(MARGIN_BOTTOM, -style->get_margin(MARGIN_BOTTOM)); + main->set_offset(SIDE_LEFT, style->get_margin(SIDE_LEFT)); + main->set_offset(SIDE_RIGHT, -style->get_margin(SIDE_RIGHT)); + main->set_offset(SIDE_TOP, style->get_margin(SIDE_TOP)); + main->set_offset(SIDE_BOTTOM, -style->get_margin(SIDE_BOTTOM)); //raise(); popup_centered(ms); @@ -218,7 +218,7 @@ void ProgressDialog::end_task(const String &p_task) { memdelete(t.vb); tasks.erase(p_task); - if (tasks.empty()) { + if (tasks.is_empty()) { hide(); } else { _popup(); @@ -235,7 +235,7 @@ void ProgressDialog::_bind_methods() { ProgressDialog::ProgressDialog() { main = memnew(VBoxContainer); add_child(main); - main->set_anchors_and_margins_preset(Control::PRESET_WIDE); + main->set_anchors_and_offsets_preset(Control::PRESET_WIDE); set_exclusive(true); last_progress_tick = 0; singleton = this; diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 68710920a5..c0f2f25465 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -196,7 +196,7 @@ void ProjectExportDialog::_edit_preset(int p_index) { export_path->hide(); runnable->set_disabled(true); parameters->edit(nullptr); - presets->unselect_all(); + presets->deselect_all(); duplicate_preset->set_disabled(true); delete_preset->set_disabled(true); sections->hide(); @@ -516,7 +516,7 @@ void ProjectExportDialog::_script_encryption_key_changed(const String &p_key) { bool ProjectExportDialog::_validate_script_encryption_key(const String &p_key) { bool is_valid = false; - if (!p_key.empty() && p_key.is_valid_hex_number(false) && p_key.length() == 64) { + if (!p_key.is_empty() && p_key.is_valid_hex_number(false) && p_key.length() == 64) { is_valid = true; } return is_valid; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index ad0c9532d8..6e32445124 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1545,7 +1545,7 @@ bool ProjectList::is_any_project_missing() const { } void ProjectList::erase_missing_projects() { - if (_projects.empty()) { + if (_projects.is_empty()) { return; } @@ -1824,7 +1824,7 @@ void ProjectManager::_notification(int p_what) { switch (p_what) { case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { - settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT); + settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT); update(); } break; case NOTIFICATION_ENTER_TREE: { @@ -1875,7 +1875,7 @@ void ProjectManager::_dim_window() { void ProjectManager::_update_project_buttons() { Vector<ProjectList::Item> selected_projects = _project_list->get_selected_projects(); - bool empty_selection = selected_projects.empty(); + bool empty_selection = selected_projects.is_empty(); bool is_missing_project_selected = false; for (int i = 0; i < selected_projects.size(); ++i) { @@ -2440,19 +2440,19 @@ ProjectManager::ProjectManager() { FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); - set_anchors_and_margins_preset(Control::PRESET_WIDE); + set_anchors_and_offsets_preset(Control::PRESET_WIDE); set_theme(create_custom_theme()); - set_anchors_and_margins_preset(Control::PRESET_WIDE); + set_anchors_and_offsets_preset(Control::PRESET_WIDE); Panel *panel = memnew(Panel); add_child(panel); - panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); + panel->set_anchors_and_offsets_preset(Control::PRESET_WIDE); panel->add_theme_style_override("panel", get_theme_stylebox("Background", "EditorStyles")); VBoxContainer *vb = memnew(VBoxContainer); panel->add_child(vb); - vb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE); + vb->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE); Control *center_box = memnew(Control); center_box->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -2460,7 +2460,7 @@ ProjectManager::ProjectManager() { tabs = memnew(TabContainer); center_box->add_child(tabs); - tabs->set_anchors_and_margins_preset(Control::PRESET_WIDE); + tabs->set_anchors_and_offsets_preset(Control::PRESET_WIDE); tabs->set_tab_align(TabContainer::ALIGN_LEFT); HBoxContainer *projects_hb = memnew(HBoxContainer); @@ -2571,7 +2571,7 @@ ProjectManager::ProjectManager() { settings_hb = memnew(HBoxContainer); settings_hb->set_alignment(BoxContainer::ALIGN_END); settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN); - settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT); + settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT); Label *version_label = memnew(Label); String hash = String(VERSION_HASH); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 9995c6ad65..a294a64dbe 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -156,7 +156,7 @@ void ProjectSettingsEditor::_update_advanced_bar() { bool disable_add = true; bool disable_del = true; - if (!property_box->get_text().empty()) { + if (!property_box->get_text().is_empty()) { const String setting = _get_setting_name(); bool setting_exists = ps->has_setting(setting); if (setting_exists) { @@ -197,7 +197,7 @@ void ProjectSettingsEditor::_update_advanced_bar() { String ProjectSettingsEditor::_get_setting_name() const { const String cat = category_box->get_text(); - const String name = (cat.empty() ? "global" : cat.strip_edges()).plus_file(property_box->get_text().strip_edges()); + const String name = (cat.is_empty() ? "global" : cat.strip_edges()).plus_file(property_box->get_text().strip_edges()); const String feature = feature_override->get_item_text(feature_override->get_selected()); return (feature == "") ? name : (name + "." + feature); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 847af0f2c2..9a58a23cb0 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -251,7 +251,7 @@ void CustomPropertyEditor::_menu_option(int p_which) { emit_signal("variant_changed"); break; } - ERR_FAIL_COND(inheritors_array.empty()); + ERR_FAIL_COND(inheritors_array.is_empty()); String intype = inheritors_array[p_which - TYPE_BASE_ID]; @@ -367,18 +367,18 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: int c = hint_text.get_slice_count(","); float min = 0, max = 100, step = type == Variant::FLOAT ? .01 : 1; if (c >= 1) { - if (!hint_text.get_slice(",", 0).empty()) { + if (!hint_text.get_slice(",", 0).is_empty()) { min = hint_text.get_slice(",", 0).to_float(); } } if (c >= 2) { - if (!hint_text.get_slice(",", 1).empty()) { + if (!hint_text.get_slice(",", 1).is_empty()) { max = hint_text.get_slice(",", 1).to_float(); } } if (c >= 3) { - if (!hint_text.get_slice(",", 2).empty()) { + if (!hint_text.get_slice(",", 2).is_empty()) { step = hint_text.get_slice(",", 2).to_float(); } } @@ -456,14 +456,14 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: set_size(Vector2(4, 4) * EDSCALE + checks20gc->get_position() + checks20gc->get_size()); } else if (hint == PROPERTY_HINT_EXP_EASING) { - easing_draw->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 5 * EDSCALE); - easing_draw->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -5 * EDSCALE); - easing_draw->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 5 * EDSCALE); - easing_draw->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -30 * EDSCALE); - type_button->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 3 * EDSCALE); - type_button->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -3 * EDSCALE); - type_button->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_END, -25 * EDSCALE); - type_button->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -7 * EDSCALE); + easing_draw->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5 * EDSCALE); + easing_draw->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5 * EDSCALE); + easing_draw->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_BEGIN, 5 * EDSCALE); + easing_draw->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -30 * EDSCALE); + type_button->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 3 * EDSCALE); + type_button->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -3 * EDSCALE); + type_button->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_END, -25 * EDSCALE); + type_button->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -7 * EDSCALE); type_button->set_text(TTR("Preset...")); type_button->get_popup()->clear(); type_button->get_popup()->add_item(TTR("Linear"), EASING_LINEAR); @@ -536,10 +536,10 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: int button_margin = text_edit->get_theme_constant("button_margin", "Dialogs"); int margin = text_edit->get_theme_constant("margin", "Dialogs"); - action_buttons[0]->set_anchor(MARGIN_LEFT, Control::ANCHOR_END); - action_buttons[0]->set_anchor(MARGIN_TOP, Control::ANCHOR_END); - action_buttons[0]->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END); - action_buttons[0]->set_anchor(MARGIN_BOTTOM, Control::ANCHOR_END); + action_buttons[0]->set_anchor(SIDE_LEFT, Control::ANCHOR_END); + action_buttons[0]->set_anchor(SIDE_TOP, Control::ANCHOR_END); + action_buttons[0]->set_anchor(SIDE_RIGHT, Control::ANCHOR_END); + action_buttons[0]->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END); action_buttons[0]->set_begin(Point2(-70 * EDSCALE, -button_margin + 5 * EDSCALE)); action_buttons[0]->set_end(Point2(-margin, -margin)); action_buttons[0]->set_text(TTR("Close")); @@ -882,7 +882,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: bool is_custom_resource = false; Ref<Texture2D> icon; - if (!custom_resources.empty()) { + if (!custom_resources.is_empty()) { for (int k = 0; k < custom_resources.size(); k++) { if (custom_resources[k].name == t) { is_custom_resource = true; @@ -1246,7 +1246,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) { } break; case Variant::OBJECT: { if (p_which == 0) { - ERR_FAIL_COND(inheritors_array.empty()); + ERR_FAIL_COND(inheritors_array.is_empty()); String intype = inheritors_array[0]; @@ -1661,10 +1661,10 @@ void CustomPropertyEditor::_focus_exit() { void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) { Ref<StyleBox> sb = action_buttons[0]->get_theme_stylebox("panel"); - int margin_top = sb->get_margin(MARGIN_TOP); - int margin_left = sb->get_margin(MARGIN_LEFT); - int margin_bottom = sb->get_margin(MARGIN_BOTTOM); - int margin_right = sb->get_margin(MARGIN_RIGHT); + int margin_top = sb->get_margin(SIDE_TOP); + int margin_left = sb->get_margin(SIDE_LEFT); + int margin_bottom = sb->get_margin(SIDE_BOTTOM); + int margin_right = sb->get_margin(SIDE_RIGHT); int max_width = 0; int height = 0; @@ -1794,8 +1794,8 @@ CustomPropertyEditor::CustomPropertyEditor() { text_edit = memnew(TextEdit); add_child(text_edit); - text_edit->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); - text_edit->set_margin(MARGIN_BOTTOM, -30); + text_edit->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); + text_edit->set_offset(SIDE_BOTTOM, -30); text_edit->hide(); text_edit->connect("text_changed", callable_mp(this, &CustomPropertyEditor::_text_edit_changed)); @@ -1853,12 +1853,12 @@ CustomPropertyEditor::CustomPropertyEditor() { spinbox = memnew(SpinBox); add_child(spinbox); - spinbox->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); + spinbox->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); spinbox->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified)); slider = memnew(HSlider); add_child(slider); - slider->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); + slider->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); slider->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified)); create_dialog = nullptr; diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index a60937a86b..379faf2131 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -572,7 +572,7 @@ void RenameDialog::rename() { // Forward recursive as opposed to the actual renaming. _iterate_scene(root_node, selected_node_list, &global_count); - if (undo_redo && !to_rename.empty()) { + if (undo_redo && !to_rename.is_empty()) { undo_redo->create_action(TTR("Batch Rename")); // Make sure to iterate reversed so that child nodes will find parents. diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 72703623ab..89750f6043 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -361,7 +361,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (current_edited_scene_root) { String root_class = current_edited_scene_root->get_class_name(); static Vector<String> preferred_types; - if (preferred_types.empty()) { + if (preferred_types.is_empty()) { preferred_types.push_back("Control"); preferred_types.push_back("Node2D"); preferred_types.push_back("Node3D"); @@ -416,7 +416,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } Node *selected = scene_tree->get_selected(); - if (!selected && !editor_selection->get_selected_node_list().empty()) { + if (!selected && !editor_selection->get_selected_node_list().is_empty()) { selected = editor_selection->get_selected_node_list().front()->get(); } @@ -438,7 +438,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Array selection = editor_selection->get_selected_nodes(); - if (selection.empty()) { + if (selection.is_empty()) { return; } @@ -737,7 +737,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { List<Node *> remove_list = editor_selection->get_selected_node_list(); - if (remove_list.empty()) { + if (remove_list.is_empty()) { return; } @@ -1015,7 +1015,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; case TOOL_CREATE_USER_INTERFACE: { Control *node = memnew(Control); - node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs. + node->set_anchors_and_offsets_preset(PRESET_WIDE); //more useful for resizable UIs. new_node = node; } break; @@ -1107,7 +1107,7 @@ void SceneTreeDock::_notification(int p_what) { node_shortcuts_toggle->set_toggle_mode(true); node_shortcuts_toggle->set_tooltip(TTR("Switch to Favorite Nodes")); node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection")); - node_shortcuts_toggle->set_anchors_and_margins_preset(Control::PRESET_CENTER_RIGHT); + node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT); node_shortcuts_toggle->connect("pressed", callable_mp(this, &SceneTreeDock::_update_create_root_dialog)); top_row->add_child(node_shortcuts_toggle); @@ -1529,7 +1529,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()) { + if (selection.is_empty()) { return; // Nothing to reparent. } @@ -1703,7 +1703,7 @@ bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const { List<TreeItem *> needs_check; needs_check.push_back(p_item); - while (!needs_check.empty()) { + while (!needs_check.is_empty()) { TreeItem *item = needs_check.back()->get(); needs_check.pop_back(); @@ -1725,7 +1725,7 @@ void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed) List<TreeItem *> to_collapse; to_collapse.push_back(p_item); - while (!to_collapse.empty()) { + while (!to_collapse.is_empty()) { TreeItem *item = to_collapse.back()->get(); to_collapse.pop_back(); @@ -1742,7 +1742,7 @@ void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed) void SceneTreeDock::_script_created(Ref<Script> p_script) { List<Node *> selected = editor_selection->get_selected_node_list(); - if (selected.empty()) { + if (selected.is_empty()) { return; } @@ -1811,7 +1811,7 @@ void SceneTreeDock::_toggle_editable_children(Node *p_node) { void SceneTreeDock::_delete_confirm() { List<Node *> remove_list = editor_selection->get_selected_node_list(); - if (remove_list.empty()) { + if (remove_list.is_empty()) { return; } @@ -2349,7 +2349,7 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) { void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) { List<Node *> selection = editor_selection->get_selected_node_list(); - if (selection.empty()) { + if (selection.is_empty()) { return; //nothing to reparent } @@ -2601,7 +2601,7 @@ void SceneTreeDock::attach_script_to_selected(bool p_extend) { } List<Node *> selection = editor_selection->get_selected_node_list(); - if (selection.empty()) { + if (selection.is_empty()) { return; } diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 685833da55..f30ad02f5e 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -251,7 +251,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { if (can_rename) { //should be can edit.. String warning = p_node->get_configuration_warning(); - if (!warning.empty()) { + if (!warning.is_empty()) { item->add_button(0, get_theme_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning()); } @@ -754,7 +754,7 @@ void SceneTreeEditor::_renamed() { ERR_FAIL_COND(!n); // Empty node names are not allowed, so resets it to previous text and show warning - if (which->get_text(0).strip_edges().empty()) { + if (which->get_text(0).strip_edges().is_empty()) { which->set_text(0, n->get_name()); EditorNode::get_singleton()->show_warning(TTR("No name provided.")); return; @@ -765,7 +765,7 @@ void SceneTreeEditor::_renamed() { error->set_text(TTR("Invalid node name, the following characters are not allowed:") + "\n" + Node::invalid_character); error->popup_centered(); - if (new_name.empty()) { + if (new_name.is_empty()) { which->set_text(0, n->get_name()); return; } @@ -931,7 +931,7 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from next = tree->get_next_selected(next); } - if (selected.empty()) { + if (selected.is_empty()) { return Variant(); } @@ -1150,8 +1150,8 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope } tree = memnew(Tree); - tree->set_anchor(MARGIN_RIGHT, ANCHOR_END); - tree->set_anchor(MARGIN_BOTTOM, ANCHOR_END); + tree->set_anchor(SIDE_RIGHT, ANCHOR_END); + tree->set_anchor(SIDE_BOTTOM, ANCHOR_END); tree->set_begin(Point2(0, p_label ? 18 : 0)); tree->set_end(Point2(0, 0)); tree->add_theme_constant_override("button_margin", 0); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 9c3e381dc8..7fd2613c1e 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -50,7 +50,7 @@ void ScriptCreateDialog::_theme_changed() { } String last_lang = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", ""); - if (!last_lang.empty()) { + if (!last_lang.is_empty()) { for (int i = 0; i < language_menu->get_item_count(); i++) { if (language_menu->get_item_text(i) == last_lang) { language_menu->select(i); @@ -568,6 +568,8 @@ void ScriptCreateDialog::_create() { void ScriptCreateDialog::_browse_class_in_tree() { select_class->set_base_type(base_type); select_class->popup_create(true); + select_class->set_title(vformat(TTR("Inherit %s"), base_type)); + select_class->get_ok_button()->set_text(TTR("Inherit")); } void ScriptCreateDialog::_path_changed(const String &p_path) { diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index a29b6aded7..c152c2625f 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -471,10 +471,10 @@ EditorSettingsDialog::EditorSettingsDialog() { Label *l = memnew(Label); l->set_text(TTR("Press a Key...")); - l->set_anchors_and_margins_preset(Control::PRESET_WIDE); + l->set_anchors_and_offsets_preset(Control::PRESET_WIDE); l->set_align(Label::ALIGN_CENTER); - l->set_margin(MARGIN_TOP, 20); - l->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_BEGIN, 30); + l->set_offset(SIDE_TOP, 20); + l->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_BEGIN, 30); press_a_key_label = l; press_a_key->add_child(l); press_a_key->connect("window_input", callable_mp(this, &EditorSettingsDialog::_wait_for_key)); |