diff options
97 files changed, 1320 insertions, 773 deletions
diff --git a/core/io/image.cpp b/core/io/image.cpp index f065dac212..473d70bd7c 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -2284,6 +2284,21 @@ Error Image::load(const String &p_path) { return ImageLoader::load_image(p_path, this); } +Ref<Image> Image::load_from_file(const String &p_path) { +#ifdef DEBUG_ENABLED + if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) { + WARN_PRINT("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource."); + } +#endif + Ref<Image> image; + image.instantiate(); + Error err = ImageLoader::load_image(p_path, image); + if (err != OK) { + ERR_FAIL_V_MSG(Ref<Image>(), vformat("Failed to load image. Error %d", err)); + } + return image; +} + Error Image::save_png(const String &p_path) const { if (save_png_func == nullptr) { return ERR_UNAVAILABLE; @@ -3183,6 +3198,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty); ClassDB::bind_method(D_METHOD("load", "path"), &Image::load); + ClassDB::bind_static_method("Image", D_METHOD("load_from_file", "path"), &Image::load_from_file); ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png); ClassDB::bind_method(D_METHOD("save_png_to_buffer"), &Image::save_png_to_buffer); ClassDB::bind_method(D_METHOD("save_jpg", "path", "quality"), &Image::save_jpg, DEFVAL(0.75)); diff --git a/core/io/image.h b/core/io/image.h index 2cad26f3e9..6b323e5eb3 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -290,6 +290,7 @@ public: Vector<uint8_t> get_data() const; Error load(const String &p_path); + static Ref<Image> load_from_file(const String &p_path); Error save_png(const String &p_path) const; Error save_jpg(const String &p_path, float p_quality = 0.75) const; Vector<uint8_t> save_png_to_buffer() const; diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index 26fe1278f7..e0bc98e208 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -55,6 +55,7 @@ </member> <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&"Master""> Bus on which this audio is playing. + [b]Note:[/b] When setting this property, keep in mind that no validation is performed to see if the given name matches an existing bus. This is because audio bus layouts might be loaded after this property is set. If this given name can't be resolved at runtime, it will fall back to [code]"Master"[/code]. </member> <member name="max_polyphony" type="int" setter="set_max_polyphony" getter="get_max_polyphony" default="1"> The maximum number of sounds this node can play at the same time. Playing additional sounds after this value is reached will cut off the oldest sounds. diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml index 76666b1f27..f04f95bd72 100644 --- a/doc/classes/AudioStreamPlayer2D.xml +++ b/doc/classes/AudioStreamPlayer2D.xml @@ -57,6 +57,7 @@ </member> <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&"Master""> Bus on which this audio is playing. + [b]Note:[/b] When setting this property, keep in mind that no validation is performed to see if the given name matches an existing bus. This is because audio bus layouts might be loaded after this property is set. If this given name can't be resolved at runtime, it will fall back to [code]"Master"[/code]. </member> <member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="2000.0"> Maximum distance from which audio is still hearable. diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml index a49b1e2291..72febf7006 100644 --- a/doc/classes/AudioStreamPlayer3D.xml +++ b/doc/classes/AudioStreamPlayer3D.xml @@ -64,6 +64,7 @@ </member> <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&"Master""> The bus on which this audio is playing. + [b]Note:[/b] When setting this property, keep in mind that no validation is performed to see if the given name matches an existing bus. This is because audio bus layouts might be loaded after this property is set. If this given name can't be resolved at runtime, it will fall back to [code]"Master"[/code]. </member> <member name="doppler_tracking" type="int" setter="set_doppler_tracking" getter="get_doppler_tracking" enum="AudioStreamPlayer3D.DopplerTracking" default="0"> Decides in which step the Doppler effect should be calculated. diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 7c9c4ed4d6..cc9c5877c5 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -37,16 +37,15 @@ <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(1, 1, 1, 1)"> The currently selected color. </member> + <member name="color_mode" type="int" setter="set_color_mode" getter="get_color_mode" enum="ColorPicker.ColorModeType" default="0"> + The currently selected color mode. See [enum ColorModeType]. + </member> <member name="deferred_mode" type="bool" setter="set_deferred_mode" getter="is_deferred_mode" default="false"> If [code]true[/code], the color will apply only after the user releases the mouse button, otherwise it will apply immediately even in mouse motion event (which can cause performance issues). </member> <member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha" default="true"> If [code]true[/code], shows an alpha channel slider (opacity). </member> - <member name="hsv_mode" type="bool" setter="set_hsv_mode" getter="is_hsv_mode" default="false"> - If [code]true[/code], allows editing the color with Hue/Saturation/Value sliders. - [b]Note:[/b] Cannot be enabled if raw mode is on. - </member> <member name="picker_shape" type="int" setter="set_picker_shape" getter="get_picker_shape" enum="ColorPicker.PickerShapeType" default="0"> The shape of the color space view. See [enum PickerShapeType]. </member> @@ -56,10 +55,6 @@ <member name="presets_visible" type="bool" setter="set_presets_visible" getter="are_presets_visible" default="true"> If [code]true[/code], saved color presets are visible. </member> - <member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode" default="false"> - If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). - [b]Note:[/b] Cannot be enabled if HSV mode is on. - </member> </members> <signals> <signal name="color_changed"> @@ -82,6 +77,20 @@ </signal> </signals> <constants> + <constant name="MODE_RGB" value="0" enum="ColorModeType"> + Allows editing the color with Red/Green/Blue sliders. + </constant> + <constant name="MODE_HSV" value="1" enum="ColorModeType"> + Allows editing the color with Hue/Saturation/Value sliders. + </constant> + <constant name="MODE_RAW" value="2" enum="ColorModeType"> + Allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). + </constant> + <constant name="MODE_OKHSL" value="3" enum="ColorModeType"> + Allows editing the color with Hue/Saturation/Lightness sliders. + OKHSL is a new color space similar to HSL but that better match perception by leveraging the Oklab color space which is designed to be simple to use, while doing a good job at predicting perceived lightness, chroma and hue. + [url=https://bottosson.github.io/posts/colorpicker/]Okhsv and Okhsl color spaces[/url] + </constant> <constant name="SHAPE_HSV_RECTANGLE" value="0" enum="PickerShapeType"> HSV Color Model rectangle color space. </constant> diff --git a/doc/classes/EditorFileDialog.xml b/doc/classes/EditorFileDialog.xml index b1fd7b4e76..6fd5abe369 100644 --- a/doc/classes/EditorFileDialog.xml +++ b/doc/classes/EditorFileDialog.xml @@ -11,9 +11,11 @@ <method name="add_filter"> <return type="void" /> <argument index="0" name="filter" type="String" /> + <argument index="1" name="description" type="String" default="""" /> <description> - Adds a comma-delimited file extension filter option to the [EditorFileDialog] with an optional semi-colon-delimited label. - For example, [code]"*.tscn, *.scn; Scenes"[/code] results in filter text "Scenes (*.tscn, *.scn)". + Adds a comma-delimited file name [code]filter[/code] option to the [EditorFileDialog] with an optional [code]description[/code], which restricts what files can be picked. + A [code]filter[/code] should be of the form [code]"filename.extension"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed. + For example, a [code]filter[/code] of [code]"*.tscn, *.scn"[/code] and a [code]description[/code] of [code]"Scenes"[/code] results in filter text "Scenes (*.tscn, *.scn)". </description> </method> <method name="clear_filters"> diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index 903f36d0ce..f45031cea8 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -12,10 +12,11 @@ <method name="add_filter"> <return type="void" /> <argument index="0" name="filter" type="String" /> + <argument index="1" name="description" type="String" default="""" /> <description> - Adds [code]filter[/code] to the list of filters, which restricts what files can be picked. - A [code]filter[/code] should be of the form [code]"filename.extension ; Description"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed. - Example filters: [code]"*.png ; PNG Images"[/code], [code]"project.godot ; Godot Project"[/code]. + Adds a comma-delimited file name [code]filter[/code] option to the [FileDialog] with an optional [code]description[/code], which restricts what files can be picked. + A [code]filter[/code] should be of the form [code]"filename.extension"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed. + For example, a [code]filter[/code] of [code]"*.png, *.jpg"[/code] and a [code]description[/code] of [code]"Images"[/code] results in filter text "Images (*.png, *.jpg)". </description> </method> <method name="clear_filters"> diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml index 166923314f..f138b9087b 100644 --- a/doc/classes/HTTPRequest.xml +++ b/doc/classes/HTTPRequest.xml @@ -106,8 +106,7 @@ if error != OK: push_error("Couldn't load the image.") - var texture = ImageTexture.new() - texture.create_from_image(image) + var texture = ImageTexture.create_from_image(image) # Display the image in a TextureRect node. var texture_rect = TextureRect.new() diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 43b03ce65e..31bd938c40 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -308,6 +308,13 @@ [b]Note:[/b] Godot's BMP module doesn't support 16-bit per pixel images. Only 1-bit, 4-bit, 8-bit, 24-bit, and 32-bit per pixel images are supported. </description> </method> + <method name="load_from_file" qualifiers="static"> + <return type="Image" /> + <argument index="0" name="path" type="String" /> + <description> + Creates a new [Image] and loads data from the specified file. + </description> + </method> <method name="load_jpg_from_buffer"> <return type="int" enum="Error" /> <argument index="0" name="buffer" type="PackedByteArray" /> diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml index aecb4fc4b6..e668e2e7fd 100644 --- a/doc/classes/ImageTexture.xml +++ b/doc/classes/ImageTexture.xml @@ -6,10 +6,8 @@ <description> A [Texture2D] based on an [Image]. For an image to be displayed, an [ImageTexture] has to be created from it using the [method create_from_image] method: [codeblock] - var texture = ImageTexture.new() - var image = Image.new() - image.load("res://icon.png") - texture.create_from_image(image) + var image = Image.load_from_file("res://icon.png") + var texture = ImageTexture.create_from_image(image) $Sprite2D.texture = texture [/codeblock] This way, textures can be created at run-time by loading images both from within the editor and externally. @@ -31,11 +29,11 @@ <link title="Importing images">$DOCS_URL/tutorials/assets_pipeline/importing_images.html</link> </tutorials> <methods> - <method name="create_from_image"> - <return type="void" /> + <method name="create_from_image" qualifiers="static"> + <return type="ImageTexture" /> <argument index="0" name="image" type="Image" /> <description> - Initializes the texture by allocating and setting the data from an [Image]. + Creates a new [ImageTexture] and initializes it by allocating and setting the data from an [Image]. </description> </method> <method name="get_format" qualifiers="const"> diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml index ffde0d95ce..c0766cd1ec 100644 --- a/doc/classes/LightmapGI.xml +++ b/doc/classes/LightmapGI.xml @@ -21,7 +21,7 @@ Number of light bounces that are taken into account during baking. Higher values result in brighter, more realistic lighting, at the cost of longer bake times. If set to [code]0[/code], only environment lighting, direct light and emissive lighting is baked. </member> <member name="directional" type="bool" setter="set_directional" getter="is_directional" default="false"> - If [code]true[/code], bakes lightmaps to contain directional information as spherical harmonics. This results in more realistic lighting appearance, especially with normal mapped materials and for lights that their have direct light baked ([member Light3D.light_bake_mode] set to [constant Light3D.BAKE_STATIC]). The directional information is also used to provide rough reflections for static and dynamic objects. This has a small run-time performance cost as the shader has to perform more work to interpret the direction information from the lightmap. Directional lightmaps also take longer to bake and result in larger file sizes. + If [code]true[/code], bakes lightmaps to contain directional information as spherical harmonics. This results in more realistic lighting appearance, especially with normal mapped materials and for lights that have their direct light baked ([member Light3D.light_bake_mode] set to [constant Light3D.BAKE_STATIC]). The directional information is also used to provide rough reflections for static and dynamic objects. This has a small run-time performance cost as the shader has to perform more work to interpret the direction information from the lightmap. Directional lightmaps also take longer to bake and result in larger file sizes. [b]Note:[/b] The property's name has no relationship with [DirectionalLight3D]. [member directional] works with all light types. </member> <member name="environment_custom_color" type="Color" setter="set_environment_custom_color" getter="get_environment_custom_color"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 7c378f33fe..2a47d4af25 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -203,6 +203,9 @@ Path to an image used as the boot splash. If left empty, the default Godot Engine splash will be displayed instead. [b]Note:[/b] Only effective if [member application/boot_splash/show_image] is [code]true[/code]. </member> + <member name="application/boot_splash/minimum_display_time" type="int" setter="" getter="" default="0"> + Minimum boot splash display time (in milliseconds). It is not recommended to set too high values for this setting. + </member> <member name="application/boot_splash/show_image" type="bool" setter="" getter="" default="true"> If [code]true[/code], displays the image specified in [member application/boot_splash/image] when the engine starts. If [code]false[/code], only displays the plain color specified in [member application/boot_splash/bg_color]. </member> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 804b8dddd9..fbba1147a2 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -223,14 +223,14 @@ <method name="get_next" qualifiers="const"> <return type="TreeItem" /> <description> - Returns the next TreeItem in the tree or a null object if there is none. + Returns the next sibling TreeItem in the tree or a null object if there is none. </description> </method> <method name="get_next_visible"> <return type="TreeItem" /> <argument index="0" name="wrap" type="bool" default="false" /> <description> - Returns the next visible TreeItem in the tree or a null object if there is none. + Returns the next visible sibling TreeItem in the tree or a null object if there is none. If [code]wrap[/code] is enabled, the method will wrap around to the first visible element in the tree when called on the last visible element, otherwise it returns [code]null[/code]. </description> </method> @@ -243,14 +243,14 @@ <method name="get_prev"> <return type="TreeItem" /> <description> - Returns the previous TreeItem in the tree or a null object if there is none. + Returns the previous sibling TreeItem in the tree or a null object if there is none. </description> </method> <method name="get_prev_visible"> <return type="TreeItem" /> <argument index="0" name="wrap" type="bool" default="false" /> <description> - Returns the previous visible TreeItem in the tree or a null object if there is none. + Returns the previous visible sibling TreeItem in the tree or a null object if there is none. If [code]wrap[/code] is enabled, the method will wrap around to the last visible element in the tree when called on the first visible element, otherwise it returns [code]null[/code]. </description> </method> diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index a1979c7619..50abe8bc36 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1895,7 +1895,6 @@ CodeTextEditor::CodeTextEditor() { } break; } } - text_editor->add_theme_font_override("font", fc); text_editor->set_draw_line_numbers(true); text_editor->set_highlight_matching_braces_enabled(true); diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index 023204b74a..bdab1cfecb 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -258,7 +258,7 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) { ResourceSaver::get_recognized_extensions(sd, &extensions); file_dialog->clear_filters(); for (int i = 0; i < extensions.size(); i++) { - file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + file_dialog->add_filter("*." + extensions[i], extensions[i].to_upper()); } file_dialog->popup_file_dialog(); diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index 1b1cdbd9ef..28b5d4be15 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -312,7 +312,7 @@ void EditorProfiler::_update_plot() { if (graph_texture.is_null()) { graph_texture.instantiate(); } - graph_texture->create_from_image(img); + graph_texture->set_image(img); } graph_texture->update(img); diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index 59482db674..ee67cbdaea 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -306,7 +306,7 @@ void EditorVisualProfiler::_update_plot() { if (graph_texture.is_null()) { graph_texture.instantiate(); } - graph_texture->create_from_image(img); + graph_texture->set_image(img); } graph_texture->update(img); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index fd121e73ab..fa365c4368 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -1332,7 +1332,7 @@ EditorAudioBuses::EditorAudioBuses() { List<String> ext; ResourceLoader::get_recognized_extensions_for_type("AudioBusLayout", &ext); for (const String &E : ext) { - file_dialog->add_filter(vformat("*.%s; %s", E, TTR("Audio Bus Layout"))); + file_dialog->add_filter("*." + E, TTR("Audio Bus Layout")); } add_child(file_dialog); file_dialog->connect("file_selected", callable_mp(this, &EditorAudioBuses::_file_dialog_callback)); diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 6dda9f0407..9e2d56b2b9 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -993,7 +993,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { import_profiles = memnew(EditorFileDialog); add_child(import_profiles); import_profiles->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES); - import_profiles->add_filter("*.profile; " + TTR("Godot Feature Profile")); + import_profiles->add_filter("*.profile", TTR("Godot Feature Profile")); import_profiles->connect("files_selected", callable_mp(this, &EditorFeatureProfileManager::_import_profiles)); import_profiles->set_title(TTR("Import Profile(s)")); import_profiles->set_access(EditorFileDialog::ACCESS_FILESYSTEM); @@ -1001,7 +1001,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { export_profile = memnew(EditorFileDialog); add_child(export_profile); export_profile->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); - export_profile->add_filter("*.profile; " + TTR("Godot Feature Profile")); + export_profile->add_filter("*.profile", TTR("Godot Feature Profile")); export_profile->connect("file_selected", callable_mp(this, &EditorFeatureProfileManager::_export_profile)); export_profile->set_title(TTR("Export Profile")); export_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 6beee5db45..9f446ab38f 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -976,8 +976,12 @@ void EditorFileDialog::clear_filters() { invalidate(); } -void EditorFileDialog::add_filter(const String &p_filter) { - filters.push_back(p_filter); +void EditorFileDialog::add_filter(const String &p_filter, const String &p_description) { + if (p_description.is_empty()) { + filters.push_back(p_filter); + } else { + filters.push_back(vformat("%s ; %s", p_filter, p_description)); + } update_filters(); invalidate(); } @@ -1481,7 +1485,7 @@ void EditorFileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_cancel_pressed"), &EditorFileDialog::_cancel_pressed); ClassDB::bind_method(D_METHOD("clear_filters"), &EditorFileDialog::clear_filters); - ClassDB::bind_method(D_METHOD("add_filter", "filter"), &EditorFileDialog::add_filter); + ClassDB::bind_method(D_METHOD("add_filter", "filter", "description"), &EditorFileDialog::add_filter, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_current_dir"), &EditorFileDialog::get_current_dir); ClassDB::bind_method(D_METHOD("get_current_file"), &EditorFileDialog::get_current_file); ClassDB::bind_method(D_METHOD("get_current_path"), &EditorFileDialog::get_current_path); diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 5f2e29b690..51629f2682 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -212,7 +212,7 @@ protected: public: void popup_file_dialog(); void clear_filters(); - void add_filter(const String &p_filter); + void add_filter(const String &p_filter, const String &p_description = ""); void set_enable_multiple_selection(bool p_enable); Vector<String> get_selected_files() const; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d123c8286c..abe431221c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1259,7 +1259,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String // This serves no purpose and confused people. continue; } - file->add_filter("*." + E + " ; " + E.to_upper()); + file->add_filter("*." + E, E.to_upper()); preferred.push_back(E); } // Lowest priority extension. @@ -2332,6 +2332,13 @@ void EditorNode::_run(bool p_current, const String &p_custom) { return; } + play_button->set_pressed(false); + play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); + play_scene_button->set_pressed(false); + play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons"))); + play_custom_scene_button->set_pressed(false); + play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons"))); + String write_movie_file; if (write_movie_button->is_pressed()) { if (p_current && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->has_meta("movie_file")) { @@ -2346,13 +2353,6 @@ void EditorNode::_run(bool p_current, const String &p_custom) { } } - play_button->set_pressed(false); - play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); - play_scene_button->set_pressed(false); - play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons"))); - play_custom_scene_button->set_pressed(false); - play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons"))); - String run_filename; if (p_current || (editor_data.get_edited_scene_root() && !p_custom.is_empty() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) { @@ -2471,7 +2471,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions); file->clear_filters(); for (int i = 0; i < extensions.size(); i++) { - file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + file->add_filter("*." + extensions[i], extensions[i].to_upper()); } Node *scene = editor_data.get_edited_scene_root(); @@ -2617,7 +2617,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { ResourceSaver::get_recognized_extensions(sd, &extensions); file->clear_filters(); for (int i = 0; i < extensions.size(); i++) { - file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + file->add_filter("*." + extensions[i], extensions[i].to_upper()); } if (!scene->get_scene_file_path().is_empty()) { @@ -2792,9 +2792,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case RUN_SETTINGS: { project_settings_editor->popup_project_settings(); } break; - case RUN_WRITE_MOVIE: { - _update_write_movie_icon(); - } break; case FILE_INSTALL_ANDROID_SOURCE: { if (p_confirmed) { export_template_manager->install_android_template(); @@ -2906,7 +2903,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions); file->clear_filters(); for (int i = 0; i < extensions.size(); i++) { - file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + file->add_filter("*." + extensions[i], extensions[i].to_upper()); } Node *scene = editor_data.get_edited_scene_root(); @@ -4046,10 +4043,8 @@ Ref<ImageTexture> EditorNode::_load_custom_class_icon(const String &p_path) cons Ref<Image> img = memnew(Image); Error err = ImageLoader::load_image(p_path, img); if (err == OK) { - Ref<ImageTexture> icon = memnew(ImageTexture); img->resize(16 * EDSCALE, 16 * EDSCALE, Image::INTERPOLATE_LANCZOS); - icon->create_from_image(img); - return icon; + return ImageTexture::create_from_image(img); } } return nullptr; @@ -4956,14 +4951,6 @@ String EditorNode::get_run_playing_scene() const { return run_filename; } -void EditorNode::_update_write_movie_icon() { - if (write_movie_button->is_pressed()) { - write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWriteEnabled"), SNAME("EditorIcons"))); - } else { - write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons"))); - } -} - void EditorNode::_immediate_dialog_confirmed() { immediate_dialog_confirmed = true; } @@ -5404,9 +5391,7 @@ Variant EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) { Ref<Image> img = texture->get_image(); img = img->duplicate(); img->resize(48, 48); // meh - Ref<ImageTexture> resized_pic = Ref<ImageTexture>(memnew(ImageTexture)); - resized_pic->create_from_image(img); - preview = resized_pic; + preview = ImageTexture::create_from_image(img); } drag_preview->set_texture(preview); @@ -6136,7 +6121,7 @@ EditorNode::EditorNode() { EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true); EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,MeshLibrary"); EDITOR_DEF("interface/inspector/default_color_picker_mode", 0); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW", PROPERTY_USAGE_DEFAULT)); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW,OKHSL", PROPERTY_USAGE_DEFAULT)); EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle", PROPERTY_USAGE_DEFAULT)); @@ -6732,15 +6717,12 @@ EditorNode::EditorNode() { write_movie_button->set_pressed(false); write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons"))); write_movie_button->set_focus_mode(Control::FOCUS_NONE); - write_movie_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_WRITE_MOVIE)); write_movie_button->set_tooltip(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file.")); - // Restore these values to something more useful so it ignores the theme - write_movie_button->add_theme_color_override("icon_normal_color", Color(1, 1, 1, 0.4)); - write_movie_button->add_theme_color_override("icon_pressed_color", Color(1, 1, 1, 1)); - write_movie_button->add_theme_color_override("icon_hover_color", Color(1.2, 1.2, 1.2, 0.4)); - write_movie_button->add_theme_color_override("icon_hover_pressed_color", Color(1.2, 1.2, 1.2, 1)); - write_movie_button->add_theme_color_override("icon_focus_color", Color(1, 1, 1, 1)); - write_movie_button->add_theme_color_override("icon_disabled_color", Color(1, 1, 1, 0.4)); + + // This button behaves differently, so color it as such. + write_movie_button->add_theme_color_override("icon_normal_color", Color(1, 1, 1, 0.7)); + write_movie_button->add_theme_color_override("icon_pressed_color", gui_base->get_theme_color(SNAME("error_color"), SNAME("Editor"))); + write_movie_button->add_theme_color_override("icon_hover_color", Color(1, 1, 1, 0.9)); HBoxContainer *right_menu_hb = memnew(HBoxContainer); menu_hb->add_child(right_menu_hb); @@ -6988,7 +6970,7 @@ EditorNode::EditorNode() { file_templates->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); file_templates->set_access(EditorFileDialog::ACCESS_FILESYSTEM); file_templates->clear_filters(); - file_templates->add_filter("*.tpz ; " + TTR("Template Package")); + file_templates->add_filter("*.tpz", TTR("Template Package")); file = memnew(EditorFileDialog); gui_base->add_child(file); @@ -7070,12 +7052,10 @@ EditorNode::EditorNode() { ScriptTextEditor::register_editor(); // Register one for text scripts. TextEditor::register_editor(); - // Asset Library can't work on Web editor for now as most assets are sourced - // directly from GitHub which does not set CORS. if (AssetLibraryEditorPlugin::is_available()) { add_editor_plugin(memnew(AssetLibraryEditorPlugin)); } else { - WARN_PRINT("Asset Library not available, as it requires SSL to work."); + print_verbose("Asset Library not available (due to using Web editor, or SSL support disabled)."); } // Add interface before adding plugins. diff --git a/editor/editor_node.h b/editor/editor_node.h index c327a73ce9..07d565314d 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -173,7 +173,6 @@ private: RUN_PLAY_CUSTOM_SCENE, RUN_SETTINGS, RUN_USER_DATA_FOLDER, - RUN_WRITE_MOVIE, RELOAD_CURRENT_PROJECT, RUN_PROJECT_MANAGER, RUN_VCS_METADATA, @@ -669,7 +668,6 @@ private: void _pick_main_scene_custom_action(const String &p_custom_action_name); void _immediate_dialog_confirmed(); - void _update_write_movie_icon(); void _select_default_main_screen_plugin(); void _bottom_panel_switch(bool p_enable, int p_idx); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 639846861b..d9c2a42114 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -133,8 +133,7 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh Main::iteration(); Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); ERR_CONTINUE(!img.is_valid() || img->is_empty()); - Ref<ImageTexture> it(memnew(ImageTexture)); - it->create_from_image(img); + Ref<ImageTexture> it = ImageTexture::create_from_image(img); RS::get_singleton()->free(inst); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 9af667612b..aaa518362c 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -3010,12 +3010,7 @@ void EditorPropertyColor::_popup_closed() { void EditorPropertyColor::_picker_created() { // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); - if (default_color_mode == 1) { - picker->get_picker()->set_hsv_mode(true); - } else if (default_color_mode == 2) { - picker->get_picker()->set_raw_mode(true); - } - + picker->get_picker()->set_color_mode((ColorPicker::ColorModeType)default_color_mode); int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape"); picker->get_picker()->set_picker_shape((ColorPicker::PickerShapeType)picker_shape); } diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 77d627ab9c..2e78b58e11 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -254,7 +254,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { file_dialog->clear_filters(); for (const String &E : valid_extensions) { - file_dialog->add_filter("*." + E + " ; " + E.to_upper()); + file_dialog->add_filter("*." + E, E.to_upper()); } file_dialog->popup_file_dialog(); @@ -678,7 +678,7 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_ if (!texture.is_valid()) { texture.instantiate(); } - texture->create_from_image(dropped_resource); + texture->set_image(dropped_resource); dropped_resource = texture; break; } diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index dffb378408..b84e654d42 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -184,7 +184,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref< small_image = small_image->duplicate(); small_image->resize(small_thumbnail_size, small_thumbnail_size, Image::INTERPOLATE_CUBIC); r_small_texture.instantiate(); - r_small_texture->create_from_image(small_image); + r_small_texture->set_image(small_image); } break; @@ -300,14 +300,14 @@ void EditorResourcePreview::_iterate() { cache_valid = false; } else { texture.instantiate(); - texture->create_from_image(img); + texture->set_image(img); if (has_small_texture) { if (small_img->load(cache_base + "_small.png") != OK) { cache_valid = false; } else { small_texture.instantiate(); - small_texture->create_from_image(small_img); + small_texture->set_image(small_img); } } } diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index 6ce9e5fa6f..854885c707 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -49,9 +49,7 @@ void EditorRunNative::_notification(int p_what) { im->clear_mipmaps(); if (!im->is_empty()) { im->resize(16 * EDSCALE, 16 * EDSCALE); - Ref<ImageTexture> small_icon; - small_icon.instantiate(); - small_icon->create_from_image(im); + Ref<ImageTexture> small_icon = ImageTexture::create_from_image(im); MenuButton *mb = memnew(MenuButton); mb->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native), varray(i)); mb->connect("pressed", callable_mp(this, &EditorRunNative::run_native), varray(-1, i)); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 82c1d278b7..13109478e4 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -97,7 +97,6 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, return p_texture; } - Ref<ImageTexture> texture(memnew(ImageTexture)); Ref<Image> img = p_texture->get_image(); ERR_FAIL_NULL_V(img, Ref<Texture2D>()); img = img->duplicate(); @@ -109,14 +108,12 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, img->flip_x(); } - texture->create_from_image(img); - return texture; + return ImageTexture::create_from_image(img); } #ifdef MODULE_SVG_ENABLED // See also `generate_icon()` in `scene/resources/default_theme.cpp`. static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, float p_saturation = 1.0, Dictionary p_convert_colors = Dictionary()) { - Ref<ImageTexture> icon = memnew(ImageTexture); Ref<Image> img = memnew(Image); // Upsample icon generation only if the editor scale isn't an integer multiplier. @@ -129,9 +126,9 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, if (p_saturation != 1.0) { img->adjust_bcs(1.0, 1.0, p_saturation); } - icon->create_from_image(img); // in this case filter really helps - return icon; + // In this case filter really helps. + return ImageTexture::create_from_image(img); } #endif diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 654ac27146..af9c918360 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -990,7 +990,7 @@ ExportTemplateManager::ExportTemplateManager() { install_file_dialog->set_title(TTR("Select Template File")); install_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM); install_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE); - install_file_dialog->add_filter("*.tpz ; " + TTR("Godot Export Templates")); + install_file_dialog->add_filter("*.tpz", TTR("Godot Export Templates")); install_file_dialog->connect("file_selected", callable_mp(this, &ExportTemplateManager::_install_file_selected), varray(false)); add_child(install_file_dialog); diff --git a/editor/icons/MainMovieWriteEnabled.svg b/editor/icons/MainMovieWriteEnabled.svg deleted file mode 100644 index b12ea38bed..0000000000 --- a/editor/icons/MainMovieWriteEnabled.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2a6 6 0 0 0-6 6 6 6 0 0 0 6 6 6 6 0 0 0 4-1.535V14h.002a2 2 0 0 0 .266 1A2 2 0 0 0 14 16h1v-2h-.5a.5.5 0 0 1-.5-.5V8a6 6 0 0 0-6-6zm0 1a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm3.441 2a1 1 0 0 1 .89.5 1 1 0 0 1-.366 1.365 1 1 0 0 1-1.367-.365 1 1 0 0 1 .367-1.365A1 1 0 0 1 11.44 5zm-6.953.002a1 1 0 0 1 .547.133A1 1 0 0 1 5.402 6.5a1 1 0 0 1-1.367.365A1 1 0 0 1 3.67 5.5a1 1 0 0 1 .818-.498zM4.512 9a1 1 0 0 1 .89.5 1 1 0 0 1-.367 1.365A1 1 0 0 1 3.67 10.5a1 1 0 0 1 .365-1.365A1 1 0 0 1 4.512 9zm6.904.002a1 1 0 0 1 .549.133 1 1 0 0 1 .365 1.365 1 1 0 0 1-1.365.365 1 1 0 0 1-.367-1.365 1 1 0 0 1 .818-.498zM8 11a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1z" fill="#e0e0e0" style="fill:#ee5353;fill-opacity:1"/></svg> diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp index e5fe99890e..28653dac3e 100644 --- a/editor/import/resource_importer_texture_atlas.cpp +++ b/editor/import/resource_importer_texture_atlas.cpp @@ -88,13 +88,7 @@ Error ResourceImporterTextureAtlas::import(const String &p_source_file, const St //use an xpm because it's size independent, the editor images are vector and size dependent //it's a simple hack Ref<Image> broken = memnew(Image((const char **)atlas_import_failed_xpm)); - Ref<ImageTexture> broken_texture; - broken_texture.instantiate(); - broken_texture->create_from_image(broken); - - String target_file = p_save_path + ".tex"; - - ResourceSaver::save(target_file, broken_texture); + ResourceSaver::save(p_save_path + ".tex", ImageTexture::create_from_image(broken)); return OK; } @@ -308,9 +302,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file Ref<Texture2D> cache; cache = ResourceCache::get_ref(p_group_file); if (!cache.is_valid()) { - Ref<ImageTexture> res_cache; - res_cache.instantiate(); - res_cache->create_from_image(new_atlas); + Ref<ImageTexture> res_cache = ImageTexture::create_from_image(new_atlas); res_cache->set_path(p_group_file); cache = res_cache; } diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index e49d3b1013..0e2967dc42 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -1382,8 +1382,8 @@ SceneImportSettings::SceneImportSettings() { item_save_path = memnew(EditorFileDialog); item_save_path->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); - item_save_path->add_filter("*.tres; " + TTR("Text Resource")); - item_save_path->add_filter("*.res; " + TTR("Binary Resource")); + item_save_path->add_filter("*.tres", TTR("Text Resource")); + item_save_path->add_filter("*.res", TTR("Binary Resource")); add_child(item_save_path); item_save_path->connect("file_selected", callable_mp(this, &SceneImportSettings::_save_path_changed)); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index ad92911810..a509cf3d8f 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -219,12 +219,12 @@ void InspectorDock::_load_resource(const String &p_type) { load_resource_dialog->clear_filters(); for (int i = 0; i < extensions.size(); i++) { - load_resource_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + load_resource_dialog->add_filter("*." + extensions[i], extensions[i].to_upper()); } const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false); for (int i = 0; i < textfile_ext.size(); i++) { - load_resource_dialog->add_filter("*." + textfile_ext[i] + " ; " + textfile_ext[i].to_upper()); + load_resource_dialog->add_filter("*." + textfile_ext[i], textfile_ext[i].to_upper()); } load_resource_dialog->popup_file_dialog(); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 2e4dcab203..248ba021ce 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -215,7 +215,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { blend_space_draw->draw_rect(Rect2(Point2(), s), color, false); } - blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor); + blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor, Math::round(EDSCALE)); if (blend_space->get_min_space() < 0) { float point = 0.0; @@ -224,9 +224,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { float x = point; - blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor); + blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor, Math::round(EDSCALE)); blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor); - blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft); + blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft, Math::round(EDSCALE)); } if (snap->is_pressed()) { @@ -240,7 +240,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { int idx = int(v / blend_space->get_snap()); if (i > 0 && prev_idx != idx) { - blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft); + blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft, Math::round(EDSCALE)); } prev_idx = idx; @@ -297,10 +297,10 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { float mind = 5 * EDSCALE; float maxd = 15 * EDSCALE; - blend_space_draw->draw_line(gui_point + Vector2(mind, 0), gui_point + Vector2(maxd, 0), color, 2); - blend_space_draw->draw_line(gui_point + Vector2(-mind, 0), gui_point + Vector2(-maxd, 0), color, 2); - blend_space_draw->draw_line(gui_point + Vector2(0, mind), gui_point + Vector2(0, maxd), color, 2); - blend_space_draw->draw_line(gui_point + Vector2(0, -mind), gui_point + Vector2(0, -maxd), color, 2); + blend_space_draw->draw_line(gui_point + Vector2(mind, 0), gui_point + Vector2(maxd, 0), color, Math::round(2 * EDSCALE)); + blend_space_draw->draw_line(gui_point + Vector2(-mind, 0), gui_point + Vector2(-maxd, 0), color, Math::round(2 * EDSCALE)); + blend_space_draw->draw_line(gui_point + Vector2(0, mind), gui_point + Vector2(0, maxd), color, Math::round(2 * EDSCALE)); + blend_space_draw->draw_line(gui_point + Vector2(0, -mind), gui_point + Vector2(0, -maxd), color, Math::round(2 * EDSCALE)); } } diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 86addde87b..dfde63ecb6 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -407,22 +407,22 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { Color color = get_theme_color(SNAME("accent_color"), SNAME("Editor")); blend_space_draw->draw_rect(Rect2(Point2(), s), color, false); } - blend_space_draw->draw_line(Point2(1, 0), Point2(1, s.height - 1), linecolor); - blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor); + blend_space_draw->draw_line(Point2(1, 0), Point2(1, s.height - 1), linecolor, Math::round(EDSCALE)); + blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor, Math::round(EDSCALE)); - blend_space_draw->draw_line(Point2(0, 0), Point2(5 * EDSCALE, 0), linecolor); + blend_space_draw->draw_line(Point2(0, 0), Point2(5 * EDSCALE, 0), linecolor, Math::round(EDSCALE)); if (blend_space->get_min_space().y < 0) { int y = (blend_space->get_max_space().y / (blend_space->get_max_space().y - blend_space->get_min_space().y)) * s.height; - blend_space_draw->draw_line(Point2(0, y), Point2(5 * EDSCALE, y), linecolor); + blend_space_draw->draw_line(Point2(0, y), Point2(5 * EDSCALE, y), linecolor, Math::round(EDSCALE)); blend_space_draw->draw_string(font, Point2(2 * EDSCALE, y - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor); - blend_space_draw->draw_line(Point2(5 * EDSCALE, y), Point2(s.width, y), linecolor_soft); + blend_space_draw->draw_line(Point2(5 * EDSCALE, y), Point2(s.width, y), linecolor_soft, Math::round(EDSCALE)); } if (blend_space->get_min_space().x < 0) { int x = (-blend_space->get_min_space().x / (blend_space->get_max_space().x - blend_space->get_min_space().x)) * s.width; - blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor); + blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor, Math::round(EDSCALE)); blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor); - blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft); + blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft, Math::round(EDSCALE)); } if (snap->is_pressed()) { @@ -435,7 +435,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { int idx = int(v / blend_space->get_snap().x); if (i > 0 && prev_idx != idx) { - blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft); + blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft, Math::round(EDSCALE)); } prev_idx = idx; @@ -449,7 +449,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { int idx = int(v / blend_space->get_snap().y); if (i > 0 && prev_idx != idx) { - blend_space_draw->draw_line(Point2(0, i), Point2(s.width, i), linecolor_soft); + blend_space_draw->draw_line(Point2(0, i), Point2(s.width, i), linecolor_soft, Math::round(EDSCALE)); } prev_idx = idx; @@ -478,7 +478,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { } for (int j = 0; j < 3; j++) { - blend_space_draw->draw_line(points[j], points[(j + 1) % 3], linecolor, 1); + blend_space_draw->draw_line(points[j], points[(j + 1) % 3], linecolor, Math::round(EDSCALE), true); } Color color; @@ -533,9 +533,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { } for (int i = 0; i < points.size() - 1; i++) { - blend_space_draw->draw_line(points[i], points[i + 1], linecolor, 2); + blend_space_draw->draw_line(points[i], points[i + 1], linecolor, Math::round(2 * EDSCALE), true); } - blend_space_draw->draw_line(points[points.size() - 1], blend_space_draw->get_local_mouse_position(), linecolor, 2); + blend_space_draw->draw_line(points[points.size() - 1], blend_space_draw->get_local_mouse_position(), linecolor, Math::round(2 * EDSCALE), true); } ///draw cursor position @@ -564,15 +564,15 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { Color lcol = color; lcol.a *= 0.4; - blend_space_draw->draw_line(point, closest, lcol, 2); + blend_space_draw->draw_line(point, closest, lcol, Math::round(2 * EDSCALE), true); } float mind = 5 * EDSCALE; float maxd = 15 * EDSCALE; - blend_space_draw->draw_line(point + Vector2(mind, 0), point + Vector2(maxd, 0), color, 2); - blend_space_draw->draw_line(point + Vector2(-mind, 0), point + Vector2(-maxd, 0), color, 2); - blend_space_draw->draw_line(point + Vector2(0, mind), point + Vector2(0, maxd), color, 2); - blend_space_draw->draw_line(point + Vector2(0, -mind), point + Vector2(0, -maxd), color, 2); + blend_space_draw->draw_line(point + Vector2(mind, 0), point + Vector2(maxd, 0), color, Math::round(2 * EDSCALE)); + blend_space_draw->draw_line(point + Vector2(-mind, 0), point + Vector2(-maxd, 0), color, Math::round(2 * EDSCALE)); + blend_space_draw->draw_line(point + Vector2(0, mind), point + Vector2(0, maxd), color, Math::round(2 * EDSCALE)); + blend_space_draw->draw_line(point + Vector2(0, -mind), point + Vector2(0, -maxd), color, Math::round(2 * EDSCALE)); } } diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 1cc296534d..3d4701a54a 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -135,7 +135,7 @@ void AnimationPlayerEditor::_notification(int p_what) { 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.instantiate(); - autoplay_reset_icon->create_from_image(autoplay_reset_img); + autoplay_reset_icon->set_image(autoplay_reset_img); } stop->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 362dbf1220..bc95624dd5 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -165,14 +165,9 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const // Overlay and thumbnail need the same format for `blend_rect` to work. thumbnail->convert(Image::FORMAT_RGBA8); - thumbnail->blend_rect(overlay, overlay->get_used_rect(), overlay_pos); + preview_images[i].button->set_icon(ImageTexture::create_from_image(thumbnail)); - Ref<ImageTexture> tex; - tex.instantiate(); - tex->create_from_image(thumbnail); - - preview_images[i].button->set_icon(tex); // Make it clearer that clicking it will open an external link preview_images[i].button->set_default_cursor_shape(Control::CURSOR_POINTING_HAND); } else { @@ -790,9 +785,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB } break; } - Ref<ImageTexture> tex; - tex.instantiate(); - tex->create_from_image(image); + Ref<ImageTexture> tex = ImageTexture::create_from_image(image); obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, tex); image_set = true; @@ -1591,7 +1584,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { asset_open = memnew(EditorFileDialog); asset_open->set_access(EditorFileDialog::ACCESS_FILESYSTEM); - asset_open->add_filter("*.zip ; " + TTR("Assets ZIP File")); + asset_open->add_filter("*.zip", TTR("Assets ZIP File")); asset_open->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); add_child(asset_open); asset_open->connect("file_selected", callable_mp(this, &EditorAssetLibrary::_asset_file_selected)); diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp index 9003c4480b..657c5a36b6 100644 --- a/editor/plugins/bit_map_editor_plugin.cpp +++ b/editor/plugins/bit_map_editor_plugin.cpp @@ -33,11 +33,7 @@ #include "editor/editor_scale.h" void BitMapEditor::setup(const Ref<BitMap> &p_bitmap) { - Ref<ImageTexture> texture; - texture.instantiate(); - texture->create_from_image(p_bitmap->convert_to_image()); - texture_rect->set_texture(texture); - + texture_rect->set_texture(ImageTexture::create_from_image(p_bitmap->convert_to_image())); size_label->set_text(vformat(String::utf8("%s×%s"), p_bitmap->get_size().width, p_bitmap->get_size().height)); } diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 79025041d3..a7c3c32120 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -257,7 +257,7 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin() { List<String> ext; ImageLoader::get_recognized_extensions(&ext); for (const String &E : ext) { - file->add_filter("*." + E + "; " + E.to_upper()); + file->add_filter("*." + E, E.to_upper()); } file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); toolbar->add_child(file); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 654c92c532..66e58339ed 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -841,9 +841,5 @@ Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, cons prev_y = y; } - - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - - ptex->create_from_image(img_ref); - return ptex; + return ImageTexture::create_from_image(img_ref); } diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index a00ed1e49a..478f4264e5 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -127,13 +127,9 @@ Ref<Texture2D> EditorTexturePreviewPlugin::generate(const Ref<Resource> &p_from, } Vector2i new_size_i(MAX(1, (int)new_size.x), MAX(1, (int)new_size.y)); img->resize(new_size_i.x, new_size_i.y, Image::INTERPOLATE_CUBIC); - post_process_preview(img); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - - ptex->create_from_image(img); - return ptex; + return ImageTexture::create_from_image(img); } EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() { @@ -171,14 +167,9 @@ Ref<Texture2D> EditorImagePreviewPlugin::generate(const Ref<Resource> &p_from, c new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y); } img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC); - post_process_preview(img); - Ref<ImageTexture> ptex; - ptex.instantiate(); - - ptex->create_from_image(img); - return ptex; + return ImageTexture::create_from_image(img); } EditorImagePreviewPlugin::EditorImagePreviewPlugin() { @@ -239,13 +230,9 @@ Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const Ref<Resource> &p_from, new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y); } img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC); - post_process_preview(img); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - - ptex->create_from_image(img); - return ptex; + return ImageTexture::create_from_image(img); } bool EditorBitmapPreviewPlugin::generate_small_preview_automatically() const { @@ -282,11 +269,8 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String & img.instantiate(); Error err = img->load(path); if (err == OK) { - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - post_process_preview(img); - ptex->create_from_image(img); - return ptex; + return ImageTexture::create_from_image(img); } else { return Ref<Texture2D>(); @@ -336,9 +320,7 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const Ref<Resource> &p_from int thumbnail_size = MAX(p_size.x, p_size.y); img->resize(thumbnail_size, thumbnail_size, Image::INTERPOLATE_CUBIC); post_process_preview(img); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img); - return ptex; + return ImageTexture::create_from_image(img); } return Ref<Texture2D>(); @@ -591,13 +573,8 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from, } } } - post_process_preview(img); - - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - - ptex->create_from_image(img); - return ptex; + return ImageTexture::create_from_image(img); } EditorScriptPreviewPlugin::EditorScriptPreviewPlugin() { @@ -676,12 +653,10 @@ Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const Ref<Resource> &p_f //post_process_preview(img); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); Ref<Image> image; image.instantiate(); image->create(w, h, false, Image::FORMAT_RGB8, img); - ptex->create_from_image(image); - return ptex; + return ImageTexture::create_from_image(image); } EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() { @@ -746,12 +721,9 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const Ref<Resource> &p_from, co new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y); } img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC); - post_process_preview(img); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img); - return ptex; + return ImageTexture::create_from_image(img); } EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() { @@ -859,13 +831,9 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path, new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y); } img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC); - post_process_preview(img); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img); - - return ptex; + return ImageTexture::create_from_image(img); } Ref<Texture2D> EditorFontPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const { @@ -915,11 +883,7 @@ Ref<Texture2D> EditorGradientPreviewPlugin::generate(const Ref<Resource> &p_from ptex.instantiate(); ptex->set_width(p_size.width * GRADIENT_PREVIEW_TEXTURE_SCALE_FACTOR * EDSCALE); ptex->set_gradient(gradient); - - Ref<ImageTexture> itex; - itex.instantiate(); - itex->create_from_image(ptex->get_image()); - return itex; + return ImageTexture::create_from_image(ptex->get_image()); } return Ref<Texture2D>(); } diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 72caa15e9c..8e6687c836 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -299,12 +299,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { img.instantiate(); img->create(w, h, false, Image::FORMAT_RGF, texdata); - - Ref<ImageTexture> imgt; - imgt.instantiate(); - imgt->create_from_image(img); - - pm->set_emission_point_texture(imgt); + pm->set_emission_point_texture(ImageTexture::create_from_image(img)); pm->set_emission_point_count(vpc); if (capture_colors) { @@ -320,10 +315,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { img.instantiate(); img->create(w, h, false, Image::FORMAT_RGBA8, colordata); - - imgt.instantiate(); - imgt->create_from_image(img); - pm->set_emission_color_texture(imgt); + pm->set_emission_color_texture(ImageTexture::create_from_image(img)); } if (valid_normals.size()) { @@ -343,10 +335,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { img.instantiate(); img->create(w, h, false, Image::FORMAT_RGF, normdata); - - imgt.instantiate(); - imgt->create_from_image(img); - pm->set_emission_normal_texture(imgt); + pm->set_emission_normal_texture(ImageTexture::create_from_image(img)); } else { pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); @@ -391,7 +380,7 @@ GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin() { List<String> ext; ImageLoader::get_recognized_extensions(&ext); for (const String &E : ext) { - file->add_filter("*." + E + "; " + E.to_upper()); + file->add_filter("*." + E, E.to_upper()); } file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); toolbar->add_child(file); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index a23a330409..6750f1aa9c 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -363,10 +363,7 @@ void GPUParticles3DEditor::_generate_emission_points() { } Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img)); - - Ref<ImageTexture> tex; - tex.instantiate(); - tex->create_from_image(image); + Ref<ImageTexture> tex = ImageTexture::create_from_image(image); Ref<ParticlesMaterial> material = node->get_process_material(); ERR_FAIL_COND(material.is_null()); @@ -392,12 +389,7 @@ void GPUParticles3DEditor::_generate_emission_points() { } Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2)); - - Ref<ImageTexture> tex2; - tex2.instantiate(); - tex2->create_from_image(image2); - - material->set_emission_normal_texture(tex2); + material->set_emission_normal_texture(ImageTexture::create_from_image(image2)); } else { material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); material->set_emission_point_count(point_count); diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp index aef97f059a..8413c5e875 100644 --- a/editor/plugins/lightmap_gi_editor_plugin.cpp +++ b/editor/plugins/lightmap_gi_editor_plugin.cpp @@ -138,7 +138,7 @@ LightmapGIEditorPlugin::LightmapGIEditorPlugin() { file_dialog = memnew(EditorFileDialog); file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); - file_dialog->add_filter("*.lmbake ; " + TTR("LightMap Bake")); + file_dialog->add_filter("*.lmbake", TTR("LightMap Bake")); file_dialog->set_title(TTR("Select lightmap bake file:")); file_dialog->connect("file_selected", callable_mp(this, &LightmapGIEditorPlugin::_bake_select_file)); bake->add_child(file_dialog); diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index d4604ebb21..72bfc05270 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -263,7 +263,7 @@ MeshLibraryEditor::MeshLibraryEditor() { file->clear_filters(); file->set_title(TTR("Import Scene")); for (int i = 0; i < extensions.size(); i++) { - file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + file->add_filter("*." + extensions[i], extensions[i].to_upper()); } add_child(file); file->connect("file_selected", callable_mp(this, &MeshLibraryEditor::_import_scene_cbk)); diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.cpp b/editor/plugins/occluder_instance_3d_editor_plugin.cpp index d5fc51aea4..365f74d7a3 100644 --- a/editor/plugins/occluder_instance_3d_editor_plugin.cpp +++ b/editor/plugins/occluder_instance_3d_editor_plugin.cpp @@ -113,7 +113,7 @@ OccluderInstance3DEditorPlugin::OccluderInstance3DEditorPlugin() { file_dialog = memnew(EditorFileDialog); file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); - file_dialog->add_filter("*.occ ; Occluder3D"); + file_dialog->add_filter("*.occ", "Occluder3D"); file_dialog->set_title(TTR("Select occluder bake file:")); file_dialog->connect("file_selected", callable_mp(this, &OccluderInstance3DEditorPlugin::_bake_select_file)); bake->add_child(file_dialog); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 427b061558..f4d42ff456 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1188,7 +1188,7 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog->clear_filters(); for (const String &E : textfile_extensions) { - file_dialog->add_filter("*." + E + " ; " + E.to_upper()); + file_dialog->add_filter("*." + E, E.to_upper()); } file_dialog->popup_file_dialog(); file_dialog->set_title(TTR("New Text File...")); @@ -1203,11 +1203,11 @@ void ScriptEditor::_menu_option(int p_option) { ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); file_dialog->clear_filters(); for (int i = 0; i < extensions.size(); i++) { - file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + file_dialog->add_filter("*." + extensions[i], extensions[i].to_upper()); } for (const String &E : textfile_extensions) { - file_dialog->add_filter("*." + E + " ; " + E.to_upper()); + file_dialog->add_filter("*." + E, E.to_upper()); } file_dialog->popup_file_dialog(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 7c3520c39d..66cd85a26a 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1865,11 +1865,7 @@ void ScriptTextEditor::_enable_code_editor() { // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); - if (default_color_mode == 1) { - color_picker->set_hsv_mode(true); - } else if (default_color_mode == 2) { - color_picker->set_raw_mode(true); - } + color_picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode); int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape"); color_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 68e6e5dcc0..129af1bb1d 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -2080,7 +2080,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito List<String> ext; ResourceLoader::get_recognized_extensions_for_type("Theme", &ext); for (const String &E : ext) { - import_another_theme_dialog->add_filter(vformat("*.%s; %s", E, TTR("Theme Resource"))); + import_another_theme_dialog->add_filter("*." + E, TTR("Theme Resource")); } import_another_file_hb->add_child(import_another_theme_dialog); import_another_theme_dialog->connect("file_selected", callable_mp(this, &ThemeItemEditorDialog::_select_another_theme_cbk)); @@ -3663,7 +3663,7 @@ ThemeEditor::ThemeEditor() { List<String> ext; ResourceLoader::get_recognized_extensions_for_type("PackedScene", &ext); for (const String &E : ext) { - preview_scene_dialog->add_filter(vformat("*.%s; %s", E, TTR("Scene"))); + preview_scene_dialog->add_filter("*." + E, TTR("Scene")); } main_hs->add_child(preview_scene_dialog); preview_scene_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_preview_scene_dialog_cbk)); diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp index fb4d5d5c88..3fe6778f48 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -116,12 +116,8 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla } } - Ref<ImageTexture> output_image_texture; - output_image_texture.instantiate(); - output_image_texture->create_from_image(output_image); - merged->set_name(p_atlas_sources[0]->get_name()); - merged->set_texture(output_image_texture); + merged->set_texture(ImageTexture::create_from_image(output_image)); merged->set_texture_region_size(new_texture_region_size); } } diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 543304346e..419d0ffcfc 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -121,12 +121,9 @@ void TilesEditorPlugin::_thread() { pattern_preview_done.wait(); Ref<Image> image = viewport->get_texture()->get_image(); - Ref<ImageTexture> image_texture; - image_texture.instantiate(); - image_texture->create_from_image(image); // Find the index for the given pattern. TODO: optimize. - Variant args[] = { item.pattern, image_texture }; + Variant args[] = { item.pattern, ImageTexture::create_from_image(image) }; const Variant *args_ptr[] = { &args[0], &args[1] }; Variant r; Callable::CallError error; diff --git a/editor/project_export.cpp b/editor/project_export.cpp index a05a73685e..209c997d58 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -892,7 +892,7 @@ void ProjectExportDialog::_export_project() { List<String> extension_list = platform->get_binary_extensions(current); for (int i = 0; i < extension_list.size(); i++) { // TRANSLATORS: This is the name of a project export file format. %s will be replaced by the platform name. - export_project->add_filter(vformat("*.%s; %s", extension_list[i], vformat(TTR("%s Export"), platform->get_name()))); + export_project->add_filter("*." + extension_list[i], vformat(TTR("%s Export"), platform->get_name())); } if (!current->get_export_path().is_empty()) { @@ -1222,8 +1222,8 @@ ProjectExportDialog::ProjectExportDialog() { export_all_button->set_disabled(true); export_pck_zip = memnew(EditorFileDialog); - export_pck_zip->add_filter("*.zip ; " + TTR("ZIP File")); - export_pck_zip->add_filter("*.pck ; " + TTR("Godot Project Pack")); + export_pck_zip->add_filter("*.zip", TTR("ZIP File")); + export_pck_zip->add_filter("*.pck", TTR("Godot Project Pack")); export_pck_zip->set_access(EditorFileDialog::ACCESS_FILESYSTEM); export_pck_zip->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); add_child(export_pck_zip); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 0f9ecca4de..f7ef574205 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -362,8 +362,8 @@ private: if (mode == MODE_IMPORT) { fdialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); fdialog->clear_filters(); - fdialog->add_filter(vformat("project.godot ; %s %s", VERSION_NAME, TTR("Project"))); - fdialog->add_filter("*.zip ; " + TTR("ZIP File")); + fdialog->add_filter("project.godot", vformat("%s %s", VERSION_NAME, TTR("Project"))); + fdialog->add_filter("*.zip", TTR("ZIP File")); } else { fdialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR); } @@ -1167,9 +1167,7 @@ void ProjectList::load_project_icon(int p_index) { Error err = img->load(item.icon.replace_first("res://", item.path + "/")); if (err == OK) { img->resize(default_icon->get_width(), default_icon->get_height(), Image::INTERPOLATE_LANCZOS); - Ref<ImageTexture> it = memnew(ImageTexture); - it->create_from_image(img); - icon = it; + icon = ImageTexture::create_from_image(img); } } if (icon.is_null()) { @@ -2797,7 +2795,7 @@ ProjectManager::ProjectManager() { tabs->add_child(asset_library); asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project)); } else { - WARN_PRINT("Asset Library not available, as it requires SSL to work."); + print_verbose("Asset Library not available (due to using Web editor, or SSL support disabled)."); } { diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index d936e821df..277ae14e0e 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -145,7 +145,7 @@ void CustomPropertyEditor::_menu_option(int p_which) { file->clear_filters(); for (const String &E : valid_extensions) { - file->add_filter("*." + E + " ; " + E.to_upper()); + file->add_filter("*." + E, E.to_upper()); } file->popup_file_dialog(); @@ -831,11 +831,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); - if (default_color_mode == 1) { - color_picker->set_hsv_mode(true); - } else if (default_color_mode == 2) { - color_picker->set_raw_mode(true); - } + color_picker->set_color_mode((ColorPicker::ColorModeType)default_color_mode); int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape"); color_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape); @@ -1227,7 +1223,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) { filter = "*." + extensions[i]; } - file->add_filter(filter + " ; " + extensions[i].to_upper()); + file->add_filter(filter, extensions[i].to_upper()); } } file->popup_file_dialog(); @@ -1311,7 +1307,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) { ResourceLoader::get_recognized_extensions_for_type(type, &extensions); file->clear_filters(); for (const String &E : extensions) { - file->add_filter("*." + E + " ; " + E.to_upper()); + file->add_filter("*." + E, E.to_upper()); } file->popup_file_dialog(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 9d92a9b7d2..fb8be5db81 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -910,7 +910,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { ResourceSaver::get_recognized_extensions(sd, &extensions); new_scene_from_dialog->clear_filters(); for (int i = 0; i < extensions.size(); i++) { - new_scene_from_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + new_scene_from_dialog->add_filter("*." + extensions[i], extensions[i].to_upper()); } String existing; diff --git a/main/main.cpp b/main/main.cpp index eb401cd9ef..2bb67f17f1 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2198,6 +2198,13 @@ bool Main::start() { #endif } + uint64_t minimum_time_msec = GLOBAL_DEF("application/boot_splash/minimum_display_time", 0); + ProjectSettings::get_singleton()->set_custom_property_info("application/boot_splash/minimum_display_time", + PropertyInfo(Variant::INT, + "application/boot_splash/minimum_display_time", + PROPERTY_HINT_RANGE, + "0,100,1,or_greater,suffix:ms")); // No negative numbers. + #ifdef TOOLS_ENABLED if (!doc_tool_path.is_empty()) { // Needed to instance editor-only classes for their default values @@ -2718,6 +2725,15 @@ bool Main::start() { if (movie_writer) { movie_writer->begin(DisplayServer::get_singleton()->window_get_size(), fixed_fps, write_movie_path); } + + if (minimum_time_msec) { + uint64_t minimum_time = 1000 * minimum_time_msec; + uint64_t elapsed_time = OS::get_singleton()->get_ticks_usec(); + if (elapsed_time < minimum_time) { + OS::get_singleton()->delay_usec(minimum_time - elapsed_time); + } + } + return true; } diff --git a/misc/scripts/install_vulkan_sdk_macos.sh b/misc/scripts/install_vulkan_sdk_macos.sh new file mode 100755 index 0000000000..e03a907749 --- /dev/null +++ b/misc/scripts/install_vulkan_sdk_macos.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -euo pipefail +IFS=$'\n\t' + +# Download and install the Vulkan SDK. +curl -LO "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.dmg" +hdiutil attach vulkan-sdk.dmg -mountpoint /Volumes/vulkan-sdk +/Volumes/vulkan-sdk/InstallVulkan.app/Contents/MacOS/InstallVulkan \ + --accept-licenses --default-answer --confirm-command install +hdiutil detach /Volumes/vulkan-sdk + +echo 'Vulkan SDK installed successfully! You can now build Godot by running "scons".' diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 2c0e604e66..eb5614338b 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -409,9 +409,7 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig } Ref<Image> img = memnew(Image(width, height, mipmaps - 1, info.format, src_data)); - - Ref<ImageTexture> texture = memnew(ImageTexture); - texture->create_from_image(img); + Ref<ImageTexture> texture = ImageTexture::create_from_image(img); if (r_error) { *r_error = OK; diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 049be47ca8..e995cce651 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -285,16 +285,15 @@ <description> </description> </annotation> - <annotation name="@export_exp_easing"> + <annotation name="@export_exp_easing" qualifiers="vararg"> <return type="void" /> - <argument index="0" name="hint1" type="String" default="null" /> - <argument index="1" name="hint2" type="String" default="null" /> + <argument index="0" name="hints" type="String" default="""" /> <description> </description> </annotation> <annotation name="@export_file" qualifiers="vararg"> <return type="void" /> - <argument index="0" name="filter" type="String" default="null" /> + <argument index="0" name="filter" type="String" default="""" /> <description> </description> </annotation> @@ -341,14 +340,14 @@ </annotation> <annotation name="@export_global_file" qualifiers="vararg"> <return type="void" /> - <argument index="0" name="filter" type="String" default="null" /> + <argument index="0" name="filter" type="String" default="""" /> <description> </description> </annotation> <annotation name="@export_group"> <return type="void" /> <argument index="0" name="name" type="String" /> - <argument index="1" name="prefix" type="String" default="null" /> + <argument index="1" name="prefix" type="String" default="""" /> <description> </description> </annotation> @@ -359,7 +358,7 @@ </annotation> <annotation name="@export_node_path" qualifiers="vararg"> <return type="void" /> - <argument index="0" name="type" type="String" default="null" /> + <argument index="0" name="type" type="String" default="""" /> <description> </description> </annotation> @@ -368,21 +367,19 @@ <description> </description> </annotation> - <annotation name="@export_range"> + <annotation name="@export_range" qualifiers="vararg"> <return type="void" /> <argument index="0" name="min" type="float" /> <argument index="1" name="max" type="float" /> - <argument index="2" name="step" type="float" default="null" /> - <argument index="3" name="slider1" type="String" default="null" /> - <argument index="4" name="slider2" type="String" default="null" /> - <argument index="5" name="slider3" type="String" default="null" /> + <argument index="2" name="step" type="float" default="1.0" /> + <argument index="3" name="extra_hints" type="String" default="""" /> <description> </description> </annotation> <annotation name="@export_subgroup"> <return type="void" /> <argument index="0" name="name" type="String" /> - <argument index="1" name="prefix" type="String" default="null" /> + <argument index="1" name="prefix" type="String" default="""" /> <description> </description> </annotation> @@ -399,10 +396,10 @@ </annotation> <annotation name="@rpc" qualifiers="vararg"> <return type="void" /> - <argument index="0" name="mode" type="String" default="null" /> - <argument index="1" name="sync" type="String" default="null" /> - <argument index="2" name="transfer_mode" type="String" default="null" /> - <argument index="3" name="transfer_channel" type="int" default="null" /> + <argument index="0" name="mode" type="String" default="""" /> + <argument index="1" name="sync" type="String" default="""" /> + <argument index="2" name="transfer_mode" type="String" default="""" /> + <argument index="3" name="transfer_channel" type="int" default="0" /> <description> </description> </annotation> diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 233da87aee..4ec56906bf 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -117,18 +117,18 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation); // Export annotations. register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); - register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::INT>, 0, true); - register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, 1, true); + register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::INT>, varray(), true); + register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true); register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>); - register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, 1, true); + register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true); register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>); register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_placeholder"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); - register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "slider1"), PropertyInfo(Variant::STRING, "slider2"), PropertyInfo(Variant::STRING, "slider3")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, 4); - register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hint1"), PropertyInfo(Variant::STRING, "hint2")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, 2); + register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "extra_hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, varray(1.0, ""), true); + register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, varray(""), true); register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); - register_annotation(MethodInfo("@export_node_path", PropertyInfo(Variant::STRING, "type")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, 1, true); - register_annotation(MethodInfo("@export_flags", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FLAGS, Variant::INT>, 0, true); + register_annotation(MethodInfo("@export_node_path", PropertyInfo(Variant::STRING, "type")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, varray(""), true); + register_annotation(MethodInfo("@export_flags", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FLAGS, Variant::INT>, varray(), true); register_annotation(MethodInfo("@export_flags_2d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_RENDER, Variant::INT>); register_annotation(MethodInfo("@export_flags_2d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_2d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_NAVIGATION, Variant::INT>); @@ -137,12 +137,12 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); // Export grouping annotations. register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>); - register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, 1); - register_annotation(MethodInfo("@export_subgroup", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_SUBGROUP>, 1); + register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, varray("")); + register_annotation(MethodInfo("@export_subgroup", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_SUBGROUP>, varray("")); // Warning annotations. - register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true); + register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, varray(), true); // Networking. - register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true); + register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, varray("", "", "", 0), true); } GDScriptParser::~GDScriptParser() { @@ -162,6 +162,7 @@ void GDScriptParser::clear() { for_completion = false; errors.clear(); multiline_stack.clear(); + nodes_in_progress.clear(); } void GDScriptParser::push_error(const String &p_message, const Node *p_origin) { @@ -413,6 +414,9 @@ GDScriptTokenizer::Token GDScriptParser::advance() { push_error(current.literal); current = tokenizer.scan(); } + for (Node *n : nodes_in_progress) { + update_extents(n); + } return previous; } @@ -609,6 +613,7 @@ void GDScriptParser::parse_program() { } parse_class_body(true); + complete_extents(head); #ifdef TOOLS_ENABLED for (const KeyValue<int, GDScriptTokenizer::CommentData> &E : tokenizer.get_comments()) { @@ -649,6 +654,7 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class() { if (multiline && !consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block after class declaration.)")) { current_class = previous_class; + complete_extents(n_class); return n_class; } @@ -661,6 +667,7 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class() { } parse_class_body(multiline); + complete_extents(n_class); if (multiline) { consume(GDScriptTokenizer::Token::DEDENT, R"(Missing unindent at the end of the class body.)"); @@ -870,11 +877,13 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable() { } GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_property) { + VariableNode *variable = alloc_node<VariableNode>(); + if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected variable name after "var".)")) { + complete_extents(variable); return nullptr; } - VariableNode *variable = alloc_node<VariableNode>(); variable->identifier = parse_identifier(); variable->export_info.name = variable->identifier->name; @@ -882,10 +891,10 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper if (check(GDScriptTokenizer::Token::NEWLINE)) { if (p_allow_property) { advance(); - return parse_property(variable, true); } else { push_error(R"(Expected type after ":")"); + complete_extents(variable); return nullptr; } } else if (check((GDScriptTokenizer::Token::EQUAL))) { @@ -924,6 +933,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper } } + complete_extents(variable); end_statement("variable declaration"); return variable; @@ -932,6 +942,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_variable, bool p_need_indent) { if (p_need_indent) { if (!consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block for property after ":".)")) { + complete_extents(p_variable); return nullptr; } } @@ -941,6 +952,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_var make_completion_context(COMPLETION_PROPERTY_DECLARATION, property); if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected "get" or "set" for property declaration.)")) { + complete_extents(p_variable); return nullptr; } @@ -997,6 +1009,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_var } function = parse_identifier(); } + complete_extents(p_variable); if (p_variable->property == VariableNode::PROP_SETGET) { end_statement("property declaration"); @@ -1011,37 +1024,37 @@ GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_var void GDScriptParser::parse_property_setter(VariableNode *p_variable) { switch (p_variable->property) { case VariableNode::PROP_INLINE: { - consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after "set".)"); - if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected parameter name after "(".)")) { - p_variable->setter_parameter = parse_identifier(); - } - consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after parameter name.)*"); - consume(GDScriptTokenizer::Token::COLON, R"*(Expected ":" after ")".)*"); - + FunctionNode *function = alloc_node<FunctionNode>(); IdentifierNode *identifier = alloc_node<IdentifierNode>(); + complete_extents(identifier); identifier->name = "@" + p_variable->identifier->name + "_setter"; - - FunctionNode *function = alloc_node<FunctionNode>(); function->identifier = identifier; - FunctionNode *previous_function = current_function; - current_function = function; + consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after "set".)"); ParameterNode *parameter = alloc_node<ParameterNode>(); - parameter->identifier = p_variable->setter_parameter; - - if (parameter->identifier != nullptr) { + if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected parameter name after "(".)")) { + reset_extents(parameter, previous); + p_variable->setter_parameter = parse_identifier(); + parameter->identifier = p_variable->setter_parameter; function->parameters_indices[parameter->identifier->name] = 0; function->parameters.push_back(parameter); + } + complete_extents(parameter); + consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after parameter name.)*"); + consume(GDScriptTokenizer::Token::COLON, R"*(Expected ":" after ")".)*"); + + FunctionNode *previous_function = current_function; + current_function = function; + if (p_variable->setter_parameter != nullptr) { SuiteNode *body = alloc_node<SuiteNode>(); body->add_local(parameter, function); - function->body = parse_suite("setter declaration", body); p_variable->setter = function; } - current_function = previous_function; + complete_extents(function); break; } case VariableNode::PROP_SETGET: @@ -1059,12 +1072,13 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) { void GDScriptParser::parse_property_getter(VariableNode *p_variable) { switch (p_variable->property) { case VariableNode::PROP_INLINE: { + FunctionNode *function = alloc_node<FunctionNode>(); + consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "get".)"); IdentifierNode *identifier = alloc_node<IdentifierNode>(); + complete_extents(identifier); identifier->name = "@" + p_variable->identifier->name + "_getter"; - - FunctionNode *function = alloc_node<FunctionNode>(); function->identifier = identifier; FunctionNode *previous_function = current_function; @@ -1072,9 +1086,10 @@ void GDScriptParser::parse_property_getter(VariableNode *p_variable) { SuiteNode *body = alloc_node<SuiteNode>(); function->body = parse_suite("getter declaration", body); - p_variable->getter = function; + current_function = previous_function; + complete_extents(function); break; } case VariableNode::PROP_SETGET: @@ -1090,11 +1105,12 @@ void GDScriptParser::parse_property_getter(VariableNode *p_variable) { } GDScriptParser::ConstantNode *GDScriptParser::parse_constant() { + ConstantNode *constant = alloc_node<ConstantNode>(); + if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected constant name after "const".)")) { return nullptr; } - ConstantNode *constant = alloc_node<ConstantNode>(); constant->identifier = parse_identifier(); if (match(GDScriptTokenizer::Token::COLON)) { @@ -1113,12 +1129,15 @@ GDScriptParser::ConstantNode *GDScriptParser::parse_constant() { if (constant->initializer == nullptr) { push_error(R"(Expected initializer expression for constant.)"); + complete_extents(constant); return nullptr; } } else { + complete_extents(constant); return nullptr; } + complete_extents(constant); end_statement("constant declaration"); return constant; @@ -1148,15 +1167,18 @@ GDScriptParser::ParameterNode *GDScriptParser::parse_parameter() { parameter->default_value = parse_expression(false); } + complete_extents(parameter); return parameter; } GDScriptParser::SignalNode *GDScriptParser::parse_signal() { + SignalNode *signal = alloc_node<SignalNode>(); + if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected signal name after "signal".)")) { + complete_extents(signal); return nullptr; } - SignalNode *signal = alloc_node<SignalNode>(); signal->identifier = parse_identifier(); if (check(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) { @@ -1188,6 +1210,7 @@ GDScriptParser::SignalNode *GDScriptParser::parse_signal() { consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after signal parameters.)*"); } + complete_extents(signal); end_statement("signal declaration"); return signal; @@ -1299,6 +1322,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() { } #endif // TOOLS_ENABLED + complete_extents(enum_node); end_statement("enum"); return enum_node; @@ -1350,19 +1374,22 @@ void GDScriptParser::parse_function_signature(FunctionNode *p_function, SuiteNod } GDScriptParser::FunctionNode *GDScriptParser::parse_function() { + FunctionNode *function = alloc_node<FunctionNode>(); + bool _static = false; if (previous.type == GDScriptTokenizer::Token::STATIC) { // TODO: Improve message if user uses "static" with "var" or "const" if (!consume(GDScriptTokenizer::Token::FUNC, R"(Expected "func" after "static".)")) { + complete_extents(function); return nullptr; } _static = true; } - FunctionNode *function = alloc_node<FunctionNode>(); make_completion_context(COMPLETION_OVERRIDE_METHOD, function); if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) { + complete_extents(function); return nullptr; } @@ -1384,6 +1411,7 @@ GDScriptParser::FunctionNode *GDScriptParser::parse_function() { function->body = parse_suite("function declaration", body); current_function = previous_function; + complete_extents(function); return function; } @@ -1431,6 +1459,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali } pop_completion_call(); } + complete_extents(annotation); match(GDScriptTokenizer::Token::NEWLINE); // Newline after annotation is optional. @@ -1449,12 +1478,12 @@ void GDScriptParser::clear_unused_annotations() { annotation_stack.clear(); } -bool GDScriptParser::register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, int p_optional_arguments, bool p_is_vararg) { +bool GDScriptParser::register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, const Vector<Variant> &p_default_arguments, bool p_is_vararg) { ERR_FAIL_COND_V_MSG(valid_annotations.has(p_info.name), false, vformat(R"(Annotation "%s" already registered.)", p_info.name)); AnnotationInfo new_annotation; new_annotation.info = p_info; - new_annotation.info.default_arguments.resize(p_optional_arguments); + new_annotation.info.default_arguments = p_default_arguments; if (p_is_vararg) { new_annotation.info.flags |= METHOD_FLAG_VARARG; } @@ -1480,9 +1509,11 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, if (multiline) { if (!consume(GDScriptTokenizer::Token::INDENT, vformat(R"(Expected indented block after %s.)", p_context))) { current_suite = suite->parent_block; + complete_extents(suite); return suite; } } + reset_extents(suite, current); int error_count = 0; @@ -1532,6 +1563,8 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, } while ((multiline || previous.type == GDScriptTokenizer::Token::SEMICOLON) && !check(GDScriptTokenizer::Token::DEDENT) && !lambda_ended && !is_at_end()); + complete_extents(suite); + if (multiline) { if (!lambda_ended) { consume(GDScriptTokenizer::Token::DEDENT, vformat(R"(Missing unindent at the end of %s.)", p_context)); @@ -1562,6 +1595,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { case GDScriptTokenizer::Token::PASS: advance(); result = alloc_node<PassNode>(); + complete_extents(result); end_statement(R"("pass")"); break; case GDScriptTokenizer::Token::VAR: @@ -1609,6 +1643,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { // If this fails the expression will be nullptr, but that's the same as no return, so it's fine. n_return->return_value = parse_expression(false); } + complete_extents(n_return); result = n_return; current_suite->has_return = true; @@ -1619,6 +1654,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { case GDScriptTokenizer::Token::BREAKPOINT: advance(); result = alloc_node<BreakpointNode>(); + complete_extents(result); end_statement(R"("breakpoint")"); break; case GDScriptTokenizer::Token::ASSERT: @@ -1710,6 +1746,7 @@ GDScriptParser::AssertNode *GDScriptParser::parse_assert() { assert->condition = parse_expression(false); if (assert->condition == nullptr) { push_error("Expected expression to assert."); + complete_extents(assert); return nullptr; } @@ -1718,12 +1755,14 @@ GDScriptParser::AssertNode *GDScriptParser::parse_assert() { assert->message = parse_expression(false); if (assert->message == nullptr) { push_error(R"(Expected error message for assert after ",".)"); + complete_extents(assert); return nullptr; } } consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after assert expression.)*"); + complete_extents(assert); end_statement(R"("assert")"); return assert; @@ -1733,8 +1772,10 @@ GDScriptParser::BreakNode *GDScriptParser::parse_break() { if (!can_break) { push_error(R"(Cannot use "break" outside of a loop.)"); } + BreakNode *break_node = alloc_node<BreakNode>(); + complete_extents(break_node); end_statement(R"("break")"); - return alloc_node<BreakNode>(); + return break_node; } GDScriptParser::ContinueNode *GDScriptParser::parse_continue() { @@ -1742,9 +1783,10 @@ GDScriptParser::ContinueNode *GDScriptParser::parse_continue() { push_error(R"(Cannot use "continue" outside of a loop or pattern matching block.)"); } current_suite->has_continue = true; - end_statement(R"("continue")"); ContinueNode *cont = alloc_node<ContinueNode>(); cont->is_for_match = is_continue_match; + complete_extents(cont); + end_statement(R"("continue")"); return cont; } @@ -1786,6 +1828,7 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() { suite->parent_for = n_for; n_for->loop = parse_suite(R"("for" block)", suite); + complete_extents(n_for); // Reset break/continue state. can_break = could_break; @@ -1813,15 +1856,16 @@ GDScriptParser::IfNode *GDScriptParser::parse_if(const String &p_token) { } if (match(GDScriptTokenizer::Token::ELIF)) { - IfNode *elif = parse_if("elif"); - SuiteNode *else_block = alloc_node<SuiteNode>(); + IfNode *elif = parse_if("elif"); else_block->statements.push_back(elif); + complete_extents(else_block); n_if->false_block = else_block; } else if (match(GDScriptTokenizer::Token::ELSE)) { consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "else".)"); n_if->false_block = parse_suite(R"("else" block)"); } + complete_extents(n_if); if (n_if->false_block != nullptr && n_if->false_block->has_return && n_if->true_block->has_return) { current_suite->has_return = true; @@ -1845,6 +1889,7 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { consume(GDScriptTokenizer::Token::NEWLINE, R"(Expected a newline after "match" statement.)"); if (!consume(GDScriptTokenizer::Token::INDENT, R"(Expected an indented block after "match" statement.)")) { + complete_extents(match); return match; } @@ -1862,7 +1907,7 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { } #ifdef DEBUG_ENABLED - if (have_wildcard_without_continue) { + if (have_wildcard_without_continue && !branch->patterns.is_empty()) { push_warning(branch->patterns[0], GDScriptWarning::UNREACHABLE_PATTERN); } @@ -1878,6 +1923,7 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { #endif match->branches.push_back(branch); } + complete_extents(match); consume(GDScriptTokenizer::Token::DEDENT, R"(Expected an indented block after "match" statement.)"); @@ -1892,6 +1938,7 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { MatchBranchNode *branch = alloc_node<MatchBranchNode>(); + reset_extents(branch, current); bool has_bind = false; @@ -1919,6 +1966,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { } if (!consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "match" patterns.)")) { + complete_extents(branch); return nullptr; } @@ -1939,6 +1987,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { } branch->block = parse_suite("match pattern block", suite); + complete_extents(branch); // Restore continue state. can_continue = could_continue; @@ -1949,12 +1998,14 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_root_pattern) { PatternNode *pattern = alloc_node<PatternNode>(); + reset_extents(pattern, current); switch (current.type) { case GDScriptTokenizer::Token::VAR: { // Bind. advance(); if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected bind name after "var".)")) { + complete_extents(pattern); return nullptr; } pattern->pattern_type = PatternNode::PT_BIND; @@ -1965,12 +2016,14 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_ if (p_root_pattern != nullptr) { if (p_root_pattern->has_bind(pattern->bind->name)) { push_error(vformat(R"(Bind variable name "%s" was already used in this pattern.)", pattern->bind->name)); + complete_extents(pattern); return nullptr; } } if (current_suite->has_local(pattern->bind->name)) { push_error(vformat(R"(There's already a %s named "%s" in this scope.)", current_suite->get_local(pattern->bind->name).get_name(), pattern->bind->name)); + complete_extents(pattern); return nullptr; } @@ -2023,6 +2076,7 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_ push_error(R"(The ".." pattern must be the last element in the pattern dictionary.)"); } else { PatternNode *sub_pattern = alloc_node<PatternNode>(); + complete_extents(sub_pattern); sub_pattern->pattern_type = PatternNode::PT_REST; pattern->dictionary.push_back({ nullptr, sub_pattern }); pattern->rest_used = true; @@ -2071,6 +2125,7 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_ break; } } + complete_extents(pattern); return pattern; } @@ -2104,6 +2159,7 @@ GDScriptParser::WhileNode *GDScriptParser::parse_while() { is_continue_match = false; n_while->loop = parse_suite(R"("while" block)"); + complete_extents(n_while); // Reset break/continue state. can_break = could_break; @@ -2176,6 +2232,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode ERR_FAIL_V_MSG(nullptr, "Parser bug: parsing literal node without literal token."); } IdentifierNode *identifier = alloc_node<IdentifierNode>(); + complete_extents(identifier); identifier->name = previous.get_identifier(); if (current_suite != nullptr && current_suite->has_local(identifier->name)) { @@ -2227,6 +2284,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_literal(ExpressionNode *p_ } LiteralNode *literal = alloc_node<LiteralNode>(); + complete_extents(literal); literal->value = previous.literal; return literal; } @@ -2236,6 +2294,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_self(ExpressionNode *p_pre push_error(R"(Cannot use "self" inside a static function.)"); } SelfNode *self = alloc_node<SelfNode>(); + complete_extents(self); self->current_class = current_class; return self; } @@ -2243,6 +2302,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_self(ExpressionNode *p_pre GDScriptParser::ExpressionNode *GDScriptParser::parse_builtin_constant(ExpressionNode *p_previous_operand, bool p_can_assign) { GDScriptTokenizer::Token::Type op_type = previous.type; LiteralNode *constant = alloc_node<LiteralNode>(); + complete_extents(constant); switch (op_type) { case GDScriptTokenizer::Token::CONST_PI: @@ -2303,30 +2363,38 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_unary_operator(ExpressionN } break; default: + complete_extents(operation); return nullptr; // Unreachable. } + complete_extents(operation); return operation; } GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_not_in_operator(ExpressionNode *p_previous_operand, bool p_can_assign) { // check that NOT is followed by IN by consuming it before calling parse_binary_operator which will only receive a plain IN + UnaryOpNode *operation = alloc_node<UnaryOpNode>(); + reset_extents(operation, p_previous_operand); + update_extents(operation); consume(GDScriptTokenizer::Token::IN, R"(Expected "in" after "not" in content-test operator.)"); ExpressionNode *in_operation = parse_binary_operator(p_previous_operand, p_can_assign); - UnaryOpNode *operation = alloc_node<UnaryOpNode>(); operation->operation = UnaryOpNode::OP_LOGIC_NOT; operation->variant_op = Variant::OP_NOT; operation->operand = in_operation; + complete_extents(operation); return operation; } GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(ExpressionNode *p_previous_operand, bool p_can_assign) { GDScriptTokenizer::Token op = previous; BinaryOpNode *operation = alloc_node<BinaryOpNode>(); + reset_extents(operation, p_previous_operand); + update_extents(operation); Precedence precedence = (Precedence)(get_rule(op.type)->precedence + 1); operation->left_operand = p_previous_operand; operation->right_operand = parse_precedence(precedence, false); + complete_extents(operation); if (operation->right_operand == nullptr) { push_error(vformat(R"(Expected expression after "%s" operator.")", op.get_name())); @@ -2429,8 +2497,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(Expression GDScriptParser::ExpressionNode *GDScriptParser::parse_ternary_operator(ExpressionNode *p_previous_operand, bool p_can_assign) { // Only one ternary operation exists, so no abstraction here. TernaryOpNode *operation = alloc_node<TernaryOpNode>(); - operation->true_expr = p_previous_operand; + reset_extents(operation, p_previous_operand); + update_extents(operation); + operation->true_expr = p_previous_operand; operation->condition = parse_precedence(PREC_TERNARY, false); if (operation->condition == nullptr) { @@ -2445,6 +2515,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_ternary_operator(Expressio push_error(R"(Expected expression after "else".)"); } + complete_extents(operation); return operation; } @@ -2497,6 +2568,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode } AssignmentNode *assignment = alloc_node<AssignmentNode>(); + reset_extents(assignment, p_previous_operand); + update_extents(assignment); + make_completion_context(COMPLETION_ASSIGN, assignment); #ifdef DEBUG_ENABLED bool has_operator = true; @@ -2561,6 +2635,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode if (assignment->assigned_value == nullptr) { push_error(R"(Expected an expression after "=".)"); } + complete_extents(assignment); #ifdef DEBUG_ENABLED if (source_variable != nullptr) { @@ -2582,6 +2657,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_await(ExpressionNode *p_pr push_error(R"(Expected signal or coroutine after "await".)"); } await->to_await = element; + complete_extents(await); if (current_function) { // Might be null in a getter or setter. current_function->is_coroutine = true; @@ -2610,6 +2686,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_array(ExpressionNode *p_pr } pop_multiline(); consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected closing "]" after array elements.)"); + complete_extents(array); return array; } @@ -2701,6 +2778,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode } pop_multiline(); consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected closing "}" after dictionary elements.)"); + complete_extents(dictionary); return dictionary; } @@ -2718,6 +2796,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_grouping(ExpressionNode *p GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode *p_previous_operand, bool p_can_assign) { SubscriptNode *attribute = alloc_node<SubscriptNode>(); + reset_extents(attribute, p_previous_operand); + update_extents(attribute); if (for_completion) { bool is_builtin = false; @@ -2737,17 +2817,21 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode * attribute->base = p_previous_operand; if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier after "." for attribute access.)")) { + complete_extents(attribute); return attribute; } attribute->is_attribute = true; attribute->attribute = parse_identifier(); + complete_extents(attribute); return attribute; } GDScriptParser::ExpressionNode *GDScriptParser::parse_subscript(ExpressionNode *p_previous_operand, bool p_can_assign) { SubscriptNode *subscript = alloc_node<SubscriptNode>(); + reset_extents(subscript, p_previous_operand); + update_extents(subscript); make_completion_context(COMPLETION_SUBSCRIPT, subscript); @@ -2760,15 +2844,19 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_subscript(ExpressionNode * pop_multiline(); consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected "]" after subscription index.)"); + complete_extents(subscript); return subscript; } GDScriptParser::ExpressionNode *GDScriptParser::parse_cast(ExpressionNode *p_previous_operand, bool p_can_assign) { CastNode *cast = alloc_node<CastNode>(); + reset_extents(cast, p_previous_operand); + update_extents(cast); cast->operand = p_previous_operand; cast->cast_type = parse_type(); + complete_extents(cast); if (cast->cast_type == nullptr) { push_error(R"(Expected type specifier after "as".)"); @@ -2780,6 +2868,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_cast(ExpressionNode *p_pre GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_previous_operand, bool p_can_assign) { CallNode *call = alloc_node<CallNode>(); + reset_extents(call, p_previous_operand); if (previous.type == GDScriptTokenizer::Token::SUPER) { // Super call. @@ -2790,6 +2879,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre if (current_function == nullptr) { push_error(R"(Cannot use implicit "super" call outside of a function.)"); pop_multiline(); + complete_extents(call); return nullptr; } if (current_function->identifier) { @@ -2802,6 +2892,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre make_completion_context(COMPLETION_SUPER_METHOD, call, true); if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after ".".)")) { pop_multiline(); + complete_extents(call); return nullptr; } IdentifierNode *identifier = parse_identifier(); @@ -2858,6 +2949,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre pop_multiline(); consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after call arguments.)*"); + complete_extents(call); return call; } @@ -2901,6 +2993,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p if (previous.type == GDScriptTokenizer::Token::PERCENT) { if (path_state != PATH_STATE_START && path_state != PATH_STATE_SLASH) { push_error(R"("%" is only valid in the beginning of a node name (either after "$" or after "/"))"); + complete_extents(get_node); return nullptr; } get_node->full_path += "%"; @@ -2909,6 +3002,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p } else if (previous.type == GDScriptTokenizer::Token::SLASH) { if (path_state != PATH_STATE_START && path_state != PATH_STATE_NODE_NAME) { push_error(R"("/" is only valid at the beginning of the path or after a node name.)"); + complete_extents(get_node); return nullptr; } @@ -2936,6 +3030,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p break; } push_error(vformat(R"(Expected node path as string or identifier after "%s".)", previous_token)); + complete_extents(get_node); return nullptr; } @@ -2949,10 +3044,12 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p path_state = PATH_STATE_NODE_NAME; } else if (!check(GDScriptTokenizer::Token::SLASH) && !check(GDScriptTokenizer::Token::PERCENT)) { push_error(vformat(R"(Unexpected "%s" in node path.)", current.get_name())); + complete_extents(get_node); return nullptr; } } while (match(GDScriptTokenizer::Token::SLASH) || match(GDScriptTokenizer::Token::PERCENT)); + complete_extents(get_node); return get_node; } @@ -2976,6 +3073,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_preload(ExpressionNode *p_ pop_multiline(); consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after preload path.)*"); + complete_extents(preload); return preload; } @@ -3025,6 +3123,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_p in_lambda = true; function->body = parse_suite("lambda declaration", body, true); + complete_extents(function); + complete_extents(lambda); pop_multiline(); @@ -3069,13 +3169,15 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) { if (!match(GDScriptTokenizer::Token::IDENTIFIER)) { if (match(GDScriptTokenizer::Token::VOID)) { if (p_allow_void) { - TypeNode *void_type = alloc_node<TypeNode>(); + complete_extents(type); + TypeNode *void_type = type; return void_type; } else { push_error(R"("void" is only allowed for a function return type.)"); } } // Leave error message to the caller who knows the context. + complete_extents(type); return nullptr; } @@ -3088,11 +3190,15 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) { type->container_type = parse_type(false); // Don't allow void for array element type. if (type->container_type == nullptr) { push_error(R"(Expected type for collection after "[".)"); + complete_extents(type); type = nullptr; } else if (type->container_type->container_type != nullptr) { push_error("Nested typed collections are not supported."); } consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected closing "]" after collection type.)"); + if (type != nullptr) { + complete_extents(type); + } return type; } @@ -3105,6 +3211,7 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) { } } + complete_extents(type); return type; } @@ -3922,6 +4029,46 @@ GDScriptParser::DataType GDScriptParser::DataType::get_typed_container_type() co return type; } +void GDScriptParser::complete_extents(Node *p_node) { + while (!nodes_in_progress.is_empty() && nodes_in_progress.back()->get() != p_node) { + ERR_PRINT("Parser bug: Mismatch in extents tracking stack."); + nodes_in_progress.pop_back(); + } + if (nodes_in_progress.is_empty()) { + ERR_PRINT("Parser bug: Extents tracking stack is empty."); + } else { + nodes_in_progress.pop_back(); + } +} + +void GDScriptParser::update_extents(Node *p_node) { + p_node->end_line = previous.end_line; + p_node->end_column = previous.end_column; + p_node->leftmost_column = MIN(p_node->leftmost_column, previous.leftmost_column); + p_node->rightmost_column = MAX(p_node->rightmost_column, previous.rightmost_column); +} + +void GDScriptParser::reset_extents(Node *p_node, GDScriptTokenizer::Token p_token) { + p_node->start_line = p_token.start_line; + p_node->end_line = p_token.end_line; + p_node->start_column = p_token.start_column; + p_node->end_column = p_token.end_column; + p_node->leftmost_column = p_token.leftmost_column; + p_node->rightmost_column = p_token.rightmost_column; +} + +void GDScriptParser::reset_extents(Node *p_node, Node *p_from) { + if (p_from == nullptr) { + return; + } + p_node->start_line = p_from->start_line; + p_node->end_line = p_from->end_line; + p_node->start_column = p_from->start_column; + p_node->end_column = p_from->end_column; + p_node->leftmost_column = p_from->leftmost_column; + p_node->rightmost_column = p_from->rightmost_column; +} + /*---------- PRETTY PRINT FOR DEBUG ----------*/ #ifdef DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 8d3295f25b..9c97f98fbc 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1301,6 +1301,12 @@ private: }; static ParseRule *get_rule(GDScriptTokenizer::Token::Type p_token_type); + List<Node *> nodes_in_progress; + void complete_extents(Node *p_node); + void update_extents(Node *p_node); + void reset_extents(Node *p_node, GDScriptTokenizer::Token p_token); + void reset_extents(Node *p_node, Node *p_from); + template <class T> T *alloc_node() { T *node = memnew(T); @@ -1308,13 +1314,8 @@ private: node->next = list; list = node; - // TODO: Properly set positions for all nodes. - node->start_line = previous.start_line; - node->end_line = previous.end_line; - node->start_column = previous.start_column; - node->end_column = previous.end_column; - node->leftmost_column = previous.leftmost_column; - node->rightmost_column = previous.rightmost_column; + reset_extents(node, previous); + nodes_in_progress.push_back(node); return node; } @@ -1359,7 +1360,7 @@ private: SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr, bool p_for_lambda = false); // Annotations AnnotationNode *parse_annotation(uint32_t p_valid_targets); - bool register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, int p_optional_arguments = 0, bool p_is_vararg = false); + bool register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, const Vector<Variant> &p_default_arguments = Vector<Variant>(), bool p_is_vararg = false); bool validate_annotation_arguments(AnnotationNode *p_annotation); void clear_unused_annotations(); bool tool_annotation(const AnnotationNode *p_annotation, Node *p_target); diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index e8036098cb..babdc9f33b 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3202,12 +3202,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat state->images.push_back(Ref<Texture2D>()); continue; } - - Ref<ImageTexture> t; - t.instantiate(); - t->create_from_image(img); - - state->images.push_back(t); + state->images.push_back(ImageTexture::create_from_image(img)); } print_verbose("glTF: Total images: " + itos(state->images.size())); @@ -3428,7 +3423,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } } orm_image->generate_mipmaps(); - orm_texture->create_from_image(orm_image); + orm_texture->set_image(orm_image); GLTFTextureIndex orm_texture_index = -1; if (has_ao || has_roughness || has_metalness) { orm_texture->set_name(material->get_name() + "_orm"); @@ -3476,7 +3471,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { img->set_pixel(x, y, c); } } - tex->create_from_image(img); + tex->set_image(img); } } } @@ -3784,13 +3779,8 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re } rm_img->generate_mipmaps(); r_spec_gloss->diffuse_img->generate_mipmaps(); - Ref<ImageTexture> diffuse_image_texture; - diffuse_image_texture.instantiate(); - diffuse_image_texture->create_from_image(r_spec_gloss->diffuse_img); - p_material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_image_texture); - Ref<ImageTexture> rm_image_texture; - rm_image_texture.instantiate(); - rm_image_texture->create_from_image(rm_img); + p_material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, ImageTexture::create_from_image(r_spec_gloss->diffuse_img)); + Ref<ImageTexture> rm_image_texture = ImageTexture::create_from_image(rm_img); if (has_roughness) { p_material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, rm_image_texture); p_material->set_roughness_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_GREEN); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index fd7636566a..6076b87203 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -2381,9 +2381,7 @@ void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vec img->generate_mipmaps(); } - tex.texture = Ref<ImageTexture>(); - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); tex.dirty = false; } @@ -2688,8 +2686,7 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const img->generate_mipmaps(); } if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); } else { tex.texture->update(img); } @@ -2728,8 +2725,7 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con img->generate_mipmaps(); } if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); } else { tex.texture->update(img); } @@ -3060,8 +3056,7 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can img->generate_mipmaps(); } if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); } else { tex.texture->update(img); } @@ -3139,8 +3134,7 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI img->generate_mipmaps(); } if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); } else { tex.texture->update(img); } diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 8f57aa339c..7ccc9e3533 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -1493,9 +1493,7 @@ void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vec img->generate_mipmaps(); } - tex.texture = Ref<ImageTexture>(); - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); tex.dirty = false; } @@ -1786,8 +1784,7 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const img->generate_mipmaps(); } if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); } else { tex.texture->update(img); } @@ -1826,8 +1823,7 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con img->generate_mipmaps(); } if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); } else { tex.texture->update(img); } @@ -2140,8 +2136,7 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can img->generate_mipmaps(); } if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); } else { tex.texture->update(img); } @@ -2219,8 +2214,7 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI img->generate_mipmaps(); } if (tex.texture.is_null()) { - tex.texture.instantiate(); - tex.texture->create_from_image(img); + tex.texture = ImageTexture::create_from_image(img); } else { tex.texture->update(img); } diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 77e370849f..c4462ba687 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -331,7 +331,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { Ref<Image> img; img.instantiate(); img->create(w, h, false, Image::FORMAT_RGBA8); - texture->create_from_image(img); + texture->set_image(img); } else { /* tear down the partial theora setup */ diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index d72137e523..2cfb152804 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -3118,13 +3118,8 @@ void EditorExportPlatformAndroid::resolve_platform_feature_priorities(const Ref< } EditorExportPlatformAndroid::EditorExportPlatformAndroid() { - Ref<Image> img = memnew(Image(_android_logo)); - logo.instantiate(); - logo->create_from_image(img); - - img = Ref<Image>(memnew(Image(_android_run_icon))); - run_icon.instantiate(); - run_icon->create_from_image(img); + logo = ImageTexture::create_from_image(memnew(Image(_android_logo))); + run_icon = ImageTexture::create_from_image(memnew(Image(_android_run_icon))); devices_changed.set(); plugins_changed.set(); diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm index 573ee9b7a8..28ffc9595e 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/iphone/display_server_iphone.mm @@ -195,6 +195,7 @@ void DisplayServerIPhone::window_set_drop_files_callback(const Callable &p_calla } void DisplayServerIPhone::process_events() { + Input::get_singleton()->flush_buffered_events(); } void DisplayServerIPhone::_dispatch_input_events(const Ref<InputEvent> &p_event) { diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp index 4cf1c279eb..3b92bd19be 100644 --- a/platform/iphone/export/export_plugin.cpp +++ b/platform/iphone/export/export_plugin.cpp @@ -1838,12 +1838,8 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset } EditorExportPlatformIOS::EditorExportPlatformIOS() { - Ref<Image> img = memnew(Image(_iphone_logo)); - logo.instantiate(); - logo->create_from_image(img); - + logo = ImageTexture::create_from_image(memnew(Image(_iphone_logo))); plugins_changed.set(); - check_for_changes_thread.start(_check_for_changes_poll_thread, this); } diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp index 901580c140..e2ae45627e 100644 --- a/platform/javascript/export/export_plugin.cpp +++ b/platform/javascript/export/export_plugin.cpp @@ -661,13 +661,8 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { server.instantiate(); server_thread.start(_server_thread_poll, this); - Ref<Image> img = memnew(Image(_javascript_logo)); - logo.instantiate(); - logo->create_from_image(img); - - img = Ref<Image>(memnew(Image(_javascript_run_icon))); - run_icon.instantiate(); - run_icon->create_from_image(img); + logo = ImageTexture::create_from_image(memnew(Image(_javascript_logo))); + run_icon = ImageTexture::create_from_image(memnew(Image(_javascript_run_icon))); Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); if (theme.is_valid()) { diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index 965b969ba8..4240e9adc0 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -35,12 +35,7 @@ void register_linuxbsd_exporter() { Ref<EditorExportPlatformLinuxBSD> platform; platform.instantiate(); - - Ref<Image> img = memnew(Image(_linuxbsd_logo)); - Ref<ImageTexture> logo; - logo.instantiate(); - logo->create_from_image(img); - platform->set_logo(logo); + platform->set_logo(ImageTexture::create_from_image(memnew(Image(_linuxbsd_logo)))); platform->set_name("Linux/X11"); platform->set_extension("x86_32"); platform->set_extension("x86_64", "binary_format/64_bits"); diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 4307685422..91d64b50f0 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -1178,10 +1178,7 @@ Ref<Texture2D> DisplayServerOSX::global_menu_get_item_icon(const String &p_menu_ GodotMenuItem *obj = [menu_item representedObject]; if (obj) { if (obj->img.is_valid()) { - Ref<ImageTexture> txt; - txt.instantiate(); - txt->create_from_image(obj->img); - return txt; + return ImageTexture::create_from_image(obj->img); } } } diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp index 00a7e54131..a22d7e5e3d 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/osx/export/export_plugin.cpp @@ -252,7 +252,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ if (icon_infos[i].is_png) { // Encode PNG icon. - it->create_from_image(copy); + it->set_image(copy); String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png"); ResourceSaver::save(path, it); @@ -1666,9 +1666,7 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset } EditorExportPlatformOSX::EditorExportPlatformOSX() { - Ref<Image> img = memnew(Image(_osx_logo)); - logo.instantiate(); - logo->create_from_image(img); + logo = ImageTexture::create_from_image(memnew(Image(_osx_logo))); } EditorExportPlatformOSX::~EditorExportPlatformOSX() { diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp index 01683c656c..19b43d50be 100644 --- a/platform/uwp/export/export_plugin.cpp +++ b/platform/uwp/export/export_plugin.cpp @@ -503,7 +503,5 @@ void EditorExportPlatformUWP::resolve_platform_feature_priorities(const Ref<Edit } EditorExportPlatformUWP::EditorExportPlatformUWP() { - Ref<Image> img = memnew(Image(_uwp_logo)); - logo.instantiate(); - logo->create_from_image(img); + logo = ImageTexture::create_from_image(memnew(Image(_uwp_logo))); } diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index 0fa2913218..af19f24f09 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -48,12 +48,7 @@ void register_windows_exporter() { Ref<EditorExportPlatformWindows> platform; platform.instantiate(); - - Ref<Image> img = memnew(Image(_windows_logo)); - Ref<ImageTexture> logo; - logo.instantiate(); - logo->create_from_image(img); - platform->set_logo(logo); + platform->set_logo(ImageTexture::create_from_image(memnew(Image(_windows_logo)))); platform->set_name("Windows Desktop"); platform->set_os_name("Windows"); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 9c4b0feea2..cf8b6b8f94 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1158,6 +1158,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List rs->canvas_item_set_transform(canvas_item, xform); rs->canvas_item_set_light_mask(canvas_item, get_light_mask()); + rs->canvas_item_set_z_as_relative_to_parent(canvas_item, true); rs->canvas_item_set_z_index(canvas_item, z_index); rs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(get_texture_filter())); diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index d23a4fff43..d8de22d27c 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -342,7 +342,11 @@ void Button::_notification(int p_what) { } break; } - text_buf->draw_outline(ci, text_ofs, get_theme_constant(SNAME("outline_size")), get_theme_color(SNAME("font_outline_color"))); + Color font_outline_color = get_theme_color(SNAME("font_outline_color")); + int outline_size = get_theme_constant(SNAME("outline_size")); + if (outline_size > 0 && font_outline_color.a > 0) { + text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color); + } text_buf->draw(ci, text_ofs, color); } break; } diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp new file mode 100644 index 0000000000..af78d67e5a --- /dev/null +++ b/scene/gui/color_mode.cpp @@ -0,0 +1,330 @@ +/*************************************************************************/ +/* color_mode.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "color_mode.h" + +#include "core/math/color.h" +#include "scene/gui/slider.h" +#include "thirdparty/misc/ok_color.h" + +ColorMode::ColorMode(ColorPicker *p_color_picker) { + color_picker = p_color_picker; +} + +String ColorModeRGB::get_slider_label(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label."); + return labels[idx]; +} + +float ColorModeRGB::get_slider_max(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value."); + Color color = color_picker->get_pick_color(); + return next_power_of_2(MAX(255, color.components[idx] * 255.0)) - 1; +} + +float ColorModeRGB::get_slider_value(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider value."); + return color_picker->get_pick_color().components[idx] * 255; +} + +Color ColorModeRGB::get_color() const { + Vector<float> values = color_picker->get_active_slider_values(); + Color color; + for (int i = 0; i < 4; i++) { + color.components[i] = values[i] / 255.0; + } + return color; +} + +void ColorModeRGB::slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + HSlider *slider = color_picker->get_slider(p_which); + Size2 size = slider->get_size(); + Color left_color; + Color right_color; + Color color = color_picker->get_pick_color(); + const real_t margin = 4 * color_picker->get_theme_default_base_scale(); + + if (p_which == ColorPicker::SLIDER_COUNT) { + slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + } else { + left_color = Color( + p_which == 0 ? 0 : color.r, + p_which == 1 ? 0 : color.g, + p_which == 2 ? 0 : color.b); + right_color = Color( + p_which == 0 ? 1 : color.r, + p_which == 1 ? 1 : color.g, + p_which == 2 ? 1 : color.b); + } + + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + slider->draw_polygon(pos, col); +} + +String ColorModeHSV::get_slider_label(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label."); + return labels[idx]; +} + +float ColorModeHSV::get_slider_max(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value."); + return slider_max[idx]; +} + +float ColorModeHSV::get_slider_value(int idx) const { + switch (idx) { + case 0: + return color_picker->get_pick_color().get_h() * 360.0; + case 1: + return color_picker->get_pick_color().get_s() * 100.0; + case 2: + return color_picker->get_pick_color().get_v() * 100.0; + case 3: + return Math::round(color_picker->get_pick_color().components[3] * 255.0); + default: + ERR_FAIL_V_MSG(0, "Couldn't get slider value."); + } +} + +Color ColorModeHSV::get_color() const { + Vector<float> values = color_picker->get_active_slider_values(); + Color color; + color.set_hsv(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0, values[3] / 255.0); + return color; +} + +void ColorModeHSV::slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + HSlider *slider = color_picker->get_slider(p_which); + Size2 size = slider->get_size(); + Color left_color; + Color right_color; + Color color = color_picker->get_pick_color(); + const real_t margin = 4 * color_picker->get_theme_default_base_scale(); + + if (p_which == ColorPicker::SLIDER_COUNT) { + slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + } else if (p_which == 0) { + Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); + slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); + slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true); + return; + } else { + Color s_col; + Color v_col; + s_col.set_hsv(color.get_h(), 0, color.get_v()); + left_color = (p_which == 1) ? s_col : Color(0, 0, 0); + s_col.set_hsv(color.get_h(), 1, color.get_v()); + v_col.set_hsv(color.get_h(), color.get_s(), 1); + right_color = (p_which == 1) ? s_col : v_col; + } + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + slider->draw_polygon(pos, col); +} + +String ColorModeRAW::get_slider_label(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label."); + return labels[idx]; +} + +float ColorModeRAW::get_slider_max(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value."); + return slider_max[idx]; +} + +float ColorModeRAW::get_slider_value(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider value."); + return color_picker->get_pick_color().components[idx]; +} + +Color ColorModeRAW::get_color() const { + Vector<float> values = color_picker->get_active_slider_values(); + Color color; + for (int i = 0; i < 4; i++) { + color.components[i] = values[i]; + } + return color; +} + +void ColorModeRAW::slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + HSlider *slider = color_picker->get_slider(p_which); + Size2 size = slider->get_size(); + Color left_color; + Color right_color; + Color color = color_picker->get_pick_color(); + const real_t margin = 4 * color_picker->get_theme_default_base_scale(); + + if (p_which == ColorPicker::SLIDER_COUNT) { + slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + slider->draw_polygon(pos, col); + } +} + +bool ColorModeRAW::apply_theme() const { + for (int i = 0; i < 4; i++) { + HSlider *slider = color_picker->get_slider(i); + slider->remove_theme_icon_override("grabber"); + slider->remove_theme_icon_override("grabber_highlight"); + slider->remove_theme_style_override("slider"); + slider->remove_theme_style_override("grabber_area"); + slider->remove_theme_style_override("grabber_area_highlight"); + } + + return true; +} + +String ColorModeOKHSL::get_slider_label(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 3, String(), "Couldn't get slider label."); + return labels[idx]; +} + +float ColorModeOKHSL::get_slider_max(int idx) const { + ERR_FAIL_INDEX_V_MSG(idx, 4, 0, "Couldn't get slider max value."); + return slider_max[idx]; +} + +float ColorModeOKHSL::get_slider_value(int idx) const { + switch (idx) { + case 0: + return color_picker->get_pick_color().get_ok_hsl_h() * 360.0; + case 1: + return color_picker->get_pick_color().get_ok_hsl_s() * 100.0; + case 2: + return color_picker->get_pick_color().get_ok_hsl_l() * 100.0; + case 3: + return Math::round(color_picker->get_pick_color().components[3] * 255.0); + default: + ERR_FAIL_V_MSG(0, "Couldn't get slider value."); + } +} + +Color ColorModeOKHSL::get_color() const { + Vector<float> values = color_picker->get_active_slider_values(); + Color color; + color.set_ok_hsl(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0, values[3] / 255.0); + return color; +} + +void ColorModeOKHSL::slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + HSlider *slider = color_picker->get_slider(p_which); + Size2 size = slider->get_size(); + Color left_color; + Color right_color; + Color color = color_picker->get_pick_color(); + const real_t margin = 4 * color_picker->get_theme_default_base_scale(); + + if (p_which == ColorPicker::SLIDER_COUNT) { + slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + } else if (p_which == 0) { + Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); + slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); + slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true); + return; + } else { + Color s_col; + Color v_col; + s_col.set_ok_hsl(color.get_h(), 0, color.get_v()); + left_color = (p_which == 1) ? s_col : Color(0, 0, 0); + s_col.set_ok_hsl(color.get_h(), 1, color.get_v()); + v_col.set_ok_hsl(color.get_h(), color.get_s(), 1); + right_color = (p_which == 1) ? s_col : v_col; + } + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + slider->draw_polygon(pos, col); +} diff --git a/scene/gui/color_mode.h b/scene/gui/color_mode.h new file mode 100644 index 0000000000..8a19699c40 --- /dev/null +++ b/scene/gui/color_mode.h @@ -0,0 +1,143 @@ +/*************************************************************************/ +/* color_mode.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 COLOR_MODE_H +#define COLOR_MODE_H + +#include "scene/gui/color_picker.h" + +struct Color; + +class ColorMode { +public: + ColorPicker *color_picker = nullptr; + + virtual String get_name() const = 0; + + virtual int get_slider_count() const { return 3; }; + virtual float get_slider_step() const = 0; + virtual String get_slider_label(int idx) const = 0; + virtual float get_slider_max(int idx) const = 0; + virtual float get_slider_value(int idx) const = 0; + + virtual Color get_color() const = 0; + + virtual void slider_draw(int p_which) = 0; + virtual bool apply_theme() const { return false; } + virtual ColorPicker::PickerShapeType get_shape_override() const { return ColorPicker::SHAPE_MAX; } + + ColorMode(ColorPicker *p_color_picker); + virtual ~ColorMode(){}; +}; + +class ColorModeHSV : public ColorMode { +public: + String labels[3] = { "H", "S", "V" }; + float slider_max[4] = { 359, 100, 100, 255 }; + + virtual String get_name() const override { return "HSV"; } + + virtual float get_slider_step() const override { return 1.0; } + virtual String get_slider_label(int idx) const override; + virtual float get_slider_max(int idx) const override; + virtual float get_slider_value(int idx) const override; + + virtual Color get_color() const override; + + virtual void slider_draw(int p_which) override; + + ColorModeHSV(ColorPicker *p_color_picker) : + ColorMode(p_color_picker){}; +}; + +class ColorModeRGB : public ColorMode { +public: + String labels[3] = { "R", "G", "B" }; + + virtual String get_name() const override { return "RGB"; } + + virtual float get_slider_step() const override { return 1; } + virtual String get_slider_label(int idx) const override; + virtual float get_slider_max(int idx) const override; + virtual float get_slider_value(int idx) const override; + + virtual Color get_color() const override; + + virtual void slider_draw(int p_which) override; + + ColorModeRGB(ColorPicker *p_color_picker) : + ColorMode(p_color_picker){}; +}; + +class ColorModeRAW : public ColorMode { +public: + String labels[3] = { "R", "G", "B" }; + float slider_max[4] = { 100, 100, 100, 1 }; + + virtual String get_name() const override { return "RAW"; } + + virtual float get_slider_step() const override { return 0.01; } + virtual String get_slider_label(int idx) const override; + virtual float get_slider_max(int idx) const override; + virtual float get_slider_value(int idx) const override; + + virtual Color get_color() const override; + + virtual void slider_draw(int p_which) override; + virtual bool apply_theme() const override; + + ColorModeRAW(ColorPicker *p_color_picker) : + ColorMode(p_color_picker){}; +}; + +class ColorModeOKHSL : public ColorMode { +public: + String labels[3] = { "H", "S", "L" }; + float slider_max[4] = { 359, 100, 100, 255 }; + + virtual String get_name() const override { return "OKHSL"; } + + virtual float get_slider_step() const override { return 1.0; } + virtual String get_slider_label(int idx) const override; + virtual float get_slider_max(int idx) const override; + virtual float get_slider_value(int idx) const override; + + virtual Color get_color() const override; + + virtual void slider_draw(int p_which) override; + virtual ColorPicker::PickerShapeType get_shape_override() const override { return ColorPicker::SHAPE_OKHSL_CIRCLE; } + + ColorModeOKHSL(ColorPicker *p_color_picker) : + ColorMode(p_color_picker){}; + + ~ColorModeOKHSL(){}; +}; + +#endif // COLOR_MODE_H diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 28d645e8f6..492a81f933 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -34,7 +34,7 @@ #include "core/math/color.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "scene/main/window.h" +#include "scene/gui/color_mode.h" #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" @@ -75,10 +75,14 @@ void ColorPicker::_notification(int p_what) { wheel_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height")))); wheel_margin->add_theme_constant_override("margin_bottom", 8 * get_theme_default_base_scale()); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < SLIDER_COUNT; i++) { labels[i]->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0)); set_offset((Side)i, get_offset((Side)i) + get_theme_constant(SNAME("margin"))); } + alpha_label->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0)); + set_offset((Side)0, get_offset((Side)0) + get_theme_constant(SNAME("margin"))); + + _reset_theme(); if (Engine::get_singleton()->is_editor_hint()) { // Adjust for the width of the "Script" icon. @@ -194,75 +198,38 @@ void ColorPicker::set_focus_on_line_edit() { } void ColorPicker::_update_controls() { - const char *rgb[3] = { "R", "G", "B" }; - const char *hsv[3] = { "H", "S", "V" }; - const char *hsl[3] = { "H", "S", "L" }; - if (hsv_mode_enabled && picker_type == SHAPE_OKHSL_CIRCLE) { - for (int i = 0; i < 3; i++) { - labels[i]->set_text(hsl[i]); - } - } else if (hsv_mode_enabled && picker_type != SHAPE_OKHSL_CIRCLE) { - for (int i = 0; i < 3; i++) { - labels[i]->set_text(hsv[i]); - } - } else { - for (int i = 0; i < 3; i++) { - labels[i]->set_text(rgb[i]); - } + int mode_sliders_count = modes[current_mode]->get_slider_count(); + + for (int i = current_slider_count; i < mode_sliders_count; i++) { + sliders[i]->show(); + labels[i]->show(); + values[i]->show(); } - if (picker_type == SHAPE_OKHSL_CIRCLE) { - btn_hsv->set_text(RTR("OKHSL")); - } else { - btn_hsv->set_text(RTR("HSV")); - } - if (hsv_mode_enabled) { - set_raw_mode(false); - set_hsv_mode(true); - btn_raw->set_disabled(true); - } else if (raw_mode_enabled) { - set_raw_mode(true); - set_hsv_mode(false); - btn_raw->set_disabled(false); - btn_hsv->set_disabled(true); - } else { - set_raw_mode(false); - set_hsv_mode(false); - btn_raw->set_disabled(false); - btn_hsv->set_disabled(false); - } - - if (raw_mode_enabled) { - for (int i = 0; i < 3; i++) { - scroll[i]->remove_theme_icon_override("grabber"); - scroll[i]->remove_theme_icon_override("grabber_highlight"); - scroll[i]->remove_theme_style_override("slider"); - scroll[i]->remove_theme_style_override("grabber_area"); - scroll[i]->remove_theme_style_override("grabber_area_highlight"); - } - } else { - Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty)); - Ref<Texture2D> bar_arrow = get_theme_icon(SNAME("bar_arrow")); - - for (int i = 0; i < 4; i++) { - scroll[i]->add_theme_icon_override("grabber", bar_arrow); - scroll[i]->add_theme_icon_override("grabber_highlight", bar_arrow); - scroll[i]->add_theme_style_override("slider", style_box_empty); - scroll[i]->add_theme_style_override("grabber_area", style_box_empty); - scroll[i]->add_theme_style_override("grabber_area_highlight", style_box_empty); - } + for (int i = mode_sliders_count; i < current_slider_count; i++) { + sliders[i]->hide(); + labels[i]->hide(); + values[i]->hide(); } + current_slider_count = mode_sliders_count; + + for (int i = 0; i < current_slider_count; i++) { + labels[i]->set_text(modes[current_mode]->get_slider_label(i)); + } + alpha_label->set_text("A"); + + slider_theme_modified = modes[current_mode]->apply_theme(); if (edit_alpha) { - values[3]->show(); - scroll[3]->show(); - labels[3]->show(); + alpha_value->show(); + alpha_slider->show(); + alpha_label->show(); } else { - values[3]->hide(); - scroll[3]->hide(); - labels[3]->hide(); + alpha_value->hide(); + alpha_slider->hide(); + alpha_label->hide(); } - switch (picker_type) { + switch (_get_actual_shape()) { case SHAPE_HSV_RECTANGLE: wheel_edit->hide(); w_edit->show(); @@ -297,7 +264,7 @@ void ColorPicker::_update_controls() { void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) { color = p_color; if (color != last_color) { - if (picker_type == SHAPE_OKHSL_CIRCLE) { + if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) { h = color.get_ok_hsl_h(); s = color.get_ok_hsl_s(); v = color.get_ok_hsl_l(); @@ -353,27 +320,93 @@ void ColorPicker::_value_changed(double) { return; } - if (hsv_mode_enabled) { - h = scroll[0]->get_value() / 360.0; - s = scroll[1]->get_value() / 100.0; - v = scroll[2]->get_value() / 100.0; - if (picker_type == SHAPE_OKHSL_CIRCLE) { - color.set_ok_hsl(h, s, v, Math::round(scroll[3]->get_value() / 255.0)); - } else { - color.set_hsv(h, s, v, Math::round(scroll[3]->get_value() / 255.0)); - } + color = modes[current_mode]->get_color(); + if (current_mode == MODE_HSV || current_mode == MODE_OKHSL) { + h = sliders[0]->get_value() / 360.0; + s = sliders[1]->get_value() / 100.0; + v = sliders[2]->get_value() / 100.0; last_color = color; - } else { - for (int i = 0; i < 4; i++) { - color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0); - } } _set_pick_color(color, false); emit_signal(SNAME("color_changed"), color); } +void ColorPicker::add_mode(ColorMode *p_mode) { + modes.push_back(p_mode); + mode_option_button->add_item(RTR(p_mode->get_name())); +} + +void ColorPicker::create_slider(GridContainer *gc, int idx) { + Label *l = memnew(Label()); + l->set_v_size_flags(SIZE_SHRINK_CENTER); + gc->add_child(l); + + HSlider *s = memnew(HSlider); + s->set_v_size_flags(SIZE_SHRINK_CENTER); + s->set_focus_mode(FOCUS_NONE); + gc->add_child(s); + + SpinBox *v = memnew(SpinBox); + s->share(v); + gc->add_child(v); + v->get_line_edit()->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter)); + v->get_line_edit()->connect("focus_exited", callable_mp(this, &ColorPicker::_focus_exit)); + + s->set_h_size_flags(SIZE_EXPAND_FILL); + + s->connect("value_changed", callable_mp(this, &ColorPicker::_value_changed)); + s->connect("draw", callable_mp(this, &ColorPicker::_slider_draw), make_binds(idx)); + + if (idx < SLIDER_COUNT) { + sliders[idx] = s; + values[idx] = v; + labels[idx] = l; + } else { + alpha_slider = s; + alpha_value = v; + alpha_label = l; + } +} + +HSlider *ColorPicker::get_slider(int idx) { + if (idx < SLIDER_COUNT) { + return sliders[idx]; + } + return alpha_slider; +} + +Vector<float> ColorPicker::get_active_slider_values() { + Vector<float> values; + for (int i = 0; i < current_slider_count; i++) { + values.push_back(sliders[i]->get_value()); + } + values.push_back(alpha_slider->get_value()); + return values; +} + +ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const { + return modes[current_mode]->get_shape_override() != SHAPE_MAX ? modes[current_mode]->get_shape_override() : current_shape; +} + +void ColorPicker::_reset_theme() { + Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty)); + + for (int i = 0; i < SLIDER_COUNT; i++) { + sliders[i]->add_theme_icon_override("grabber", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); + sliders[i]->add_theme_icon_override("grabber_highlight", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); + sliders[i]->add_theme_style_override("slider", style_box_empty); + sliders[i]->add_theme_style_override("grabber_area", style_box_empty); + sliders[i]->add_theme_style_override("grabber_area_highlight", style_box_empty); + } + alpha_slider->add_theme_icon_override("grabber", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); + alpha_slider->add_theme_icon_override("grabber_highlight", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker"))); + alpha_slider->add_theme_style_override("slider", style_box_empty); + alpha_slider->add_theme_style_override("grabber_area", style_box_empty); + alpha_slider->add_theme_style_override("grabber_area_highlight", style_box_empty); +} + void ColorPicker::_html_submitted(const String &p_html) { if (updating || text_is_constructor || !c_text->is_visible()) { return; @@ -397,35 +430,15 @@ void ColorPicker::_update_color(bool p_update_sliders) { updating = true; if (p_update_sliders) { - if (hsv_mode_enabled) { - for (int i = 0; i < 4; i++) { - scroll[i]->set_step(1.0); - } - scroll[0]->set_max(359); - scroll[0]->set_value(h * 360.0); - scroll[1]->set_max(100); - scroll[1]->set_value(s * 100.0); - scroll[2]->set_max(100); - scroll[2]->set_value(v * 100.0); - scroll[3]->set_max(255); - scroll[3]->set_value(Math::round(color.components[3] * 255.0)); - } else { - for (int i = 0; i < 4; i++) { - if (raw_mode_enabled) { - scroll[i]->set_step(0.01); - scroll[i]->set_max(100); - if (i == 3) { - scroll[i]->set_max(1); - } - scroll[i]->set_value(color.components[i]); - } else { - scroll[i]->set_step(1); - const float byte_value = Math::round(color.components[i] * 255.0); - scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1); - scroll[i]->set_value(byte_value); - } - } + float step = modes[current_mode]->get_slider_step(); + for (int i = 0; i < current_slider_count; i++) { + sliders[i]->set_max(modes[current_mode]->get_slider_max(i)); + sliders[i]->set_step(step); + sliders[i]->set_value(modes[current_mode]->get_slider_value(i)); } + alpha_slider->set_max(modes[current_mode]->get_slider_max(current_slider_count)); + alpha_slider->set_step(step); + alpha_slider->set_value(modes[current_mode]->get_slider_value(current_slider_count)); } _update_text_value(); @@ -433,9 +446,10 @@ void ColorPicker::_update_color(bool p_update_sliders) { sample->update(); uv_edit->update(); w_edit->update(); - for (int i = 0; i < 4; i++) { - scroll[i]->update(); + for (int i = 0; i < current_slider_count; i++) { + sliders[i]->update(); } + alpha_slider->update(); wheel->update(); wheel_uv->update(); updating = false; @@ -481,15 +495,16 @@ Color ColorPicker::get_pick_color() const { return color; } -void ColorPicker::set_picker_shape(PickerShapeType p_picker_type) { - ERR_FAIL_INDEX(p_picker_type, SHAPE_MAX); - picker_type = p_picker_type; +void ColorPicker::set_picker_shape(PickerShapeType p_shape) { + ERR_FAIL_INDEX(p_shape, SHAPE_MAX); + current_shape = p_shape; + _update_controls(); _update_color(); } ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const { - return picker_type; + return current_shape; } inline int ColorPicker::_get_preset_size() { @@ -505,6 +520,21 @@ void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { preset_container->add_child(btn_preset); } +void ColorPicker::_set_color_mode(ColorModeType p_mode) { + if (slider_theme_modified) { + _reset_theme(); + } + + current_mode = p_mode; + + if (!is_inside_tree()) { + return; + } + + _update_controls(); + _update_color(); +} + void ColorPicker::add_preset(const Color &p_color) { if (presets.find(p_color)) { presets.move_to_back(presets.find(p_color)); @@ -564,46 +594,14 @@ PackedColorArray ColorPicker::get_presets() const { return arr; } -void ColorPicker::set_hsv_mode(bool p_enabled) { - if (hsv_mode_enabled == p_enabled || raw_mode_enabled) { - return; - } - hsv_mode_enabled = p_enabled; - if (btn_hsv->is_pressed() != p_enabled) { - btn_hsv->set_pressed(p_enabled); - } - - if (!is_inside_tree()) { - return; - } - - _update_controls(); - _update_color(); -} - -bool ColorPicker::is_hsv_mode() const { - return hsv_mode_enabled; -} - -void ColorPicker::set_raw_mode(bool p_enabled) { - if (raw_mode_enabled == p_enabled || hsv_mode_enabled) { - return; - } - raw_mode_enabled = p_enabled; - if (btn_raw->is_pressed() != p_enabled) { - btn_raw->set_pressed(p_enabled); - } - - if (!is_inside_tree()) { - return; - } - - _update_controls(); - _update_color(); +void ColorPicker::set_color_mode(ColorModeType p_mode) { + ERR_FAIL_INDEX(p_mode, MODE_MAX); + mode_option_button->select(p_mode); + _set_color_mode(p_mode); } -bool ColorPicker::is_raw_mode() const { - return raw_mode_enabled; +ColorPicker::ColorModeType ColorPicker::get_color_mode() const { + return current_mode; } void ColorPicker::set_deferred_mode(bool p_enabled) { @@ -690,6 +688,8 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { if (!c) { return; } + + PickerShapeType actual_shape = _get_actual_shape(); if (p_which == 0) { Vector<Point2> points; Vector<Color> colors; @@ -697,7 +697,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { Color col = color; Vector2 center = c->get_size() / 2.0; - switch (picker_type) { + switch (actual_shape) { case SHAPE_HSV_WHEEL: { points.resize(4); colors.resize(4); @@ -759,7 +759,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { Ref<Texture2D> cursor = get_theme_icon(SNAME("picker_cursor"), SNAME("ColorPicker")); int x; int y; - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { x = center.x + (center.x * Math::cos(h * Math_TAU) * s) - (cursor->get_width() / 2); y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (cursor->get_height() / 2); } else { @@ -773,7 +773,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { c->draw_texture(cursor, Point2(x, y)); col.set_hsv(h, 1, 1); - if (picker_type == SHAPE_HSV_WHEEL) { + if (actual_shape == SHAPE_HSV_WHEEL) { points.resize(4); double h1 = h - (0.5 / 360); double h2 = h + (0.5 / 360); @@ -785,14 +785,14 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } } else if (p_which == 1) { - if (picker_type == SHAPE_HSV_RECTANGLE) { + if (actual_shape == SHAPE_HSV_RECTANGLE) { Ref<Texture2D> hue = get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); c->draw_texture_rect(hue, Rect2(Point2(), c->get_size())); int y = c->get_size().y - c->get_size().y * (1.0 - h); Color col; col.set_hsv(h, 1, 1); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); - } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + } else if (actual_shape == SHAPE_OKHSL_CIRCLE) { Vector<Point2> points; Vector<Color> colors; Color col; @@ -811,7 +811,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1); col.set_ok_hsl(h, 1, v); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); - } else if (picker_type == SHAPE_VHS_CIRCLE) { + } else if (actual_shape == SHAPE_VHS_CIRCLE) { Vector<Point2> points; Vector<Color> colors; Color col; @@ -833,87 +833,24 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } } else if (p_which == 2) { c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1)); - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { circle_mat->set_shader_param("v", v); } } } void ColorPicker::_slider_draw(int p_which) { - Vector<Vector2> pos; - pos.resize(4); - Vector<Color> col; - col.resize(4); - Size2 size = scroll[p_which]->get_size(); - Color left_color; - Color right_color; - const real_t margin = 4 * get_theme_default_base_scale(); - - if (p_which == 3) { - scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); - - left_color = color; - left_color.a = 0; - right_color = color; - right_color.a = 1; - } else { - if (raw_mode_enabled) { - return; - } - if (hsv_mode_enabled) { - if (p_which == 0) { - Ref<Texture2D> hue = get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); - scroll[p_which]->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); - scroll[p_which]->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(scroll[p_which]->get_size().x, margin)), false, Color(1, 1, 1), true); - return; - } - Color s_col; - Color v_col; - if (picker_type == SHAPE_OKHSL_CIRCLE) { - s_col.set_ok_hsl(h, 0, v); - } else { - s_col.set_hsv(h, 0, v); - } - left_color = (p_which == 1) ? s_col : Color(0, 0, 0); - if (picker_type == SHAPE_OKHSL_CIRCLE) { - s_col.set_ok_hsl(h, 1, v); - v_col.set_ok_hsl(h, s, 1); - } else { - s_col.set_hsv(h, 1, v); - v_col.set_hsv(h, s, 1); - } - right_color = (p_which == 1) ? s_col : v_col; - } else { - left_color = Color( - p_which == 0 ? 0 : color.r, - p_which == 1 ? 0 : color.g, - p_which == 2 ? 0 : color.b); - right_color = Color( - p_which == 0 ? 1 : color.r, - p_which == 1 ? 1 : color.g, - p_which == 2 ? 1 : color.b); - } - } - - col.set(0, left_color); - col.set(1, right_color); - col.set(2, right_color); - col.set(3, left_color); - pos.set(0, Vector2(0, margin)); - pos.set(1, Vector2(size.x, margin)); - pos.set(2, Vector2(size.x, margin * 2)); - pos.set(3, Vector2(0, margin * 2)); - - scroll[p_which]->draw_polygon(pos, col); + modes[current_mode]->slider_draw(p_which); } void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { Ref<InputEventMouseButton> bev = p_event; + PickerShapeType current_picker = _get_actual_shape(); if (bev.is_valid()) { if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { Vector2 center = c->get_size() / 2.0; - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (current_picker == SHAPE_VHS_CIRCLE || current_picker == SHAPE_OKHSL_CIRCLE) { real_t dist = center.distance_to(bev->get_position()); if (dist <= center.x) { real_t rad = center.angle_to_point(bev->get_position()); @@ -951,11 +888,12 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { } } changing_color = true; - if (picker_type == SHAPE_OKHSL_CIRCLE) { + if (current_picker == SHAPE_OKHSL_CIRCLE) { color.set_ok_hsl(h, s, v, color.a); - } else if (picker_type != SHAPE_OKHSL_CIRCLE) { + } else { color.set_hsv(h, s, v, color.a); } + last_color = color; set_pick_color(color); @@ -981,7 +919,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { } Vector2 center = c->get_size() / 2.0; - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (current_picker == SHAPE_VHS_CIRCLE || current_picker == SHAPE_OKHSL_CIRCLE) { real_t dist = center.distance_to(mev->get_position()); real_t rad = center.angle_to_point(mev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; @@ -1002,9 +940,9 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { v = 1.0 - (y - corner_y) / real_size.y; } } - if (picker_type != SHAPE_OKHSL_CIRCLE) { + if (current_picker != SHAPE_OKHSL_CIRCLE) { color.set_hsv(h, s, v, color.a); - } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + } else { color.set_ok_hsl(h, s, v, color.a); } last_color = color; @@ -1018,12 +956,13 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> bev = p_event; + PickerShapeType actual_shape = _get_actual_shape(); if (bev.is_valid()) { if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { changing_color = true; float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height); - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { v = 1.0 - (y / w_edit->get_size().height); } else { h = y / w_edit->get_size().height; @@ -1031,9 +970,9 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { } else { changing_color = false; } - if (picker_type != SHAPE_OKHSL_CIRCLE) { + if (actual_shape != SHAPE_OKHSL_CIRCLE) { color.set_hsv(h, s, v, color.a); - } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + } else { color.set_ok_hsl(h, s, v, color.a); } last_color = color; @@ -1053,16 +992,18 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { return; } float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height); - if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { + if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { v = 1.0 - (y / w_edit->get_size().height); } else { h = y / w_edit->get_size().height; } - if (hsv_mode_enabled && picker_type != SHAPE_OKHSL_CIRCLE) { + + if (current_mode == MODE_HSV) { color.set_hsv(h, s, v, color.a); - } else if (hsv_mode_enabled && picker_type == SHAPE_OKHSL_CIRCLE) { + } else if (current_mode == MODE_OKHSL) { color.set_ok_hsl(h, s, v, color.a); } + last_color = color; set_pick_color(color); _update_color(); @@ -1153,21 +1094,30 @@ void ColorPicker::_focus_enter() { c_text->select(0, 0); } - for (int i = 0; i < 4; i++) { + for (int i = 0; i < current_slider_count; i++) { if (values[i]->get_line_edit()->has_focus() && !has_ctext_focus) { values[i]->get_line_edit()->select_all(); } else { values[i]->get_line_edit()->select(0, 0); } } + if (alpha_value->get_line_edit()->has_focus() && !has_ctext_focus) { + alpha_value->get_line_edit()->select_all(); + } else { + alpha_value->get_line_edit()->select(0, 0); + } } void ColorPicker::_focus_exit() { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < current_slider_count; i++) { if (!values[i]->get_line_edit()->get_menu()->is_visible()) { values[i]->get_line_edit()->select(0, 0); } } + if (!alpha_value->get_line_edit()->get_menu()->is_visible()) { + alpha_value->get_line_edit()->select(0, 0); + } + c_text->select(0, 0); } @@ -1207,12 +1157,10 @@ bool ColorPicker::are_presets_visible() const { void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color); ClassDB::bind_method(D_METHOD("get_pick_color"), &ColorPicker::get_pick_color); - ClassDB::bind_method(D_METHOD("set_hsv_mode", "enabled"), &ColorPicker::set_hsv_mode); - ClassDB::bind_method(D_METHOD("is_hsv_mode"), &ColorPicker::is_hsv_mode); - ClassDB::bind_method(D_METHOD("set_raw_mode", "enabled"), &ColorPicker::set_raw_mode); - ClassDB::bind_method(D_METHOD("is_raw_mode"), &ColorPicker::is_raw_mode); ClassDB::bind_method(D_METHOD("set_deferred_mode", "mode"), &ColorPicker::set_deferred_mode); ClassDB::bind_method(D_METHOD("is_deferred_mode"), &ColorPicker::is_deferred_mode); + ClassDB::bind_method(D_METHOD("set_color_mode", "color_mode"), &ColorPicker::set_color_mode); + ClassDB::bind_method(D_METHOD("get_color_mode"), &ColorPicker::get_color_mode); ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha); ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha); ClassDB::bind_method(D_METHOD("set_presets_enabled", "enabled"), &ColorPicker::set_presets_enabled); @@ -1222,13 +1170,12 @@ void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset); ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset); ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets); - ClassDB::bind_method(D_METHOD("set_picker_shape", "picker"), &ColorPicker::set_picker_shape); + ClassDB::bind_method(D_METHOD("set_picker_shape", "shape"), &ColorPicker::set_picker_shape); ClassDB::bind_method(D_METHOD("get_picker_shape"), &ColorPicker::get_picker_shape); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hsv_mode"), "set_hsv_mode", "is_hsv_mode"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "color_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW,OKHSL"), "set_color_mode", "get_color_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle"), "set_picker_shape", "get_picker_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled"); @@ -1238,6 +1185,11 @@ void ColorPicker::_bind_methods() { ADD_SIGNAL(MethodInfo("preset_added", PropertyInfo(Variant::COLOR, "color"))); ADD_SIGNAL(MethodInfo("preset_removed", PropertyInfo(Variant::COLOR, "color"))); + BIND_ENUM_CONSTANT(MODE_RGB); + BIND_ENUM_CONSTANT(MODE_HSV); + BIND_ENUM_CONSTANT(MODE_RAW); + BIND_ENUM_CONSTANT(MODE_OKHSL); + BIND_ENUM_CONSTANT(SHAPE_HSV_RECTANGLE); BIND_ENUM_CONSTANT(SHAPE_HSV_WHEEL); BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE); @@ -1250,6 +1202,7 @@ ColorPicker::ColorPicker() : add_child(hb_edit, false, INTERNAL_MODE_FRONT); hb_edit->set_v_size_flags(SIZE_EXPAND_FILL); + uv_edit = memnew(Control); hb_edit->add_child(uv_edit); uv_edit->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input), make_binds(uv_edit)); uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); @@ -1260,11 +1213,13 @@ ColorPicker::ColorPicker() : HBoxContainer *hb_smpl = memnew(HBoxContainer); add_child(hb_smpl, false, INTERNAL_MODE_FRONT); + sample = memnew(TextureRect); hb_smpl->add_child(sample); sample->set_h_size_flags(SIZE_EXPAND_FILL); sample->connect("gui_input", callable_mp(this, &ColorPicker::_sample_input)); sample->connect("draw", callable_mp(this, &ColorPicker::_sample_draw)); + btn_pick = memnew(Button); btn_pick->set_flat(true); hb_smpl->add_child(btn_pick); btn_pick->set_toggle_mode(true); @@ -1277,51 +1232,35 @@ ColorPicker::ColorPicker() : add_child(memnew(HSeparator), false, INTERNAL_MODE_FRONT); VBoxContainer *vbr = memnew(VBoxContainer); + add_child(vbr, false, INTERNAL_MODE_FRONT); vbr->set_h_size_flags(SIZE_EXPAND_FILL); - for (int i = 0; i < 4; i++) { - HBoxContainer *hbc = memnew(HBoxContainer); + GridContainer *gc = memnew(GridContainer); - labels[i] = memnew(Label()); - labels[i]->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0)); - labels[i]->set_v_size_flags(SIZE_SHRINK_CENTER); - hbc->add_child(labels[i]); + vbr->add_child(gc); + gc->set_h_size_flags(SIZE_EXPAND_FILL); + gc->set_columns(3); - scroll[i] = memnew(HSlider); - scroll[i]->set_v_size_flags(SIZE_SHRINK_CENTER); - scroll[i]->set_focus_mode(FOCUS_NONE); - hbc->add_child(scroll[i]); - - values[i] = memnew(SpinBox); - scroll[i]->share(values[i]); - hbc->add_child(values[i]); - values[i]->get_line_edit()->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter)); - values[i]->get_line_edit()->connect("focus_exited", callable_mp(this, &ColorPicker::_focus_exit)); - - scroll[i]->set_min(0); - scroll[i]->set_page(0); - scroll[i]->set_h_size_flags(SIZE_EXPAND_FILL); - - scroll[i]->connect("value_changed", callable_mp(this, &ColorPicker::_value_changed)); - scroll[i]->connect("draw", callable_mp(this, &ColorPicker::_slider_draw), make_binds(i)); - - vbr->add_child(hbc); + for (int i = 0; i < SLIDER_COUNT + 1; i++) { + create_slider(gc, i); } - labels[3]->set_text("A"); + alpha_label->set_text("A"); HBoxContainer *hhb = memnew(HBoxContainer); vbr->add_child(hhb); - hhb->add_child(btn_hsv); - btn_hsv->set_text(RTR("HSV")); - btn_hsv->connect("toggled", callable_mp(this, &ColorPicker::set_hsv_mode)); + mode_option_button = memnew(OptionButton); - hhb->add_child(btn_raw); - btn_raw->set_text(RTR("Raw")); - btn_raw->connect("toggled", callable_mp(this, &ColorPicker::set_raw_mode)); + hhb->add_child(mode_option_button); + add_mode(new ColorModeRGB(this)); + add_mode(new ColorModeHSV(this)); + add_mode(new ColorModeRAW(this)); + add_mode(new ColorModeOKHSL(this)); + mode_option_button->connect("item_selected", callable_mp(this, &ColorPicker::_set_color_mode)); + text_type = memnew(Button); hhb->add_child(text_type); text_type->set_text("#"); text_type->set_tooltip(RTR("Switch between hexadecimal and code values.")); @@ -1332,12 +1271,14 @@ ColorPicker::ColorPicker() : text_type->set_mouse_filter(MOUSE_FILTER_IGNORE); } + c_text = memnew(LineEdit); hhb->add_child(c_text); c_text->set_h_size_flags(SIZE_EXPAND_FILL); c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted)); c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter)); c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit)); + wheel_edit = memnew(AspectRatioContainer); wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL); wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL); hb_edit->add_child(wheel_edit); @@ -1347,41 +1288,53 @@ ColorPicker::ColorPicker() : circle_mat.instantiate(); circle_mat->set_shader(circle_shader); + wheel_margin = memnew(MarginContainer); wheel_margin->add_theme_constant_override("margin_bottom", 8); wheel_edit->add_child(wheel_margin); + wheel = memnew(Control); wheel_margin->add_child(wheel); wheel->set_mouse_filter(MOUSE_FILTER_PASS); wheel->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(2, wheel)); + wheel_uv = memnew(Control); wheel_margin->add_child(wheel_uv); wheel_uv->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input), make_binds(wheel_uv)); wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, wheel_uv)); + w_edit = memnew(Control); hb_edit->add_child(w_edit); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input)); w_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(1, w_edit)); - picker_type = SHAPE_HSV_RECTANGLE; _update_controls(); updating = false; set_pick_color(Color(1, 1, 1)); + preset_separator = memnew(HSeparator); add_child(preset_separator, false, INTERNAL_MODE_FRONT); + preset_container = memnew(GridContainer); preset_container->set_h_size_flags(SIZE_EXPAND_FILL); preset_container->set_columns(preset_column_count); add_child(preset_container, false, INTERNAL_MODE_FRONT); + btn_add_preset = memnew(Button); btn_add_preset->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER); btn_add_preset->set_tooltip(RTR("Add current color as a preset.")); btn_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed)); preset_container->add_child(btn_add_preset); } +ColorPicker::~ColorPicker() { + for (int i = 0; i < modes.size(); i++) { + delete modes[i]; + } +} + ///////////////// void ColorPickerButton::_about_to_popup() { diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 953be032ec..e219c78319 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -34,16 +34,23 @@ #include "scene/gui/aspect_ratio_container.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" -#include "scene/gui/check_button.h" +#include "scene/gui/control.h" #include "scene/gui/grid_container.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" +#include "scene/gui/option_button.h" #include "scene/gui/popup.h" #include "scene/gui/separator.h" #include "scene/gui/slider.h" #include "scene/gui/spin_box.h" #include "scene/gui/texture_rect.h" +class ColorMode; +class ColorModeRGB; +class ColorModeHSV; +class ColorModeRAW; +class ColorModeOKHSL; + class ColorPresetButton : public BaseButton { GDCLASS(ColorPresetButton, BaseButton); @@ -64,6 +71,15 @@ class ColorPicker : public BoxContainer { GDCLASS(ColorPicker, BoxContainer); public: + enum ColorModeType { + MODE_RGB, + MODE_HSV, + MODE_RAW, + MODE_OKHSL, + + MODE_MAX + }; + enum PickerShapeType { SHAPE_HSV_RECTANGLE, SHAPE_HSV_WHEEL, @@ -73,38 +89,52 @@ public: SHAPE_MAX }; + static const int SLIDER_COUNT = 4; + private: static Ref<Shader> wheel_shader; static Ref<Shader> circle_shader; static Ref<Shader> circle_ok_color_shader; static List<Color> preset_cache; + int current_slider_count = SLIDER_COUNT; + + bool slider_theme_modified = true; + + Vector<ColorMode *> modes; + Control *screen = nullptr; - Control *uv_edit = memnew(Control); - Control *w_edit = memnew(Control); - AspectRatioContainer *wheel_edit = memnew(AspectRatioContainer); - MarginContainer *wheel_margin = memnew(MarginContainer); + Control *uv_edit = nullptr; + Control *w_edit = nullptr; + AspectRatioContainer *wheel_edit = nullptr; + MarginContainer *wheel_margin = nullptr; Ref<ShaderMaterial> wheel_mat; Ref<ShaderMaterial> circle_mat; - Control *wheel = memnew(Control); - Control *wheel_uv = memnew(Control); - TextureRect *sample = memnew(TextureRect); - GridContainer *preset_container = memnew(GridContainer); - HSeparator *preset_separator = memnew(HSeparator); - Button *btn_add_preset = memnew(Button); - Button *btn_pick = memnew(Button); - CheckButton *btn_hsv = memnew(CheckButton); - CheckButton *btn_raw = memnew(CheckButton); - HSlider *scroll[4]; - SpinBox *values[4]; - Label *labels[4]; - Button *text_type = memnew(Button); - LineEdit *c_text = memnew(LineEdit); + Control *wheel = nullptr; + Control *wheel_uv = nullptr; + TextureRect *sample = nullptr; + GridContainer *preset_container = nullptr; + HSeparator *preset_separator = nullptr; + Button *btn_add_preset = nullptr; + Button *btn_pick = nullptr; + + OptionButton *mode_option_button = nullptr; + + HSlider *sliders[SLIDER_COUNT]; + SpinBox *values[SLIDER_COUNT]; + Label *labels[SLIDER_COUNT]; + Button *text_type = nullptr; + LineEdit *c_text = nullptr; + + HSlider *alpha_slider = nullptr; + SpinBox *alpha_value = nullptr; + Label *alpha_label = nullptr; bool edit_alpha = true; Size2i ms; bool text_is_constructor = false; - PickerShapeType picker_type = SHAPE_HSV_WHEEL; + PickerShapeType current_shape = SHAPE_HSV_RECTANGLE; + ColorModeType current_mode = MODE_RGB; const int preset_column_count = 9; int prev_preset_size = 0; @@ -114,8 +144,6 @@ private: Color old_color; bool display_old_color = false; - bool raw_mode_enabled = false; - bool hsv_mode_enabled = false; bool deferred_mode_enabled = false; bool updating = true; bool changing_color = false; @@ -128,6 +156,9 @@ private: float v = 0.0; Color last_color; + PickerShapeType _get_actual_shape() const; + void create_slider(GridContainer *gc, int idx); + void _reset_theme(); void _html_submitted(const String &p_html); void _value_changed(double); void _update_controls(); @@ -152,14 +183,21 @@ private: inline int _get_preset_size(); void _add_preset_button(int p_size, const Color &p_color); + void _set_color_mode(ColorModeType p_mode); + protected: void _notification(int); static void _bind_methods(); public: + HSlider *get_slider(int idx); + Vector<float> get_active_slider_values(); + static void init_shaders(); static void finish_shaders(); + void add_mode(ColorMode *p_mode); + void set_edit_alpha(bool p_show); bool is_editing_alpha() const; @@ -173,7 +211,7 @@ public: void set_display_old_color(bool p_enabled); bool is_displaying_old_color() const; - void set_picker_shape(PickerShapeType p_picker_type); + void set_picker_shape(PickerShapeType p_shape); PickerShapeType get_picker_shape() const; void add_preset(const Color &p_color); @@ -181,11 +219,8 @@ public: PackedColorArray get_presets() const; void _update_presets(); - void set_hsv_mode(bool p_enabled); - bool is_hsv_mode() const; - - void set_raw_mode(bool p_enabled); - bool is_raw_mode() const; + void set_color_mode(ColorModeType p_mode); + ColorModeType get_color_mode() const; void set_deferred_mode(bool p_enabled); bool is_deferred_mode() const; @@ -199,6 +234,7 @@ public: void set_focus_on_line_edit(); ColorPicker(); + ~ColorPicker(); }; class ColorPickerButton : public Button { @@ -239,4 +275,5 @@ public: }; VARIANT_ENUM_CAST(ColorPicker::PickerShapeType); +VARIANT_ENUM_CAST(ColorPicker::ColorModeType); #endif // COLOR_PICKER_H diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 3766bf9e59..8ec930b753 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -673,9 +673,13 @@ void FileDialog::clear_filters() { invalidate(); } -void FileDialog::add_filter(const String &p_filter) { +void FileDialog::add_filter(const String &p_filter, const String &p_description) { ERR_FAIL_COND_MSG(p_filter.begins_with("."), "Filter must be \"filename.extension\", can't start with dot."); - filters.push_back(p_filter); + if (p_description.is_empty()) { + filters.push_back(p_filter); + } else { + filters.push_back(vformat("%s ; %s", p_filter, p_description)); + } update_filters(); invalidate(); } @@ -919,7 +923,7 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_cancel_pressed"), &FileDialog::_cancel_pressed); ClassDB::bind_method(D_METHOD("clear_filters"), &FileDialog::clear_filters); - ClassDB::bind_method(D_METHOD("add_filter", "filter"), &FileDialog::add_filter); + ClassDB::bind_method(D_METHOD("add_filter", "filter", "description"), &FileDialog::add_filter, DEFVAL("")); ClassDB::bind_method(D_METHOD("set_filters", "filters"), &FileDialog::set_filters); ClassDB::bind_method(D_METHOD("get_filters"), &FileDialog::get_filters); ClassDB::bind_method(D_METHOD("get_current_dir"), &FileDialog::get_current_dir); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 8b8d93920c..017c9d8d4f 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -151,7 +151,7 @@ protected: public: void popup_file_dialog(); void clear_filters(); - void add_filter(const String &p_filter); + void add_filter(const String &p_filter, const String &p_description = ""); void set_filters(const Vector<String> &p_filters); Vector<String> get_filters() const; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 9c6cd6bdb2..06553cd0f6 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1217,7 +1217,7 @@ void TextEdit::_notification(int p_what) { if (brace_open_mismatch) { current_color = brace_mismatch_color; } - Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, font->get_underline_thickness(font_size)); + Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, MAX(font->get_underline_thickness(font_size) * get_theme_default_base_scale(), 1)); draw_rect(rect, current_color); } @@ -1226,7 +1226,7 @@ void TextEdit::_notification(int p_what) { if (brace_close_mismatch) { current_color = brace_mismatch_color; } - Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, font->get_underline_thickness(font_size)); + Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, MAX(font->get_underline_thickness(font_size) * get_theme_default_base_scale(), 1)); draw_rect(rect, current_color); } } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 32d348c121..4bb8208679 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2967,6 +2967,15 @@ void Tree::_go_down() { accept_event(); } +bool Tree::_scroll(bool p_horizontal, float p_pages) { + ScrollBar *scroll = p_horizontal ? (ScrollBar *)h_scroll : (ScrollBar *)v_scroll; + + double prev_value = scroll->get_value(); + scroll->set_value(scroll->get_value() + scroll->get_page() * p_pages); + + return scroll->get_value() != prev_value; +} + void Tree::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); @@ -3481,17 +3490,25 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } break; case MouseButton::WHEEL_UP: { - double prev_value = v_scroll->get_value(); - v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * mb->get_factor() / 8); - if (v_scroll->get_value() != prev_value) { + if (_scroll(false, -mb->get_factor() / 8)) { accept_event(); } } break; case MouseButton::WHEEL_DOWN: { - double prev_value = v_scroll->get_value(); - v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * mb->get_factor() / 8); - if (v_scroll->get_value() != prev_value) { + if (_scroll(false, mb->get_factor() / 8)) { + accept_event(); + } + + } break; + case MouseButton::WHEEL_LEFT: { + if (_scroll(true, -mb->get_factor() / 8)) { + accept_event(); + } + + } break; + case MouseButton::WHEEL_RIGHT: { + if (_scroll(true, mb->get_factor() / 8)) { accept_event(); } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 65f7ab185c..1690e7ac57 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -610,6 +610,8 @@ private: void _go_down(); void _go_up(); + bool _scroll(bool p_horizontal, float p_pages); + protected: static void _bind_methods(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 9d13ac3a38..520a0a04ed 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -76,7 +76,6 @@ static Ref<StyleBoxFlat> sb_expand(Ref<StyleBoxFlat> p_sbox, float p_left, float // See also `editor_generate_icon()` in `editor/editor_themes.cpp`. static Ref<ImageTexture> generate_icon(int p_index) { - Ref<ImageTexture> icon = memnew(ImageTexture); Ref<Image> img = memnew(Image); #ifdef MODULE_SVG_ENABLED @@ -87,9 +86,8 @@ static Ref<ImageTexture> generate_icon(int p_index) { ImageLoaderSVG img_loader; img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, false); #endif - icon->create_from_image(img); - return icon; + return ImageTexture::create_from_image(img); } static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index e58ef68388..8c175e9ced 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -139,7 +139,7 @@ void ImageTexture::reload_from_file() { img.instantiate(); if (ImageLoader::load_image(path, img) == OK) { - create_from_image(img); + set_image(img); } else { Resource::reload_from_file(); notify_property_list_changed(); @@ -149,7 +149,7 @@ void ImageTexture::reload_from_file() { bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) { if (p_name == "image") { - create_from_image(p_value); + set_image(p_value); return true; } return false; @@ -167,7 +167,16 @@ void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("image"), PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT)); } -void ImageTexture::create_from_image(const Ref<Image> &p_image) { +Ref<ImageTexture> ImageTexture::create_from_image(const Ref<Image> &p_image) { + ERR_FAIL_COND_V_MSG(p_image.is_null() || p_image->is_empty(), Ref<ImageTexture>(), "Invalid image"); + + Ref<ImageTexture> image_texture; + image_texture.instantiate(); + image_texture->set_image(p_image); + return image_texture; +} + +void ImageTexture::set_image(const Ref<Image> &p_image) { ERR_FAIL_COND_MSG(p_image.is_null() || p_image->is_empty(), "Invalid image"); w = p_image->get_width(); h = p_image->get_height(); @@ -311,7 +320,7 @@ void ImageTexture::set_path(const String &p_path, bool p_take_over) { } void ImageTexture::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image); + ClassDB::bind_static_method("ImageTexture", D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image); ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format); ClassDB::bind_method(D_METHOD("update", "image"), &ImageTexture::update); diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 317756e313..5973643034 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -110,7 +110,8 @@ protected: static void _bind_methods(); public: - void create_from_image(const Ref<Image> &p_image); + void set_image(const Ref<Image> &p_image); + static Ref<ImageTexture> create_from_image(const Ref<Image> &p_image); Image::Format get_format() const; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 13b671e562..05483db1e4 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -1809,11 +1809,8 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) { image->create(1, 1, false, Image::FORMAT_RGBA8); image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain)); } - Ref<ImageTexture> icon; - icon.instantiate(); - icon->create_from_image(image); + Ref<ImageTexture> icon = ImageTexture::create_from_image(image); icon->set_size_override(p_size); - output.write[terrain_set].write[terrain] = icon; } } @@ -4594,7 +4591,7 @@ void TileSetAtlasSource::_update_padded_texture() { if (!padded_texture.is_valid()) { padded_texture.instantiate(); } - padded_texture->create_from_image(image); + padded_texture->set_image(image); emit_changed(); } @@ -4924,6 +4921,10 @@ void TileData::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) { void TileData::remove_terrain(int p_terrain_set, int p_index) { if (terrain_set == p_terrain_set) { + if (terrain == p_index) { + terrain = -1; + } + for (int i = 0; i < 16; i++) { if (terrain_peering_bits[i] == p_index) { terrain_peering_bits[i] = -1; diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index 54df935168..bdfbb59fa6 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -470,7 +470,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2> image->set_pixel(i, 0, Color(v.x, v.y, 0)); } if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { - r_texture->create_from_image(image); + r_texture->set_image(image); } else { r_texture->update(image); } @@ -491,7 +491,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3> image->set_pixel(i, 0, Color(v.x, v.y, v.z)); } if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { - r_texture->create_from_image(image); + r_texture->set_image(image); } else { r_texture->update(image); } @@ -511,7 +511,7 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p image->set_pixel(i, 0, p_array[i]); } if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { - r_texture->create_from_image(image); + r_texture->set_image(image); } else { r_texture->update(image); } diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index bc1e8eb348..dea68ac61c 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -76,10 +76,11 @@ void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas } } -void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2D p_transform, RendererCanvasCull::Item *p_material_owner, RendererCanvasCull::Item **r_items, int &r_index) { +void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2D p_transform, RendererCanvasCull::Item *p_material_owner, RendererCanvasCull::Item **r_items, int &r_index, int p_z) { int child_item_count = p_canvas_item->child_items.size(); RendererCanvasCull::Item **child_items = p_canvas_item->child_items.ptrw(); for (int i = 0; i < child_item_count; i++) { + int abs_z = 0; if (child_items[i]->visible) { if (r_items) { r_items[r_index] = child_items[i]; @@ -87,12 +88,20 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2 child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.columns[2]); child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr; child_items[i]->ysort_index = r_index; + child_items[i]->ysort_parent_abs_z_index = p_z; + + // Y sorted canvas items are flattened into r_items. Calculate their absolute z index to use when rendering r_items. + if (child_items[i]->z_relative) { + abs_z = CLAMP(p_z + child_items[i]->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX); + } else { + abs_z = child_items[i]->z_index; + } } r_index++; if (child_items[i]->sort_y) { - _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], r_items, r_index); + _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], r_items, r_index, abs_z); } } } @@ -277,6 +286,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 ci->final_clip_owner = p_canvas_clip; } + int parent_z = p_z; if (ci->z_relative) { p_z = CLAMP(p_z + ci->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX); } else { @@ -287,22 +297,23 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 if (allow_y_sort) { if (ci->ysort_children_count == -1) { ci->ysort_children_count = 0; - _collect_ysort_children(ci, Transform2D(), p_material_owner, nullptr, ci->ysort_children_count); + _collect_ysort_children(ci, Transform2D(), p_material_owner, nullptr, ci->ysort_children_count, p_z); } child_item_count = ci->ysort_children_count + 1; child_items = (Item **)alloca(child_item_count * sizeof(Item *)); + ci->ysort_parent_abs_z_index = parent_z; child_items[0] = ci; int i = 1; - _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i); + _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i, p_z); ci->ysort_xform = ci->xform.affine_inverse(); SortArray<Item *, ItemPtrSort> sorter; sorter.sort(child_items, child_item_count); for (i = 0; i < child_item_count; i++) { - _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false); + _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, child_items[i]->ysort_parent_abs_z_index, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 963cca7630..48d0598c9f 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -53,6 +53,7 @@ public: Transform2D ysort_xform; Vector2 ysort_pos; int ysort_index; + int ysort_parent_abs_z_index; // Absolute Z index of parent. Only populated and used when y-sorting. Vector<Item *> child_items; @@ -84,6 +85,7 @@ public: ysort_xform = Transform2D(); ysort_pos = Vector2(); ysort_index = 0; + ysort_parent_abs_z_index = 0; } }; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index b1e0017e5b..f759fa3aa5 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -346,7 +346,7 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); - tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -436,7 +436,7 @@ void RenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferData tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { - tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; } else { tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; } @@ -449,7 +449,7 @@ void RenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferData fb.push_back(rb->normal_roughness_buffer); rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, rb->view_count); } else { - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; tf.samples = rb->texture_samples; rb->normal_roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index bf4f3546c1..5185d537ec 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -3098,7 +3098,7 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; } if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) { - tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, (RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT)) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; } else { tf.format = RD::DATA_FORMAT_R32_SFLOAT; } diff --git a/servers/rendering/renderer_rd/shaders/taa_resolve.glsl b/servers/rendering/renderer_rd/shaders/taa_resolve.glsl index a1a77b95aa..ddd984ad83 100644 --- a/servers/rendering/renderer_rd/shaders/taa_resolve.glsl +++ b/servers/rendering/renderer_rd/shaders/taa_resolve.glsl @@ -29,7 +29,8 @@ #VERSION_DEFINES -// Based on Spartan Engine's TAA implementation https://github.com/PanosK92/SpartanEngine/blob/master/Data/shaders/temporal_antialiasing.hlsl +// Based on Spartan Engine's TAA implementation (without TAA upscale). +// <https://github.com/PanosK92/SpartanEngine/blob/a8338d0609b85dc32f3732a5c27fb4463816a3b9/Data/shaders/temporal_antialiasing.hlsl> #define USE_SUBGROUPS |