diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index cc5b2921af5..bf09e39347c 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -760,7 +760,7 @@ int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { unsigned int hour = ((datetime.has(HOUR_KEY)) ? static_cast(datetime[HOUR_KEY]) : 0); unsigned int day = ((datetime.has(DAY_KEY)) ? static_cast(datetime[DAY_KEY]) : 1); unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast(datetime[MONTH_KEY]) : 1); - unsigned int year = ((datetime.has(YEAR_KEY)) ? static_cast(datetime[YEAR_KEY]) : 0); + unsigned int year = ((datetime.has(YEAR_KEY)) ? static_cast(datetime[YEAR_KEY]) : 1970); /// How many days come before each month (0-12) static const unsigned short int DAYS_PAST_THIS_YEAR_TABLE[2][13] = { @@ -771,15 +771,14 @@ int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { }; ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + "."); - ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); - ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); - + ERR_FAIL_COND_V_MSG(year == 0, 0, "Years before 1 AD are not supported. Value passed: " + itos(year) + "."); ERR_FAIL_COND_V_MSG(month > 12 || month == 0, 0, "Invalid month value of: " + itos(month) + "."); - // Do this check after month is tested as valid - ERR_FAIL_COND_V_MSG(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1] || day == 0, 0, "Invalid day value of '" + itos(day) + "' which is larger than '" + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]) + "' or 0."); + unsigned int days_in_month = MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]; + ERR_FAIL_COND_V_MSG(day == 0 || day > days_in_month, 0, "Invalid day value of: " + itos(day) + ". It should be comprised between 1 and " + itos(days_in_month) + " for month " + itos(month) + "."); + // Calculate all the seconds from months past in this year uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY; diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 2f0790570c2..45694757d81 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -550,7 +550,7 @@ Gets an epoch time value from a dictionary of time values. [code]datetime[/code] must be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], [code]second[/code]. - If the dictionary is empty [code]0[/code] is returned. + If the dictionary is empty [code]0[/code] is returned. If some keys are omitted, they default to the equivalent values for the UNIX epoch timestamp 0 (1970-01-01 at 00:00:00 UTC). You can pass the output from [method get_datetime_from_unix_time] directly into this function. Daylight Savings Time ([code]dst[/code]), if present, is ignored. diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index b7bc8b6d15e..d7e40819688 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -27,6 +27,7 @@ Duplicates the resource, returning a new resource. By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [code]subresources[/code] argument which will copy the subresources. [b]Note:[/b] If [code]subresources[/code] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared. + [b]Note:[/b] When duplicating a resource, only [code]export[/code]ed properties are copied. Other properties will be set to their default value in the new resource. diff --git a/doc/classes/TextureButton.xml b/doc/classes/TextureButton.xml index f11c5200024..8f8aca1f49a 100644 --- a/doc/classes/TextureButton.xml +++ b/doc/classes/TextureButton.xml @@ -17,6 +17,12 @@ If [code]true[/code], the texture stretches to the edges of the node's bounding rectangle using the [member stretch_mode]. If [code]false[/code], the texture will not scale with the node. + + If [code]true[/code], texture is flipped horizontally. + + + If [code]true[/code], texture is flipped vertically. + Controls the texture's behavior when you resize the node's bounding rectangle, [b]only if[/b] [member expand] is [code]true[/code]. Set it to one of the [enum StretchMode] constants. See the constants to learn more. diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 6ac491f6d0f..4d0ea16a3ab 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -432,7 +432,7 @@ uint64_t DirAccessUnix::get_space_left() { return 0; }; - return vfs.f_bfree * vfs.f_bsize; + return (uint64_t)vfs.f_bavail * (uint64_t)vfs.f_frsize; #else // FIXME: Implement this. return 0; diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 68d1e6d5d3f..fae282239ac 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -173,6 +173,9 @@ void EditorAudioBus::_notification(int p_what) { bypass->set_icon(get_icon("AudioBusBypass", "EditorIcons")); bus_options->set_icon(get_icon("GuiTabMenuHl", "EditorIcons")); + + audio_value_preview_box->add_color_override("font_color", get_color("font_color", "TooltipLabel")); + audio_value_preview_box->add_style_override("panel", get_stylebox("panel", "TooltipPanel")); } break; case NOTIFICATION_MOUSE_EXIT: case NOTIFICATION_DRAG_END: { @@ -379,15 +382,24 @@ void EditorAudioBus::_show_value(float slider_value) { db = _normalized_volume_to_scaled_db(slider_value); } - String text = vformat("%10.1f dB", db); + String text; + if (Math::is_zero_approx(Math::stepify(db, 0.1))) { + // Prevent displaying `-0.0 dB` and show ` 0.0 dB` instead. + // The leading space makes the text visually line up with its positive/negative counterparts. + text = " 0.0 dB"; + } else { + // Show an explicit `+` sign if positive. + text = vformat("%+.1f dB", db); + } + // Also set the preview text as a standard Control tooltip. + // This way, it can be seen when the slider is merely hovered (instead of dragged). slider->set_tooltip(text); audio_value_preview_label->set_text(text); - Vector2 slider_size = slider->get_size(); - Vector2 slider_position = slider->get_global_position(); - float left_padding = 5.0f; - float vert_padding = 10.0f; - Vector2 box_position = Vector2(slider_size.x + left_padding, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding); + const Vector2 slider_size = slider->get_size(); + const Vector2 slider_position = slider->get_global_position(); + const float vert_padding = 10.0f; + const Vector2 box_position = Vector2(slider_size.x, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding); audio_value_preview_box->set_position(slider_position + box_position); audio_value_preview_box->set_size(audio_value_preview_label->get_size()); if (slider->has_focus() && !audio_value_preview_box->is_visible()) { @@ -818,7 +830,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { bus_options = memnew(MenuButton); bus_options->set_h_size_flags(SIZE_SHRINK_END); bus_options->set_anchor(MARGIN_RIGHT, 0.0); - bus_options->set_tooltip(TTR("Bus options")); + bus_options->set_tooltip(TTR("Bus Options")); hbc->add_child(bus_options); Ref sbempty = memnew(StyleBoxEmpty); @@ -853,14 +865,13 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { audio_value_preview_label->set_v_size_flags(SIZE_EXPAND_FILL); audio_value_preview_label->set_h_size_flags(SIZE_EXPAND_FILL); audio_value_preview_label->set_mouse_filter(MOUSE_FILTER_PASS); + audio_value_preview_box->add_color_override("font_color", get_color("font_color", "TooltipLabel")); audioprev_hbc->add_child(audio_value_preview_label); slider->add_child(audio_value_preview_box); audio_value_preview_box->set_as_toplevel(true); - Ref panel_style = memnew(StyleBoxFlat); - panel_style->set_bg_color(Color(0.0f, 0.0f, 0.0f, 0.8f)); - audio_value_preview_box->add_style_override("panel", panel_style); + audio_value_preview_box->add_style_override("panel", get_stylebox("panel", "TooltipPanel")); audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS); audio_value_preview_box->hide(); @@ -1427,7 +1438,7 @@ void EditorAudioMeterNotches::_bind_methods() { void EditorAudioMeterNotches::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - notch_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(0, 0, 0); + notch_color = get_color("font_color", "Editor"); } break; case NOTIFICATION_DRAW: { _draw_audio_notches(); @@ -1442,13 +1453,13 @@ void EditorAudioMeterNotches::_draw_audio_notches() { for (int i = 0; i < notches.size(); i++) { AudioNotch n = notches[i]; draw_line(Vector2(0, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding), - Vector2(line_length, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding), + Vector2(line_length * EDSCALE, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding), notch_color, - 1); + Math::round(EDSCALE)); if (n.render_db_value) { draw_string(font, - Vector2(line_length + label_space, + Vector2((line_length + label_space) * EDSCALE, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + (font_height / 4) + top_padding), String::num(Math::abs(n.db_value)) + "dB", notch_color); @@ -1456,10 +1467,6 @@ void EditorAudioMeterNotches::_draw_audio_notches() { } } -EditorAudioMeterNotches::EditorAudioMeterNotches() : - line_length(5.0f), - label_space(2.0f), - btm_padding(9.0f), - top_padding(5.0f) { - notch_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(0, 0, 0); +EditorAudioMeterNotches::EditorAudioMeterNotches() { + notch_color = get_color("font_color", "Editor"); } diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h index b971046ee74..ff3bccdee6c 100644 --- a/editor/editor_audio_buses.h +++ b/editor/editor_audio_buses.h @@ -244,10 +244,10 @@ private: List notches; public: - float line_length; - float label_space; - float btm_padding; - float top_padding; + const float line_length = 5.0f; + const float label_space = 2.0f; + const float btm_padding = 9.0f; + const float top_padding = 5.0f; Color notch_color; void add_notch(float p_normalized_offset, float p_db_value, bool p_render_value = false); diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index c870c963dec..22a683038aa 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -116,6 +116,18 @@ bool EditorFeatureProfile::has_class_properties_disabled(const StringName &p_cla return disabled_properties.has(p_class); } +void EditorFeatureProfile::set_item_collapsed(const StringName &p_class, bool p_collapsed) { + if (p_collapsed) { + collapsed_classes.insert(p_class); + } else { + collapsed_classes.erase(p_class); + } +} + +bool EditorFeatureProfile::is_item_collapsed(const StringName &p_class) const { + return collapsed_classes.has(p_class); +} + void EditorFeatureProfile::set_disable_feature(Feature p_feature, bool p_disable) { ERR_FAIL_INDEX(p_feature, FEATURE_MAX); features_disabled[p_feature] = p_disable; @@ -478,6 +490,9 @@ void EditorFeatureProfileManager::_fill_classes_from(TreeItem *p_parent, const S class_item->set_selectable(0, true); class_item->set_metadata(0, p_class); + bool collapsed = edited->is_item_collapsed(p_class); + class_item->set_collapsed(collapsed); + if (p_class == p_selected) { class_item->select(0); } @@ -590,6 +605,26 @@ void EditorFeatureProfileManager::_class_list_item_edited() { } } +void EditorFeatureProfileManager::_class_list_item_collapsed(Object *p_item) { + if (updating_features) { + return; + } + + TreeItem *item = Object::cast_to(p_item); + if (!item) { + return; + } + + Variant md = item->get_metadata(0); + if (md.get_type() != Variant::STRING) { + return; + } + + String class_name = md; + bool collapsed = item->is_collapsed(); + edited->set_item_collapsed(class_name, collapsed); +} + void EditorFeatureProfileManager::_property_item_edited() { if (updating_features) { return; @@ -781,6 +816,7 @@ void EditorFeatureProfileManager::_bind_methods() { ClassDB::bind_method("_export_profile", &EditorFeatureProfileManager::_export_profile); ClassDB::bind_method("_class_list_item_selected", &EditorFeatureProfileManager::_class_list_item_selected); ClassDB::bind_method("_class_list_item_edited", &EditorFeatureProfileManager::_class_list_item_edited); + ClassDB::bind_method("_class_list_item_collapsed", &EditorFeatureProfileManager::_class_list_item_collapsed); ClassDB::bind_method("_property_item_edited", &EditorFeatureProfileManager::_property_item_edited); ClassDB::bind_method("_emit_current_profile_changed", &EditorFeatureProfileManager::_emit_current_profile_changed); @@ -852,6 +888,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); class_list->connect("cell_selected", this, "_class_list_item_selected"); class_list->connect("item_edited", this, "_class_list_item_edited", varray(), CONNECT_DEFERRED); + class_list->connect("item_collapsed", this, "_class_list_item_collapsed"); VBoxContainer *property_list_vbc = memnew(VBoxContainer); h_split->add_child(property_list_vbc); diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h index 4ab263942f1..b160877739a 100644 --- a/editor/editor_feature_profile.h +++ b/editor/editor_feature_profile.h @@ -60,6 +60,8 @@ private: Set disabled_editors; Map> disabled_properties; + Set collapsed_classes; + bool features_disabled[FEATURE_MAX]; static const char *feature_names[FEATURE_MAX]; static const char *feature_identifiers[FEATURE_MAX]; @@ -80,6 +82,9 @@ public: bool is_class_property_disabled(const StringName &p_class, const StringName &p_property) const; bool has_class_properties_disabled(const StringName &p_class) const; + void set_item_collapsed(const StringName &p_class, bool p_collapsed); + bool is_item_collapsed(const StringName &p_class) const; + void set_disable_feature(Feature p_feature, bool p_disable); bool is_feature_disabled(Feature p_feature) const; @@ -148,6 +153,7 @@ class EditorFeatureProfileManager : public AcceptDialog { void _class_list_item_selected(); void _class_list_item_edited(); + void _class_list_item_collapsed(Object *p_item); void _property_item_edited(); void _save_and_update(); diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index accc480cb76..5699a5a84f4 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -209,6 +209,7 @@ PluginConfigDialog::PluginConfigDialog() { desc_edit = memnew(TextEdit); desc_edit->set_custom_minimum_size(Size2(400, 80) * EDSCALE); + desc_edit->set_wrap_enabled(true); grid->add_child(desc_edit); Label *author_lb = memnew(Label); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 76e71aef776..6f4fd1d291e 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -5252,8 +5252,10 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method("_popup_warning_depop", &CanvasItemEditor::_popup_warning_depop); ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed); ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide); + ClassDB::bind_method(D_METHOD("get_state"), &CanvasItemEditor::get_state); ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state); ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport); + ClassDB::bind_method(D_METHOD("_zoom_on_position"), &CanvasItemEditor::_zoom_on_position); ADD_SIGNAL(MethodInfo("item_lock_status_changed")); ADD_SIGNAL(MethodInfo("item_group_status_changed")); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index e603ab76818..3e379197e9a 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -31,6 +31,7 @@ #include "script_text_editor.h" #include "core/math/expression.h" +#include "core/os/input.h" #include "core/os/keyboard.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" @@ -1506,11 +1507,17 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data Array files = d["files"]; String text_to_drop; + bool preload = Input::get_singleton()->is_key_pressed(KEY_CONTROL); for (int i = 0; i < files.size(); i++) { if (i > 0) { - text_to_drop += ","; + text_to_drop += ", "; + } + + if (preload) { + text_to_drop += "preload(\"" + String(files[i]).c_escape() + "\")"; + } else { + text_to_drop += "\"" + String(files[i]).c_escape() + "\""; } - text_to_drop += "\"" + String(files[i]).c_escape() + "\""; } te->cursor_set_line(row); diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index 5e397dbdba7..fd609a73e8c 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -247,7 +247,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 10.0; OTHER_LDFLAGS = "$linker_flags"; SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "$targeted_device_family"; }; name = Debug; }; @@ -286,7 +286,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 10.0; OTHER_LDFLAGS = "$linker_flags"; SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "$targeted_device_family"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -315,7 +315,7 @@ PRODUCT_BUNDLE_IDENTIFIER = $identifier; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "$provisioning_profile_uuid_debug"; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "$targeted_device_family"; VALID_ARCHS = "armv7 armv7s arm64 i386 x86_64"; WRAPPER_EXTENSION = app; }; @@ -345,7 +345,7 @@ PRODUCT_BUNDLE_IDENTIFIER = $identifier; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "$provisioning_profile_uuid_release"; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "$targeted_device_family"; VALID_ARCHS = "armv7 armv7s arm64 i386 x86_64"; WRAPPER_EXTENSION = app; }; diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme b/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme index b6beeb012fe..d61a53d5c2c 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme @@ -23,7 +23,7 @@ @@ -42,7 +42,7 @@ + buildConfiguration = "$default_build_config"> diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp index 5a2a569830e..6956481db0c 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.cpp +++ b/modules/gdnative/pluginscript/pluginscript_script.cpp @@ -203,6 +203,8 @@ ScriptInstance *PluginScript::instance_create(Object *p_this) { } bool PluginScript::instance_has(const Object *p_this) const { + ERR_FAIL_COND_V(!_language, false); + _language->lock(); bool hasit = _instances.has((Object *)p_this); _language->unlock(); diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml index 0eddcf4e571..709f97e6c91 100644 --- a/modules/opensimplex/doc_classes/NoiseTexture.xml +++ b/modules/opensimplex/doc_classes/NoiseTexture.xml @@ -31,6 +31,9 @@ The [OpenSimplexNoise] instance used to generate the noise. + + An offset used to specify the noise space coordinate of the top left corner of the generated noise. This value is ignored if [member seamless] is enabled. + Whether the texture can be tiled without visible seams or not. Seamless textures take longer to generate. [b]Note:[/b] Seamless noise has a lower contrast compared to non-seamless noise. This is due to the way noise uses higher dimensions for generating seamless noise. diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml index 835bfafc891..4fd4d65a28e 100644 --- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml +++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml @@ -31,8 +31,10 @@ + + - Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. + Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. If [code]noise_offset[/code] is specified, then the offset value is used as the coordinates of the top-left corner of the generated noise. diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp index f473ff4f3e4..558c2de5019 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/opensimplex/noise_texture.cpp @@ -62,6 +62,9 @@ void NoiseTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise); ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise); + ClassDB::bind_method(D_METHOD("set_noise_offset", "noise_offset"), &NoiseTexture::set_noise_offset); + ClassDB::bind_method(D_METHOD("get_noise_offset"), &NoiseTexture::get_noise_offset); + ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless); ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless); @@ -82,6 +85,7 @@ void NoiseTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normalmap"), "set_as_normalmap", "is_normalmap"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bump_strength", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_bump_strength", "get_bump_strength"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_noise", "get_noise"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "noise_offset"), "set_noise_offset", "get_noise_offset"); } void NoiseTexture::_validate_property(PropertyInfo &property) const { @@ -137,7 +141,7 @@ Ref NoiseTexture::_generate_texture() { if (seamless) { image = ref_noise->get_seamless_image(size.x); } else { - image = ref_noise->get_image(size.x, size.y); + image = ref_noise->get_image(size.x, size.y, noise_offset); } if (as_normalmap) { @@ -205,6 +209,14 @@ void NoiseTexture::set_height(int p_height) { _queue_update(); } +void NoiseTexture::set_noise_offset(Vector2 p_noise_offset) { + if (noise_offset == p_noise_offset) { + return; + } + noise_offset = p_noise_offset; + _queue_update(); +} + void NoiseTexture::set_seamless(bool p_seamless) { if (p_seamless == seamless) { return; @@ -252,6 +264,10 @@ int NoiseTexture::get_height() const { return size.y; } +Vector2 NoiseTexture::get_noise_offset() const { + return noise_offset; +} + void NoiseTexture::set_flags(uint32_t p_flags) { flags = p_flags; VS::get_singleton()->texture_set_flags(texture, flags); diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h index 6fa8c12d640..ce054b3ba1c 100644 --- a/modules/opensimplex/noise_texture.h +++ b/modules/opensimplex/noise_texture.h @@ -56,6 +56,7 @@ private: Ref noise; Vector2i size; + Vector2 noise_offset; bool seamless; bool as_normalmap; float bump_strength; @@ -79,6 +80,9 @@ public: void set_width(int p_width); void set_height(int p_height); + void set_noise_offset(Vector2 p_noise_offset); + Vector2 get_noise_offset() const; + void set_seamless(bool p_seamless); bool get_seamless(); diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp index ff637f95e99..e07a888ffb7 100644 --- a/modules/opensimplex/open_simplex_noise.cpp +++ b/modules/opensimplex/open_simplex_noise.cpp @@ -102,7 +102,7 @@ void OpenSimplexNoise::set_lacunarity(float p_lacunarity) { emit_changed(); } -Ref OpenSimplexNoise::get_image(int p_width, int p_height) const { +Ref OpenSimplexNoise::get_image(int p_width, int p_height, const Vector2 &p_noise_offset) const { PoolVector data; data.resize(p_width * p_height); @@ -110,7 +110,7 @@ Ref OpenSimplexNoise::get_image(int p_width, int p_height) const { for (int i = 0; i < p_height; i++) { for (int j = 0; j < p_width; j++) { - float v = get_noise_2d(i, j); + float v = get_noise_2d(float(j) + p_noise_offset.x, float(i) + p_noise_offset.y); v = v * 0.5 + 0.5; // Normalize [0..1] wd8[(i * p_width + j)] = uint8_t(CLAMP(v * 255.0, 0, 255)); } @@ -167,7 +167,7 @@ void OpenSimplexNoise::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lacunarity", "lacunarity"), &OpenSimplexNoise::set_lacunarity); ClassDB::bind_method(D_METHOD("get_lacunarity"), &OpenSimplexNoise::get_lacunarity); - ClassDB::bind_method(D_METHOD("get_image", "width", "height"), &OpenSimplexNoise::get_image); + ClassDB::bind_method(D_METHOD("get_image", "width", "height", "noise_offset"), &OpenSimplexNoise::get_image, DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("get_seamless_image", "size"), &OpenSimplexNoise::get_seamless_image); ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &OpenSimplexNoise::get_noise_1d); diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h index 759159793bc..82aa3e317d2 100644 --- a/modules/opensimplex/open_simplex_noise.h +++ b/modules/opensimplex/open_simplex_noise.h @@ -75,7 +75,7 @@ public: void set_lacunarity(float p_lacunarity); float get_lacunarity() const { return lacunarity; } - Ref get_image(int p_width, int p_height) const; + Ref get_image(int p_width, int p_height, const Vector2 &p_noise_offset = Vector2()) const; Ref get_seamless_image(int p_size) const; float get_noise_1d(float x) const; diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 3a2a3d34d36..9a8a8df951b 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -134,6 +134,7 @@ bool VisualScriptBuiltinFunc::has_input_sequence_port() const { case TEXT_PRINT: case TEXT_PRINTERR: case TEXT_PRINTRAW: + case MATH_SEED: return true; default: return false; diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 923c2b15d9b..7cdfd6f16de 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -352,6 +352,8 @@ void EditorExportPlatformIOS::get_export_options(List *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_release", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Distribution"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_release", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/targeted_device_family", PROPERTY_HINT_ENUM, "iPhone,iPad,iPhone & iPad"), 2)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); @@ -444,6 +446,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; } else if (lines[i].find("$team_id") != -1) { strnew += lines[i].replace("$team_id", p_preset->get("application/app_store_team_id")) + "\n"; + } else if (lines[i].find("$default_build_config") != -1) { + strnew += lines[i].replace("$default_build_config", p_debug ? "Debug" : "Release") + "\n"; } else if (lines[i].find("$export_method") != -1) { int export_method = p_preset->get(p_debug ? "application/export_method_debug" : "application/export_method_release"); strnew += lines[i].replace("$export_method", export_method_string[export_method]) + "\n"; @@ -464,6 +468,20 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ strnew += lines[i].replace("$godot_archs", p_config.architectures) + "\n"; } else if (lines[i].find("$linker_flags") != -1) { strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n"; + } else if (lines[i].find("$targeted_device_family") != -1) { + String xcode_value; + switch ((int)p_preset->get("application/targeted_device_family")) { + case 0: // iPhone + xcode_value = "1"; + break; + case 1: // iPad + xcode_value = "2"; + break; + case 2: // iPhone & iPad + xcode_value = "1,2"; + break; + } + strnew += lines[i].replace("$targeted_device_family", xcode_value) + "\n"; } else if (lines[i].find("$cpp_code") != -1) { strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n"; } else if (lines[i].find("$docs_in_place") != -1) { diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index c38544404a5..f070191a11f 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -272,11 +272,10 @@ void Camera2D::_notification(int p_what) { } if (screen_drawing_enabled) { - Color area_axis_color(0.5, 0.42, 0.87, 0.63); + Color area_axis_color(1, 0.4, 1, 0.63); float area_axis_width = 1; if (is_current()) { area_axis_width = 3; - area_axis_color.a = 0.83; } Transform2D inv_camera_transform = get_camera_transform().affine_inverse(); @@ -297,10 +296,9 @@ void Camera2D::_notification(int p_what) { } if (limit_drawing_enabled) { - Color limit_drawing_color(1, 1, 0, 0.63); + Color limit_drawing_color(1, 1, 0.25, 0.63); float limit_drawing_width = 1; if (is_current()) { - limit_drawing_color.a = 0.83; limit_drawing_width = 3; } @@ -319,11 +317,10 @@ void Camera2D::_notification(int p_what) { } if (margin_drawing_enabled) { - Color margin_drawing_color(0, 1, 1, 0.63); + Color margin_drawing_color(0.25, 1, 1, 0.63); float margin_drawing_width = 1; if (is_current()) { margin_drawing_width = 3; - margin_drawing_color.a = 0.83; } Transform2D inv_camera_transform = get_camera_transform().affine_inverse(); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 6f303e9aecf..1e5cfcdaabb 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -666,7 +666,7 @@ void Skeleton::_rebuild_physical_bones_cache() { const int b_size = bones.size(); for (int i = 0; i < b_size; ++i) { PhysicalBone *parent_pb = _get_physical_bone_parent(i); - if (parent_pb != bones[i].physical_bone) { + if (parent_pb != bones[i].cache_parent_physical_bone) { bones.write[i].cache_parent_physical_bone = parent_pb; if (bones[i].physical_bone) { bones[i].physical_bone->_on_bone_parent_changed(); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index cc19c561bfe..5f771b16a18 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -32,6 +32,12 @@ #include "core/method_bind_ext.gen.inc" +struct _MinSizeCache { + int min_size; + bool will_stretch; + int final_size; +}; + bool GraphNode::_set(const StringName &p_name, const Variant &p_value) { if (!p_name.operator String().begins_with("slot/")) { return false; @@ -119,15 +125,23 @@ void GraphNode::_get_property_list(List *p_list) const { } void GraphNode::_resort() { - int sep = get_constant("separation"); - Ref sb = get_stylebox("frame"); - bool first = true; + /** First pass, determine minimum size AND amount of stretchable elements */ - Size2 minsize; + Size2 new_size = get_size(); + Ref sb = get_stylebox("frame"); + + int sep = get_constant("separation"); + + bool first = true; + int children_count = 0; + int stretch_min = 0; + int stretch_avail = 0; + float stretch_ratio_total = 0; + Map min_size_cache; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to(get_child(i)); - if (!c) { + if (!c || !c->is_visible_in_tree()) { continue; } if (c->is_set_as_toplevel()) { @@ -135,38 +149,120 @@ void GraphNode::_resort() { } Size2i size = c->get_combined_minimum_size(); + _MinSizeCache msc; - minsize.y += size.y; - minsize.x = MAX(minsize.x, size.x); + stretch_min += size.height; + msc.min_size = size.height; + msc.will_stretch = c->get_v_size_flags() & SIZE_EXPAND; + + if (msc.will_stretch) { + stretch_avail += msc.min_size; + stretch_ratio_total += c->get_stretch_ratio(); + } + msc.final_size = msc.min_size; + min_size_cache[c] = msc; + children_count++; + } + + if (children_count == 0) { + return; + } + + int stretch_max = new_size.height - (children_count - 1) * sep; + int stretch_diff = stretch_max - stretch_min; + if (stretch_diff < 0) { + //avoid negative stretch space + stretch_diff = 0; + } + + stretch_avail += stretch_diff - sb->get_margin(MARGIN_BOTTOM) - sb->get_margin(MARGIN_TOP); //available stretch space. + /** Second, pass sucessively to discard elements that can't be stretched, this will run while stretchable + elements exist */ + + while (stretch_ratio_total > 0) { // first of all, don't even be here if no stretchable objects exist + bool refit_successful = true; //assume refit-test will go well + + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to(get_child(i)); + if (!c || !c->is_visible_in_tree()) { + continue; + } + if (c->is_set_as_toplevel()) { + continue; + } + + ERR_FAIL_COND(!min_size_cache.has(c)); + _MinSizeCache &msc = min_size_cache[c]; + + if (msc.will_stretch) { //wants to stretch + //let's see if it can really stretch + + int final_pixel_size = stretch_avail * c->get_stretch_ratio() / stretch_ratio_total; + if (final_pixel_size < msc.min_size) { + //if available stretching area is too small for widget, + //then remove it from stretching area + msc.will_stretch = false; + stretch_ratio_total -= c->get_stretch_ratio(); + refit_successful = false; + stretch_avail -= msc.min_size; + msc.final_size = msc.min_size; + break; + } else { + msc.final_size = final_pixel_size; + } + } + } + + if (refit_successful) { //uf refit went well, break + break; + } + } + + /** Final pass, draw and stretch elements **/ + + int ofs = sb->get_margin(MARGIN_TOP); + + first = true; + int idx = 0; + cache_y.clear(); + int w = new_size.width - sb->get_minimum_size().x; + + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to(get_child(i)); + if (!c || !c->is_visible_in_tree()) { + continue; + } + if (c->is_set_as_toplevel()) { + continue; + } + + _MinSizeCache &msc = min_size_cache[c]; if (first) { first = false; } else { - minsize.y += sep; - } - } - - int vofs = 0; - int w = get_size().x - sb->get_minimum_size().x; - - cache_y.clear(); - for (int i = 0; i < get_child_count(); i++) { - Control *c = Object::cast_to(get_child(i)); - if (!c) { - continue; - } - if (c->is_set_as_toplevel()) { - continue; + ofs += sep; } - Size2i size = c->get_combined_minimum_size(); + int from = ofs; + int to = ofs + msc.final_size; - Rect2 r(sb->get_margin(MARGIN_LEFT), sb->get_margin(MARGIN_TOP) + vofs, w, size.y); + if (msc.will_stretch && idx == children_count - 1) { + //adjust so the last one always fits perfect + //compensating for numerical imprecision - fit_child_in_rect(c, r); - cache_y.push_back(vofs + size.y * 0.5); + to = new_size.height - sb->get_margin(MARGIN_BOTTOM); + } - vofs += size.y + sep; + int size = to - from; + + Rect2 rect(sb->get_margin(MARGIN_LEFT), from, w, size); + + fit_child_in_rect(c, rect); + cache_y.push_back(from - sb->get_margin(MARGIN_TOP) + size * 0.5); + + ofs = to; + idx++; } update(); diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index b75c693edb6..a2bb022be20 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -166,9 +166,11 @@ void TextureButton::_notification(int p_what) { } break; } + Point2 ofs; + Size2 size; + if (texdraw.is_valid()) { - Point2 ofs; - Size2 size = texdraw->get_size(); + size = texdraw->get_size(); _texture_region = Rect2(Point2(), texdraw->get_size()); _tile = false; if (expand) { @@ -218,17 +220,21 @@ void TextureButton::_notification(int p_what) { } _position_rect = Rect2(ofs, size); + + size.width *= hflip ? -1.0f : 1.0f; + size.height *= vflip ? -1.0f : 1.0f; + if (_tile) { - draw_texture_rect(texdraw, _position_rect, _tile); + draw_texture_rect(texdraw, Rect2(ofs, size), _tile); } else { - draw_texture_rect_region(texdraw, _position_rect, _texture_region); + draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region); } } else { _position_rect = Rect2(); } if (has_focus() && focused.is_valid()) { - draw_texture_rect(focused, _position_rect, false); + draw_texture_rect(focused, Rect2(ofs, size), false); }; } break; } @@ -243,6 +249,10 @@ void TextureButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_click_mask", "mask"), &TextureButton::set_click_mask); ClassDB::bind_method(D_METHOD("set_expand", "p_expand"), &TextureButton::set_expand); ClassDB::bind_method(D_METHOD("set_stretch_mode", "p_mode"), &TextureButton::set_stretch_mode); + ClassDB::bind_method(D_METHOD("set_flip_h", "enable"), &TextureButton::set_flip_h); + ClassDB::bind_method(D_METHOD("is_flipped_h"), &TextureButton::is_flipped_h); + ClassDB::bind_method(D_METHOD("set_flip_v", "enable"), &TextureButton::set_flip_v); + ClassDB::bind_method(D_METHOD("is_flipped_v"), &TextureButton::is_flipped_v); ClassDB::bind_method(D_METHOD("get_normal_texture"), &TextureButton::get_normal_texture); ClassDB::bind_method(D_METHOD("get_pressed_texture"), &TextureButton::get_pressed_texture); @@ -262,6 +272,8 @@ void TextureButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_click_mask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_click_mask", "get_click_mask"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_expand", "get_expand"); ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_flip_h", "is_flipped_h"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_flip_v", "is_flipped_v"); BIND_ENUM_CONSTANT(STRETCH_SCALE); BIND_ENUM_CONSTANT(STRETCH_TILE); @@ -338,9 +350,29 @@ TextureButton::StretchMode TextureButton::get_stretch_mode() const { return stretch_mode; } +void TextureButton::set_flip_h(bool p_flip) { + hflip = p_flip; + update(); +} + +bool TextureButton::is_flipped_h() const { + return hflip; +} + +void TextureButton::set_flip_v(bool p_flip) { + vflip = p_flip; + update(); +} + +bool TextureButton::is_flipped_v() const { + return vflip; +} + TextureButton::TextureButton() { expand = false; stretch_mode = STRETCH_SCALE; + hflip = false; + vflip = false; _texture_region = Rect2(); _position_rect = Rect2(); diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h index 19a933024c9..382c384a522 100644 --- a/scene/gui/texture_button.h +++ b/scene/gui/texture_button.h @@ -61,6 +61,9 @@ private: Rect2 _position_rect; bool _tile; + bool hflip; + bool vflip; + protected: virtual Size2 get_minimum_size() const; virtual bool has_point(const Point2 &p_point) const; @@ -88,6 +91,12 @@ public: void set_stretch_mode(StretchMode p_stretch_mode); StretchMode get_stretch_mode() const; + void set_flip_h(bool p_flip); + bool is_flipped_h() const; + + void set_flip_v(bool p_flip); + bool is_flipped_v() const; + TextureButton(); }; diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index f17a31ed031..5e7af4c846e 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -322,17 +322,19 @@ bool HTTPRequest::_update_connection() { } PoolByteArray chunk = client->read_response_body_chunk(); - downloaded.add(chunk.size()); - if (file) { - PoolByteArray::Read r = chunk.read(); - file->store_buffer(r.ptr(), chunk.size()); - if (file->get_error() != OK) { - call_deferred("_request_done", RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PoolByteArray()); - return true; + if (chunk.size()) { + downloaded.add(chunk.size()); + if (file) { + PoolByteArray::Read r = chunk.read(); + file->store_buffer(r.ptr(), chunk.size()); + if (file->get_error() != OK) { + call_deferred("_request_done", RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PoolByteArray()); + return true; + } + } else { + body.append_array(chunk); } - } else { - body.append_array(chunk); } if (body_size_limit >= 0 && downloaded.get() > body_size_limit) { diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index cf354f3302d..ad8ffdd389a 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -65,17 +65,19 @@ void BodySW::update_inertias() { // We have to recompute the center of mass. center_of_mass_local.zero(); - for (int i = 0; i < get_shape_count(); i++) { - real_t area = get_shape_area(i); + if (total_area != 0.0) { + for (int i = 0; i < get_shape_count(); i++) { + real_t area = get_shape_area(i); - real_t mass = area * this->mass / total_area; + real_t mass = area * this->mass / total_area; - // NOTE: we assume that the shape origin is also its center of mass. - center_of_mass_local += mass * get_shape_transform(i).origin; + // NOTE: we assume that the shape origin is also its center of mass. + center_of_mass_local += mass * get_shape_transform(i).origin; + } + + center_of_mass_local /= mass; } - center_of_mass_local /= mass; - // Recompute the inertia tensor. Basis inertia_tensor; inertia_tensor.set_zero(); @@ -86,12 +88,15 @@ void BodySW::update_inertias() { continue; } + real_t area = get_shape_area(i); + if (area == 0.0) { + continue; + } + inertia_set = true; const ShapeSW *shape = get_shape(i); - real_t area = get_shape_area(i); - real_t mass = area * this->mass / total_area; Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix();