diff options
153 files changed, 8713 insertions, 907 deletions
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 456d29520f..b0f2ca754d 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* multiplayer_api.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "core/io/multiplayer_api.h" #include "core/io/marshalls.h" #include "scene/main/node.h" diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index 25f445004d..64f59d32d8 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* multiplayer_api.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 MULTIPLAYER_PROTOCOL_H #define MULTIPLAYER_PROTOCOL_H diff --git a/core/object.h b/core/object.h index c405e22557..7963a43fd6 100644 --- a/core/object.h +++ b/core/object.h @@ -55,7 +55,7 @@ enum PropertyHint { PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional" PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" - PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) + PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout") PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) PROPERTY_HINT_SPRITE_FRAME, PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml index 99a3f59487..20d8bebd6b 100644 --- a/doc/classes/AcceptDialog.xml +++ b/doc/classes/AcceptDialog.xml @@ -21,7 +21,7 @@ <argument index="2" name="action" type="String" default=""""> </argument> <description> - Adds a button with label [i]text[/i] and a custom [i]action[/i] to the dialog and returns the created button. [i]action[/i] will be passed to the [custom_action] signal when pressed. + Adds a button with label [i]text[/i] and a custom [i]action[/i] to the dialog and returns the created button. [i]action[/i] will be passed to the [signal custom_action] signal when pressed. If [code]true[/code], [i]right[/i] will place the button to the right of any sibling buttons. Default value: [code]false[/code]. </description> </method> diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml index 6b2c540c19..e215585b74 100644 --- a/doc/classes/ClassDB.xml +++ b/doc/classes/ClassDB.xml @@ -112,7 +112,7 @@ <argument index="1" name="no_inheritance" type="bool" default="false"> </argument> <description> - Returns an array with all the signals of 'class' or its ancestry if 'no_inheritance' is false. Every element of the array is a [Dictionary] as described in [class_get_signal]. + Returns an array with all the signals of 'class' or its ancestry if 'no_inheritance' is false. Every element of the array is a [Dictionary] as described in [method class_get_signal]. </description> </method> <method name="class_has_integer_constant" qualifiers="const"> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 4b6a9cca8a..9413a8aa34 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -51,7 +51,7 @@ <argument index="1" name="color" type="Color"> </argument> <description> - Overrides the color in the [theme] resource the node uses. + Overrides the color in the [member theme] resource the node uses. </description> </method> <method name="add_constant_override"> @@ -62,7 +62,7 @@ <argument index="1" name="constant" type="int"> </argument> <description> - Overrides an integer constant in the [Theme] resource the node uses. If the [code]constant[/code] is invalid, Godot clears the override. See [member Theme.INVALID_CONSTANT] for more information. + Overrides an integer constant in the [member theme] resource the node uses. If the [code]constant[/code] is invalid, Godot clears the override. See [member Theme.INVALID_CONSTANT] for more information. </description> </method> <method name="add_font_override"> @@ -73,7 +73,7 @@ <argument index="1" name="font" type="Font"> </argument> <description> - Overrides the [code]name[/code] font in the [theme] resource the node uses. If [code]font[/code] is empty, Godot clears the override. + Overrides the [code]name[/code] font in the [member theme] resource the node uses. If [code]font[/code] is empty, Godot clears the override. </description> </method> <method name="add_icon_override"> @@ -84,7 +84,7 @@ <argument index="1" name="texture" type="Texture"> </argument> <description> - Overrides the [code]name[/code] icon in the [theme] resource the node uses. If [code]icon[/code] is empty, Godot clears the override. + Overrides the [code]name[/code] icon in the [member theme] resource the node uses. If [code]icon[/code] is empty, Godot clears the override. </description> </method> <method name="add_shader_override"> @@ -95,7 +95,7 @@ <argument index="1" name="shader" type="Shader"> </argument> <description> - Overrides the [code]name[/code] shader in the [theme] resource the node uses. If [code]shader[/code] is empty, Godot clears the override. + Overrides the [code]name[/code] shader in the [member theme] resource the node uses. If [code]shader[/code] is empty, Godot clears the override. </description> </method> <method name="add_stylebox_override"> @@ -106,7 +106,7 @@ <argument index="1" name="stylebox" type="StyleBox"> </argument> <description> - Overrides the [code]name[/code] [Stylebox] in the [theme] resource the node uses. If [code]stylebox[/code] is empty, Godot clears the override. + Overrides the [code]name[/code] [Stylebox] in the [member theme] resource the node uses. If [code]stylebox[/code] is empty, Godot clears the override. </description> </method> <method name="can_drop_data" qualifiers="virtual"> diff --git a/doc/classes/InputEventJoypadButton.xml b/doc/classes/InputEventJoypadButton.xml index fdfdc10460..9614b0805b 100644 --- a/doc/classes/InputEventJoypadButton.xml +++ b/doc/classes/InputEventJoypadButton.xml @@ -15,7 +15,7 @@ </methods> <members> <member name="button_index" type="int" setter="set_button_index" getter="get_button_index"> - Button identifier. One of the [code]JOY_BUTTON_*[/code] constants from [@global Scope]. + Button identifier. One of the [code]JOY_BUTTON_*[/code] constants from [@GlobalScope]. </member> <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed"> If [code]true[/code] the button's state is pressed. If [code]false[/code] the button's state is released. diff --git a/doc/classes/InputEventJoypadMotion.xml b/doc/classes/InputEventJoypadMotion.xml index 001dce9a03..b01f2a3fe1 100644 --- a/doc/classes/InputEventJoypadMotion.xml +++ b/doc/classes/InputEventJoypadMotion.xml @@ -15,7 +15,7 @@ </methods> <members> <member name="axis" type="int" setter="set_axis" getter="get_axis"> - Axis identifier. Use one of the [code]JOY_AXIS_*[/code] constants in [@global Scope]. + Axis identifier. Use one of the [code]JOY_AXIS_*[/code] constants in [@GlobalScope]. </member> <member name="axis_value" type="float" setter="set_axis_value" getter="get_axis_value"> Current position of the joystick on the given axis. The value ranges from [code]-1.0[/code] to [code]1.0[/code]. A value of [code]0[/code] means the axis is in its resting position. diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml index dada5034f5..410738c68e 100644 --- a/doc/classes/InputEventKey.xml +++ b/doc/classes/InputEventKey.xml @@ -27,7 +27,7 @@ If [code]true[/code] the key's state is pressed. If [code]false[/code] the key's state is released. </member> <member name="scancode" type="int" setter="set_scancode" getter="get_scancode"> - Key scancode, one of the [code]KEY_*[/code] constants in [@global Scope]. + Key scancode, one of the [code]KEY_*[/code] constants in [@GlobalScope]. </member> <member name="unicode" type="int" setter="set_unicode" getter="get_unicode"> Key unicode identifier when relevant. diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml index f6950d0fbc..7a7036c857 100644 --- a/doc/classes/MultiplayerAPI.xml +++ b/doc/classes/MultiplayerAPI.xml @@ -61,7 +61,7 @@ </return> <description> Method used for polling the MultiplayerAPI. - You only need to worry about this if you are using [member Node.custom_multplayer] override. + You only need to worry about this if you are using [member Node.custom_multiplayer] override. SceneTree will poll the default MultiplayerAPI for you. </description> </method> diff --git a/doc/classes/Physics2DServer.xml b/doc/classes/Physics2DServer.xml index 1098b0d6b1..4a678d9f6b 100644 --- a/doc/classes/Physics2DServer.xml +++ b/doc/classes/Physics2DServer.xml @@ -566,7 +566,7 @@ <argument index="3" name="userdata" type="Variant" default="null"> </argument> <description> - Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force integration]). + Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]). </description> </method> <method name="body_set_max_contacts_reported"> diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml index dd2c322ee3..f5311974f2 100644 --- a/doc/classes/PhysicsServer.xml +++ b/doc/classes/PhysicsServer.xml @@ -605,7 +605,7 @@ <argument index="3" name="userdata" type="Variant" default="null"> </argument> <description> - Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force integration]). + Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]). </description> </method> <method name="body_set_kinematic_safe_margin"> diff --git a/doc/classes/ProceduralSky.xml b/doc/classes/ProceduralSky.xml index 11af73f953..664c80be5e 100644 --- a/doc/classes/ProceduralSky.xml +++ b/doc/classes/ProceduralSky.xml @@ -1,8 +1,11 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="ProceduralSky" inherits="Sky" category="Core" version="3.1"> <brief_description> + Type of [Sky] that is generated procedurally based on user input parameters. </brief_description> <description> + ProceduralSky provides a way to create an effective background quickly by defining procedural parameters for the sun, the sky and the ground. The sky and ground are very similar, they are defined by a color at the horizon, another color, and finally an easing curve to interpolate between these two colors. Similarly the sun is described by a position in the sky, a color, and an easing curve. However, the sun also defines a minimum and maximum angle, these two values define at what distance the easing curve begins and ends from the sun, and thus end up defining the size of the sun in the sky. + The ProceduralSky is updated on the CPU after the parameters change and stored in a texture and then displayed as a background in the scene. This makes it relatively unsuitable for realtime updates during gameplay. But with a small texture size it is still feasible to update relatively frequently becuase it is updated on a background thread when multi-threading is available. </description> <tutorials> </tutorials> @@ -12,36 +15,52 @@ </methods> <members> <member name="ground_bottom_color" type="Color" setter="set_ground_bottom_color" getter="get_ground_bottom_color"> + Color of the ground at the bottom. </member> <member name="ground_curve" type="float" setter="set_ground_curve" getter="get_ground_curve"> + How quickly the [member ground_horizon_color] fades into the [member ground_bottom_color]. </member> <member name="ground_energy" type="float" setter="set_ground_energy" getter="get_ground_energy"> + Amount of energy contribution from the ground. </member> <member name="ground_horizon_color" type="Color" setter="set_ground_horizon_color" getter="get_ground_horizon_color"> + Color of the ground at the horizon. </member> <member name="sky_curve" type="float" setter="set_sky_curve" getter="get_sky_curve"> + How quickly the [member sky_horizon_color] fades into the [member sky_top_color]. </member> <member name="sky_energy" type="float" setter="set_sky_energy" getter="get_sky_energy"> + Amount of energy contribution from the sky. </member> <member name="sky_horizon_color" type="Color" setter="set_sky_horizon_color" getter="get_sky_horizon_color"> + Color of the sky at the horizon. </member> <member name="sky_top_color" type="Color" setter="set_sky_top_color" getter="get_sky_top_color"> + Color of the sky at the top. </member> <member name="sun_angle_max" type="float" setter="set_sun_angle_max" getter="get_sun_angle_max"> + Distance from center of sun where it fades out completely. </member> <member name="sun_angle_min" type="float" setter="set_sun_angle_min" getter="get_sun_angle_min"> + Distance from sun where it goes from solid to starting to fade. </member> <member name="sun_color" type="Color" setter="set_sun_color" getter="get_sun_color"> + Color of the sun. </member> <member name="sun_curve" type="float" setter="set_sun_curve" getter="get_sun_curve"> + How quickly the sun fades away between [member sun_angle_min] and [member sun_angle_max] </member> <member name="sun_energy" type="float" setter="set_sun_energy" getter="get_sun_energy"> + Amount of energy contribution from the sun. </member> <member name="sun_latitude" type="float" setter="set_sun_latitude" getter="get_sun_latitude"> + The suns height using polar coordinates. </member> <member name="sun_longitude" type="float" setter="set_sun_longitude" getter="get_sun_longitude"> + The direction of the sun using polar coordinates. </member> <member name="texture_size" type="int" setter="set_texture_size" getter="get_texture_size" enum="ProceduralSky.TextureSize"> + Size of [Texture] that the ProceduralSky will generate. </member> </members> <constants> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 76d94fbfbc..11fc00d129 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -99,6 +99,8 @@ </argument> <argument index="2" name="can_be_hidden" type="bool" default="true"> </argument> + <argument index="3" name="wrap_index" type="int" default="0"> + </argument> <description> </description> </method> diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index f7c8cac93f..a03bf76d1b 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -2969,6 +2969,7 @@ void AnimationKeyEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { + update_keying(); EditorNode::get_singleton()->update_keying(); emit_signal("keying_changed"); } break; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 93c86d920a..665ce7658f 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -373,7 +373,6 @@ void FindReplaceBar::_hide_bar() { void FindReplaceBar::_show_search() { - hide(); // to update size correctly show(); search_text->grab_focus(); @@ -481,7 +480,7 @@ void FindReplaceBar::set_text_edit(TextEdit *p_text_edit) { void FindReplaceBar::_update_size() { - container->set_custom_minimum_size(Size2(0, hbc->get_size().height)); + container->set_size(Size2(hbc->get_size().width, 1)); } void FindReplaceBar::_bind_methods() { @@ -507,7 +506,8 @@ void FindReplaceBar::_bind_methods() { FindReplaceBar::FindReplaceBar() { - container = memnew(Control); + container = memnew(MarginContainer); + container->add_constant_override("margin_bottom", 5 * EDSCALE); add_child(container); container->set_clip_contents(true); container->set_h_size_flags(SIZE_EXPAND_FILL); @@ -592,8 +592,7 @@ FindReplaceBar::FindReplaceBar() { add_child(hide_button); hide_button->set_focus_mode(FOCUS_NONE); hide_button->connect("pressed", this, "_hide_pressed"); - hide_button->set_expand(true); - hide_button->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED); + hide_button->set_v_size_flags(SIZE_SHRINK_CENTER); } /*** CODE EDITOR ****/ diff --git a/editor/code_editor.h b/editor/code_editor.h index a860ad24e2..2a3bb1ba76 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -63,7 +63,7 @@ class FindReplaceBar : public HBoxContainer { GDCLASS(FindReplaceBar, HBoxContainer); - Control *container; + MarginContainer *container; LineEdit *search_text; ToolButton *find_prev; ToolButton *find_next; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp new file mode 100644 index 0000000000..38e74c126e --- /dev/null +++ b/editor/editor_inspector.cpp @@ -0,0 +1,1831 @@ +/*************************************************************************/ +/* editor_inspector.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_inspector.h" +#include "array_property_edit.h" +#include "dictionary_property_edit.h" +#include "editor_node.h" +#include "editor_scale.h" +#include "multi_node_edit.h" +#include "scene/resources/packed_scene.h" + +// TODO: +// arrays + +Size2 EditorProperty::get_minimum_size() const { + + Size2 ms; + for (int i = 0; i < get_child_count(); i++) { + + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + if (!c->is_visible()) + continue; + Size2 minsize = c->get_combined_minimum_size(); + ms.width = MAX(ms.width, minsize.width); + ms.height = MAX(ms.height, minsize.height); + } + + if (keying) { + Ref<Texture> key = get_icon("Key", "EditorIcons"); + ms.width += key->get_width() + get_constant("hseparator", "Tree"); + } + + if (checkable) { + Ref<Texture> check = get_icon("checked", "CheckBox"); + ms.width += check->get_width() + get_constant("hseparator", "Tree"); + } + + if (label_layout == LABEL_LAYOUT_TOP) { + Ref<Font> font = get_font("font", "Tree"); + ms.height += font->get_height(); + ms.height += get_constant("vseparation", "Tree"); + } + + return ms; +} + +void EditorProperty::_notification(int p_what) { + + if (p_what == NOTIFICATION_SORT_CHILDREN) { + + Size2 size = get_size(); + Rect2 rect; + + if (label_layout == LABEL_LAYOUT_LEFT) { + int child_room = size.width / 2; + + //compute room needed + for (int i = 0; i < get_child_count(); i++) { + + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + + Size2 minsize = c->get_combined_minimum_size(); + child_room = MAX(child_room, minsize.width); + } + + text_size = MAX(0, size.width - child_room + 4 * EDSCALE); + + rect = Rect2(text_size, 0, size.width - text_size, size.height); + } else { + Ref<Font> font = get_font("font", "Tree"); + + text_size = size.width; + rect.position.x = 0; + rect.position.y = font->get_height() + get_constant("vseparation", "Tree"); + rect.size = get_size(); + rect.size.height -= rect.position.y; + } + + if (keying) { + Ref<Texture> key; + + if (use_keying_next()) { + key = get_icon("KeyNext", "EditorIcons"); + } else { + key = get_icon("Key", "EditorIcons"); + } + + rect.size.x -= key->get_width() + get_constant("hseparator", "Tree"); + } + + //set children + for (int i = 0; i < get_child_count(); i++) { + + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + + fit_child_in_rect(c, rect); + } + + update(); //need to redraw text + } + + if (p_what == NOTIFICATION_DRAW) { + Ref<Font> font = get_font("font", "Tree"); + + Size2 size = get_size(); + if (label_layout == LABEL_LAYOUT_TOP) { + size.height = font->get_height(); + } else if (label_reference) { + size.height = label_reference->get_size().height; + } + + if (selected) { + Ref<StyleBox> sb = get_stylebox("selected", "Tree"); + draw_style_box(sb, Rect2(Vector2(), size)); + } + + Color color; + if (draw_red) { + color = get_color("error_color", "Editor"); + } else { + color = get_color("font_color", "Tree"); + } + if (label.find(".") != -1) { + color.a = 0.5; //this should be un-hacked honestly, as it's used for editor overrides + } + + int ofs = 0; + if (checkable) { + Ref<Texture> checkbox; + if (checked) + checkbox = get_icon("checked", "CheckBox"); + else + checkbox = get_icon("unchecked", "CheckBox"); + + Color color(1, 1, 1); + if (check_hover) { + color.r *= 1.2; + color.g *= 1.2; + color.b *= 1.2; + } + check_rect = Rect2(ofs, ((size.height - checkbox->get_height()) / 2), checkbox->get_width(), checkbox->get_height()); + draw_texture(checkbox, check_rect.position, color); + ofs += get_constant("hseparator", "Tree"); + ofs += checkbox->get_width(); + } else { + check_rect = Rect2(); + } + + int text_limit = text_size; + + if (can_revert) { + Ref<Texture> reload_icon = get_icon("ReloadSmall", "EditorIcons"); + text_limit -= reload_icon->get_width() + get_constant("hseparator", "Tree") * 2; + revert_rect = Rect2(text_limit + get_constant("hseparator", "Tree"), (size.height - reload_icon->get_height()) / 2, reload_icon->get_width(), reload_icon->get_height()); + + Color color(1, 1, 1); + if (revert_hover) { + color.r *= 1.2; + color.g *= 1.2; + color.b *= 1.2; + } + + draw_texture(reload_icon, revert_rect.position, color); + } else { + revert_rect = Rect2(); + } + + int v_ofs = (size.height - font->get_height()) / 2; + draw_string(font, Point2(ofs, v_ofs + font->get_ascent()), label, color, text_limit); + + if (keying) { + Ref<Texture> key; + + if (use_keying_next()) { + key = get_icon("KeyNext", "EditorIcons"); + } else { + key = get_icon("Key", "EditorIcons"); + } + + ofs = size.width - key->get_width() - get_constant("hseparator", "Tree"); + + Color color(1, 1, 1); + if (keying_hover) { + color.r *= 1.2; + color.g *= 1.2; + color.b *= 1.2; + } + keying_rect = Rect2(ofs, ((size.height - key->get_height()) / 2), key->get_width(), key->get_height()); + draw_texture(key, keying_rect.position, color); + } else { + keying_rect = Rect2(); + } + + //int vs = get_constant("vseparation", "Tree"); + Color guide_color = get_color("guide_color", "Tree"); + int vs_height = get_size().height; // vs / 2; + draw_line(Point2(0, vs_height), Point2(get_size().width, vs_height), guide_color); + } +} + +void EditorProperty::set_label(const String &p_label) { + label = p_label; + update(); +} + +String EditorProperty::get_label() const { + return label; +} + +Object *EditorProperty::get_edited_object() { + return object; +} + +StringName EditorProperty::get_edited_property() { + return property; +} + +void EditorProperty::update_property() { + if (get_script_instance()) + get_script_instance()->call("update_property"); +} + +void EditorProperty::set_read_only(bool p_read_only) { + read_only = p_read_only; +} + +bool EditorProperty::is_read_only() const { + return read_only; +} + +bool EditorProperty::_might_be_in_instance() { + + if (!object) + return false; + + Node *node = Object::cast_to<Node>(object); + + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + + bool might_be = false; + + while (node) { + + if (node->get_scene_instance_state().is_valid()) { + might_be = true; + break; + } + if (node == edited_scene) { + if (node->get_scene_inherited_state().is_valid()) { + might_be = true; + break; + } + might_be = false; + break; + } + node = node->get_owner(); + } + + return might_be; // or might not be +} + +bool EditorProperty::_get_instanced_node_original_property(const StringName &p_prop, Variant &value) { + + Node *node = Object::cast_to<Node>(object); + + if (!node) + return false; + + Node *orig = node; + + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + + bool found = false; + + while (node) { + + Ref<SceneState> ss; + + if (node == edited_scene) { + ss = node->get_scene_inherited_state(); + + } else { + ss = node->get_scene_instance_state(); + } + + if (ss.is_valid()) { + + NodePath np = node->get_path_to(orig); + int node_idx = ss->find_node_by_path(np); + if (node_idx >= 0) { + bool lfound = false; + Variant lvar; + lvar = ss->get_property_value(node_idx, p_prop, lfound); + if (lfound) { + + found = true; + value = lvar; + } + } + } + if (node == edited_scene) { + //just in case + break; + } + node = node->get_owner(); + } + + return found; +} + +bool EditorProperty::_is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage) { + + // this is a pretty difficult function, because a property may not be saved but may have + // the flag to not save if one or if zero + + { + Node *node = Object::cast_to<Node>(object); + if (!node) + return false; + + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + bool found_state = false; + + while (node) { + + Ref<SceneState> ss; + + if (node == edited_scene) { + ss = node->get_scene_inherited_state(); + + } else { + ss = node->get_scene_instance_state(); + } + + if (ss.is_valid()) { + found_state = true; + } + if (node == edited_scene) { + //just in case + break; + } + node = node->get_owner(); + } + + if (!found_state) + return false; //pointless to check if we are not comparing against anything. + } + + if (p_orig.get_type() == Variant::NIL) { + // not found (was not saved) + // check if it was not saved due to being zero or one + if (p_current.is_zero() && property_usage & PROPERTY_USAGE_STORE_IF_NONZERO) + return false; + if (p_current.is_one() && property_usage & PROPERTY_USAGE_STORE_IF_NONONE) + return false; + } + + if (p_current.get_type() == Variant::REAL && p_orig.get_type() == Variant::REAL) { + float a = p_current; + float b = p_orig; + + return Math::abs(a - b) > CMP_EPSILON; //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error + } + + return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig)); +} + +bool EditorProperty::_is_instanced_node_with_original_property_different() { + + bool mbi = _might_be_in_instance(); + if (mbi) { + Variant vorig; + int usage = property_usage & (PROPERTY_USAGE_STORE_IF_NONONE | PROPERTY_USAGE_STORE_IF_NONZERO); + if (_get_instanced_node_original_property(property, vorig) || usage) { + Variant v = object->get(property); + + if (_is_property_different(v, vorig, usage)) { + return true; + } + } + } + return false; +} + +void EditorProperty::update_reload_status() { + + if (property == StringName()) + return; //no property, so nothing to do + + bool has_reload = false; + + if (_is_instanced_node_with_original_property_different()) { + has_reload = true; + } + + if (object->call("property_can_revert", property).operator bool()) { + + has_reload = true; + } + + if (!has_reload && !object->get_script().is_null()) { + Ref<Script> scr = object->get_script(); + Variant orig_value; + if (scr->get_property_default_value(property, orig_value)) { + if (orig_value != object->get(property)) { + has_reload = true; + } + } + } + + if (has_reload != can_revert) { + can_revert = has_reload; + update(); + } +} + +bool EditorProperty::use_keying_next() const { + return false; +} +void EditorProperty::set_checkable(bool p_checkable) { + + checkable = p_checkable; + update(); + queue_sort(); +} + +bool EditorProperty::is_checkable() const { + + return checkable; +} + +void EditorProperty::set_checked(bool p_checked) { + + checked = p_checked; + update(); +} + +bool EditorProperty::is_checked() const { + + return checked; +} + +void EditorProperty::set_draw_red(bool p_draw_red) { + + draw_red = p_draw_red; + update(); +} + +void EditorProperty::set_keying(bool p_keying) { + keying = p_keying; + update(); + queue_sort(); +} + +bool EditorProperty::is_keying() const { + return keying; +} + +bool EditorProperty::is_draw_red() const { + + return draw_red; +} + +void EditorProperty::_focusable_focused(int p_index) { + + bool already_selected = selected; + selected = true; + selected_focusable = p_index; + update(); + if (!already_selected && selected) { + emit_signal("selected", property, selected_focusable); + } +} + +void EditorProperty::add_focusable(Control *p_control) { + + p_control->connect("focus_entered", this, "_focusable_focused", varray(focusables.size())); + focusables.push_back(p_control); +} + +void EditorProperty::select(int p_focusable) { + + bool already_selected = selected; + + if (p_focusable >= 0) { + ERR_FAIL_INDEX(p_focusable, focusables.size()); + focusables[p_focusable]->grab_focus(); + } else { + selected = true; + update(); + } + + if (!already_selected && selected) { + emit_signal("selected", property, selected_focusable); + } +} + +void EditorProperty::deselect() { + selected = false; + selected_focusable = -1; + update(); +} + +bool EditorProperty::is_selected() const { + return selected; +} + +void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) { + + if (property == StringName()) + return; + + Ref<InputEventMouse> me = p_event; + + if (me.is_valid()) { + + bool button_left = me->get_button_mask() & BUTTON_MASK_LEFT; + + bool new_keying_hover = keying_rect.has_point(me->get_position()) && !button_left; + if (new_keying_hover != keying_hover) { + keying_hover = new_keying_hover; + update(); + } + + bool new_revert_hover = revert_rect.has_point(me->get_position()) && !button_left; + if (new_revert_hover != revert_hover) { + revert_hover = new_revert_hover; + update(); + } + + bool new_check_hover = check_rect.has_point(me->get_position()) && !button_left; + if (new_check_hover != check_hover) { + check_hover = new_check_hover; + update(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + + if (!selected) { + selected = true; + emit_signal("selected", property, -1); + update(); + } + + if (keying_rect.has_point(mb->get_position())) { + emit_signal("property_keyed", property); + } + + if (revert_rect.has_point(mb->get_position())) { + + Variant vorig; + + if (_might_be_in_instance() && _get_instanced_node_original_property(property, vorig)) { + + emit_signal("property_changed", property, vorig.duplicate(true)); + update_property(); + return; + } + + if (object->call("property_can_revert", property).operator bool()) { + Variant rev = object->call("property_get_revert", property); + emit_signal("property_changed", property, rev); + update_property(); + } + + if (!object->get_script().is_null()) { + Ref<Script> scr = object->get_script(); + Variant orig_value; + if (scr->get_property_default_value(property, orig_value)) { + emit_signal("property_changed", property, orig_value); + update_property(); + } + } + } + if (check_rect.has_point(mb->get_position())) { + checked = !checked; + update(); + emit_signal("property_checked", property, checked); + } + } +} + +void EditorProperty::set_label_reference(Control *p_control) { + + label_reference = p_control; +} + +Variant EditorProperty::get_drag_data(const Point2 &p_point) { + + if (property == StringName()) + return Variant(); + + Dictionary dp; + dp["type"] = "obj_property"; + dp["object"] = object; + dp["property"] = property; + dp["value"] = object->get(property); + + Label *label = memnew(Label); + label->set_text(property); + set_drag_preview(label); + return dp; +} + +void EditorProperty::set_label_layout(LabelLayout p_layout) { + label_layout = p_layout; + queue_sort(); + update(); +} + +void EditorProperty::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_label", "text"), &EditorProperty::set_label); + ClassDB::bind_method(D_METHOD("get_label"), &EditorProperty::get_label); + + ClassDB::bind_method(D_METHOD("set_read_only", "read_only"), &EditorProperty::set_read_only); + ClassDB::bind_method(D_METHOD("is_read_only"), &EditorProperty::is_read_only); + + ClassDB::bind_method(D_METHOD("set_checkable", "checkable"), &EditorProperty::set_checkable); + ClassDB::bind_method(D_METHOD("is_checkable"), &EditorProperty::is_checkable); + + ClassDB::bind_method(D_METHOD("set_checked", "checked"), &EditorProperty::set_checked); + ClassDB::bind_method(D_METHOD("is_checked"), &EditorProperty::is_checked); + + ClassDB::bind_method(D_METHOD("set_draw_red", "draw_red"), &EditorProperty::set_draw_red); + ClassDB::bind_method(D_METHOD("is_draw_red"), &EditorProperty::is_draw_red); + + ClassDB::bind_method(D_METHOD("set_keying", "keying"), &EditorProperty::set_keying); + ClassDB::bind_method(D_METHOD("is_keying"), &EditorProperty::is_keying); + + ClassDB::bind_method(D_METHOD("get_edited_property"), &EditorProperty::get_edited_property); + ClassDB::bind_method(D_METHOD("get_edited_object"), &EditorProperty::get_edited_object); + + ClassDB::bind_method(D_METHOD("_gui_input"), &EditorProperty::_gui_input); + ClassDB::bind_method(D_METHOD("_focusable_focused"), &EditorProperty::_focusable_focused); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "checkable"), "set_checkable", "is_checkable"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "checked"), "set_checked", "is_checked"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_red"), "set_draw_red", "is_draw_red"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keying"), "set_keying", "is_keying"); + ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); + ADD_SIGNAL(MethodInfo("multiple_properties_changed", PropertyInfo(Variant::POOL_STRING_ARRAY, "properties"), PropertyInfo(Variant::ARRAY, "value"))); + ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property"))); + ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::STRING, "bool"))); + ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx"))); + + MethodInfo vm; + vm.name = "update_property"; + BIND_VMETHOD(vm); +} + +EditorProperty::EditorProperty() { + + text_size = 0; + read_only = false; + checkable = false; + checked = false; + draw_red = false; + keying = false; + keying_hover = false; + revert_hover = false; + check_hover = false; + can_revert = false; + property_usage = 0; + selected = false; + selected_focusable = -1; + label_reference = NULL; + label_layout = LABEL_LAYOUT_LEFT; +} +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +void EditorInspectorPlugin::add_custom_control(Control *control) { + + AddedEditor ae; + ae.property_editor = control; + added_editors.push_back(ae); +} + +void EditorInspectorPlugin::add_property_editor(const String &p_for_property, Control *p_prop) { + + ERR_FAIL_COND(Object::cast_to<EditorProperty>(p_prop) == NULL); + + AddedEditor ae; + ae.properties.push_back(p_for_property); + ae.property_editor = p_prop; + added_editors.push_back(ae); +} + +void EditorInspectorPlugin::add_property_editor_for_multiple_properties(const String &p_label, const Vector<String> &p_properties, Control *p_prop) { + + AddedEditor ae; + ae.properties = p_properties; + ae.property_editor = p_prop; + ae.label = p_label; + added_editors.push_back(ae); +} + +bool EditorInspectorPlugin::can_handle(Object *p_object) { + + if (get_script_instance()) { + return get_script_instance()->call("can_handle", p_object); + } + return false; +} +void EditorInspectorPlugin::parse_begin(Object *p_object) { + + if (get_script_instance()) { + get_script_instance()->call("parse_begin", p_object); + } +} +bool EditorInspectorPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { + + if (get_script_instance()) { + Variant arg[6] = { + p_object, p_type, p_path, p_hint, p_hint_text, p_usage + }; + const Variant *argptr[6] = { + &arg[0], &arg[1], &arg[2], &arg[3], &arg[4], &arg[5] + }; + + Variant::CallError err; + return get_script_instance()->call("parse_property", (const Variant **)&argptr, 6, err); + } + return false; +} +void EditorInspectorPlugin::parse_end() { + + if (get_script_instance()) { + get_script_instance()->call("parse_end"); + } +} + +void EditorInspectorPlugin::_bind_methods() { + + ClassDB::bind_method(D_METHOD("add_custom_control", "control"), &EditorInspectorPlugin::add_custom_control); + ClassDB::bind_method(D_METHOD("add_property_editor", "property", "editor"), &EditorInspectorPlugin::add_property_editor); + ClassDB::bind_method(D_METHOD("add_property_editor_for_multiple_properties", "label", "properties", "editor"), &EditorInspectorPlugin::add_property_editor_for_multiple_properties); + + MethodInfo vm; + vm.name = "can_handle"; + vm.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); + BIND_VMETHOD(vm); + vm.name = "parse_begin"; + BIND_VMETHOD(vm); + vm.name = "parse_property"; + vm.return_val.type = Variant::BOOL; + vm.arguments.push_back(PropertyInfo(Variant::INT, "type")); + vm.arguments.push_back(PropertyInfo(Variant::STRING, "path")); + vm.arguments.push_back(PropertyInfo(Variant::INT, "hint")); + vm.arguments.push_back(PropertyInfo(Variant::STRING, "hint_text")); + vm.arguments.push_back(PropertyInfo(Variant::INT, "usage")); + BIND_VMETHOD(vm); + vm.arguments.clear(); + vm.return_val.type = Variant::NIL; + vm.name = "parse_end"; + BIND_VMETHOD(vm); +} + +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +void EditorInspectorCategory::_notification(int p_what) { + + if (p_what == NOTIFICATION_DRAW) { + + draw_rect(Rect2(Vector2(), get_size()), bg_color); + Ref<Font> font = get_font("font", "Tree"); + + int hs = get_constant("hseparation", "Tree"); + + int w = font->get_string_size(label).width; + if (icon.is_valid()) { + w += hs + icon->get_width(); + } + + int ofs = (get_size().width - w) / 2; + + if (icon.is_valid()) { + draw_texture(icon, Point2(ofs, (get_size().height - icon->get_height()) / 2).floor()); + ofs += hs + icon->get_width(); + } + + Color color = get_color("font_color", "Tree"); + draw_string(font, Point2(ofs, font->get_ascent() + (get_size().height - font->get_height()) / 2).floor(), label, color, get_size().width); + } +} + +Size2 EditorInspectorCategory::get_minimum_size() const { + + Ref<Font> font = get_font("font", "Tree"); + + Size2 ms; + ms.width = 1; + ms.height = font->get_height(); + if (icon.is_valid()) { + ms.height = MAX(icon->get_height(), ms.height); + } + ms.height += get_constant("vseparation", "Tree"); + + return ms; +} + +EditorInspectorCategory::EditorInspectorCategory() { +} + +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +void EditorInspectorSection::_notification(int p_what) { + + if (p_what == NOTIFICATION_SORT_CHILDREN) { + + Ref<Font> font = get_font("font", "Tree"); + Ref<Texture> arrow; + +#ifdef TOOLS_ENABLED + if (foldable) { + if (object->editor_is_section_unfolded(section)) { + arrow = get_icon("arrow", "Tree"); + } else { + arrow = get_icon("arrow_collapsed", "Tree"); + } + } +#endif + + Size2 size = get_size(); + Point2 offset; + offset.y = font->get_height(); + if (arrow.is_valid()) { + offset.y = MAX(offset.y, arrow->get_height()); + } + + offset.y += get_constant("vseparation", "Tree"); + offset.x += get_constant("item_margin", "Tree"); + + Rect2 rect(offset, size - offset); + + //set children + for (int i = 0; i < get_child_count(); i++) { + + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + if (!c->is_visible_in_tree()) + continue; + + fit_child_in_rect(c, rect); + } + + update(); //need to redraw text + } + + if (p_what == NOTIFICATION_DRAW) { + + Ref<Texture> arrow; + +#ifdef TOOLS_ENABLED + if (foldable) { + if (object->editor_is_section_unfolded(section)) { + arrow = get_icon("arrow", "Tree"); + } else { + arrow = get_icon("arrow_collapsed", "Tree"); + } + } +#endif + + Ref<Font> font = get_font("font", "Tree"); + + int h = font->get_height(); + if (arrow.is_valid()) { + h = MAX(h, arrow->get_height()); + } + h += get_constant("vseparation", "Tree"); + + draw_rect(Rect2(Vector2(), Vector2(get_size().width, h)), bg_color); + + int hs = get_constant("hseparation", "Tree"); + + int ofs = 0; + if (arrow.is_valid()) { + draw_texture(arrow, Point2(ofs, (h - arrow->get_height()) / 2).floor()); + ofs += hs + arrow->get_width(); + } + + Color color = get_color("font_color", "Tree"); + draw_string(font, Point2(ofs, font->get_ascent() + (h - font->get_height()) / 2).floor(), label, color, get_size().width); + } +} + +Size2 EditorInspectorSection::get_minimum_size() const { + + Size2 ms; + for (int i = 0; i < get_child_count(); i++) { + + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + if (!c->is_visible()) + continue; + Size2 minsize = c->get_combined_minimum_size(); + ms.width = MAX(ms.width, minsize.width); + ms.height = MAX(ms.height, minsize.height); + } + + Ref<Font> font = get_font("font", "Tree"); + ms.height += font->get_ascent() + get_constant("vseparation", "Tree"); + ms.width += get_constant("item_margin", "Tree"); + + return ms; +} + +void EditorInspectorSection::setup(const String &p_section, const String &p_label, Object *p_object, const Color &p_bg_color, bool p_foldable) { + + section = p_section; + label = p_label; + object = p_object; + bg_color = p_bg_color; + foldable = p_foldable; + +#ifdef TOOLS_ENABLED + if (foldable) { + if (object->editor_is_section_unfolded(section)) { + vbox->show(); + } else { + vbox->hide(); + } + } + // void editor_set_section_unfold(const String &p_section, bool p_unfolded); + +#endif +} + +void EditorInspectorSection::_gui_input(const Ref<InputEvent> &p_event) { + + if (!foldable) + return; + +#ifdef TOOLS_ENABLED + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + bool unfold = !object->editor_is_section_unfolded(section); + object->editor_set_section_unfold(section, unfold); + if (unfold) { + vbox->show(); + } else { + vbox->hide(); + } + } +#endif +} + +VBoxContainer *EditorInspectorSection::get_vbox() { + return vbox; +} + +void EditorInspectorSection::unfold() { + + if (!foldable) + return; +#ifdef TOOLS_ENABLED + + object->editor_set_section_unfold(section, true); + vbox->show(); + update(); +#endif +} + +void EditorInspectorSection::fold() { + if (!foldable) + return; + +#ifdef TOOLS_ENABLED + + object->editor_set_section_unfold(section, false); + vbox->hide(); + update(); +#endif +} + +void EditorInspectorSection::_bind_methods() { + + ClassDB::bind_method(D_METHOD("setup", "section", "label", "object", "bg_color", "foldable"), &EditorInspectorSection::setup); + ClassDB::bind_method(D_METHOD("get_vbox"), &EditorInspectorSection::get_vbox); + ClassDB::bind_method(D_METHOD("unfold"), &EditorInspectorSection::unfold); + ClassDB::bind_method(D_METHOD("fold"), &EditorInspectorSection::fold); + ClassDB::bind_method(D_METHOD("_gui_input"), &EditorInspectorSection::_gui_input); +} + +EditorInspectorSection::EditorInspectorSection() { + object = NULL; + foldable = false; + vbox = memnew(VBoxContainer); + add_child(vbox); +} + +//////////////////////////////////////////////// +//////////////////////////////////////////////// + +Ref<EditorInspectorPlugin> EditorInspector::inspector_plugins[MAX_PLUGINS]; +int EditorInspector::inspector_plugin_count = 0; + +void EditorInspector::add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) { + + ERR_FAIL_COND(inspector_plugin_count == MAX_PLUGINS); + + for (int i = 0; i < inspector_plugin_count; i++) { + if (inspector_plugins[i] == p_plugin) + return; //already exists + } + inspector_plugins[inspector_plugin_count++] = p_plugin; +} + +void EditorInspector::remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) { + + ERR_FAIL_COND(inspector_plugin_count == MAX_PLUGINS); + + int idx = -1; + for (int i = 0; i < inspector_plugin_count; i++) { + if (inspector_plugins[i] == p_plugin) { + idx = i; + break; + } + } + + for (int i = idx; i < inspector_plugin_count - 1; i++) { + inspector_plugins[i] = inspector_plugins[i + 1]; + } + inspector_plugin_count--; +} + +void EditorInspector::cleanup_plugins() { + for (int i = 0; i < inspector_plugin_count; i++) { + inspector_plugins[i].unref(); + } + inspector_plugin_count = 0; +} + +void EditorInspector::set_undo_redo(UndoRedo *p_undo_redo) { + undo_redo = p_undo_redo; +} + +String EditorInspector::get_selected_path() const { + + return property_selected; +} + +void EditorInspector::update_tree() { + + //to update properly if all is refreshed + StringName current_selected = property_selected; + int current_focusable = property_focusable; + + _clear(); + + if (!object) + return; + + List<Ref<EditorInspectorPlugin> > valid_plugins; + + for (int i = inspector_plugin_count - 1; i >= 0; i--) { //start by last, so lastly added can override newly added + if (!inspector_plugins[i]->can_handle(object)) + continue; + valid_plugins.push_back(inspector_plugins[i]); + } + + bool draw_red = false; + + { + Node *nod = Object::cast_to<Node>(object); + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (nod && es != nod && nod->get_owner() != es) { + draw_red = true; + } + } + + // TreeItem *current_category = NULL; + + String filter = search_box ? search_box->get_text() : ""; + String group; + String group_base; + + List<PropertyInfo> plist; + object->get_property_list(&plist, true); + + HashMap<String, VBoxContainer *> item_path; + item_path[""] = main_vbox; + + Color sscolor = get_color("prop_subsection", "Editor"); + + for (List<PropertyInfo>::Element *I = plist.front(); I; I = I->next()) { + + PropertyInfo &p = I->get(); + + //make sure the property can be edited + + if (p.usage & PROPERTY_USAGE_GROUP) { + + group = p.name; + group_base = p.hint_string; + + continue; + + } else if (p.usage & PROPERTY_USAGE_CATEGORY) { + + group = ""; + group_base = ""; + + if (!show_categories) + continue; + + List<PropertyInfo>::Element *N = I->next(); + bool valid = true; + //if no properties in category, skip + while (N) { + if (N->get().usage & PROPERTY_USAGE_EDITOR) + break; + if (N->get().usage & PROPERTY_USAGE_CATEGORY) { + valid = false; + break; + } + N = N->next(); + } + if (!valid) + continue; //empty, ignore + + EditorInspectorCategory *category = memnew(EditorInspectorCategory); + main_vbox->add_child(category); + + String type = p.name; + if (has_icon(type, "EditorIcons")) + category->icon = get_icon(type, "EditorIcons"); + else + category->icon = get_icon("Object", "EditorIcons"); + category->label = type; + + category->bg_color = get_color("prop_category", "Editor"); + if (use_doc_hints) { + StringName type = p.name; + if (!class_descr_cache.has(type)) { + + String descr; + DocData *dd = EditorHelp::get_doc_data(); + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(type); + if (E) { + descr = E->get().brief_description; + } + class_descr_cache[type] = descr.word_wrap(80); + } + + category->set_tooltip(TTR("Class:") + " " + p.name + (class_descr_cache[type] == "" ? "" : "\n\n" + class_descr_cache[type])); + } + continue; + + } else if (!(p.usage & PROPERTY_USAGE_EDITOR)) + continue; + + if (hide_script && p.name == "script") + continue; + + String basename = p.name; + if (group != "") { + if (group_base != "") { + if (basename.begins_with(group_base)) { + basename = basename.replace_first(group_base, ""); + } else if (group_base.begins_with(basename)) { + //keep it, this is used pretty often + } else { + group = ""; //no longer using group base, clear + } + } + } + + if (group != "") { + basename = group + "/" + basename; + } + + String name = (basename.find("/") != -1) ? basename.right(basename.find_last("/") + 1) : basename; + + if (capitalize_paths) { + int dot = name.find("."); + if (dot != -1) { + String ov = name.right(dot); + name = name.substr(0, dot); + name = name.camelcase_to_underscore().capitalize(); + name += ov; + + } else { + name = name.camelcase_to_underscore().capitalize(); + } + } + + String path = basename.left(basename.find_last("/")); + + if (use_filter && filter != "") { + + String cat = path; + + if (capitalize_paths) + cat = cat.capitalize(); + + if (!filter.is_subsequence_ofi(cat) && !filter.is_subsequence_ofi(name)) + continue; + } + + VBoxContainer *current_vbox = main_vbox; + + { + + String acc_path = ""; + int level = 1; + for (int i = 0; i < path.get_slice_count("/"); i++) { + String path_name = path.get_slice("/", i); + if (i > 0) + acc_path += "/"; + acc_path += path_name; + if (!item_path.has(acc_path)) { + EditorInspectorSection *section = memnew(EditorInspectorSection); + current_vbox->add_child(section); + sections.push_back(section); + + if (capitalize_paths) + path_name = path_name.capitalize(); + Color c = sscolor; + c.a /= level; + section->setup(path_name, acc_path, object, c, use_folding); + + item_path[acc_path] = section->get_vbox(); + } + current_vbox = item_path[acc_path]; + level = (MIN(level + 1, 4)); + } + } + + bool checkable = false; + bool checked = false; + if (p.usage & PROPERTY_USAGE_CHECKABLE) { + checkable = true; + checked = p.usage & PROPERTY_USAGE_CHECKED; + } + + String doc_hint; + + if (use_doc_hints) { + + StringName classname = object->get_class_name(); + StringName propname = p.name; + String descr; + bool found = false; + + Map<StringName, Map<StringName, String> >::Element *E = descr_cache.find(classname); + if (E) { + Map<StringName, String>::Element *F = E->get().find(propname); + if (F) { + found = true; + descr = F->get(); + } + } + + if (!found) { + DocData *dd = EditorHelp::get_doc_data(); + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(classname); + while (E && descr == String()) { + for (int i = 0; i < E->get().properties.size(); i++) { + if (E->get().properties[i].name == propname.operator String()) { + descr = E->get().properties[i].description.strip_edges().word_wrap(80); + break; + } + } + if (!E->get().inherits.empty()) { + E = dd->class_list.find(E->get().inherits); + } else { + break; + } + } + descr_cache[classname][propname] = descr; + } + + doc_hint = descr; + } + +#if 0 + if (p.name == selected_property) { + + item->select(1); + } +#endif + for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) { + Ref<EditorInspectorPlugin> ped = E->get(); + ped->parse_property(object, p.type, p.name, p.hint, p.hint_string, p.usage); + for (List<EditorInspectorPlugin::AddedEditor>::Element *F = ped->added_editors.front(); F; F = F->next()) { + + EditorProperty *ep = Object::cast_to<EditorProperty>(F->get().property_editor); + current_vbox->add_child(F->get().property_editor); + + if (ep) { + + ep->object = object; + ep->connect("property_changed", this, "_property_changed"); + ep->connect("property_keyed", this, "_property_keyed"); + ep->connect("property_checked", this, "_property_checked"); + ep->connect("selected", this, "_property_selected"); + ep->connect("multiple_properties_changed", this, "_multiple_properties_changed"); + ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED); + ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED); + if (doc_hint != String()) { + ep->set_tooltip(TTR("Property: ") + p.name + "\n\n" + doc_hint); + } else { + ep->set_tooltip(TTR("Property: ") + p.name); + } + ep->set_draw_red(draw_red); + ep->set_checkable(checkable); + ep->set_checked(checked); + ep->set_keying(keying); + + if (F->get().properties.size()) { + + if (F->get().properties.size() == 1) { + //since it's one, associate: + ep->property = F->get().properties[0]; + ep->property_usage = p.usage; + //and set label? + } + + if (F->get().label != String()) { + ep->set_label(F->get().label); + } else { + //use existin one + ep->set_label(name); + } + for (int i = 0; i < F->get().properties.size(); i++) { + String prop = F->get().properties[i]; + + if (!editor_property_map.has(prop)) { + editor_property_map[prop] = List<EditorProperty *>(); + } + editor_property_map[prop].push_back(ep); + } + } + + ep->set_read_only(read_only); + ep->update_property(); + ep->update_reload_status(); + + if (current_selected && ep->property == current_selected) { + ep->select(current_focusable); + } + } + } + ped->added_editors.clear(); + } + } + + //see if this property exists and should be kept +} +void EditorInspector::update_property(const String &p_prop) { + if (!editor_property_map.has(p_prop)) + return; + + for (List<EditorProperty *>::Element *E = editor_property_map[p_prop].front(); E; E = E->next()) { + E->get()->update_property(); + E->get()->update_reload_status(); + } +} + +void EditorInspector::_clear() { + + editor_property_map.clear(); + sections.clear(); + pending.clear(); + property_selected = StringName(); + property_focusable = -1; + while (main_vbox->get_child_count()) { + memdelete(main_vbox->get_child(0)); + } +} + +void EditorInspector::refresh() { + + if (refresh_countdown > 0) + return; + refresh_countdown = EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval"); +} + +void EditorInspector::edit(Object *p_object) { + if (object != p_object) { + _clear(); + } + + if (object) { + + object->remove_change_receptor(this); + } + + object = p_object; + if (object) { + object->add_change_receptor(this); + update_tree(); + } +} + +void EditorInspector::set_keying(bool p_active) { + if (keying == p_active) + return; + keying = p_active; + update_tree(); +} +void EditorInspector::set_read_only(bool p_read_only) { + read_only = p_read_only; + update_tree(); +} + +bool EditorInspector::is_capitalize_paths_enabled() const { + + return capitalize_paths; +} +void EditorInspector::set_enable_capitalize_paths(bool p_capitalize) { + capitalize_paths = p_capitalize; + update_tree(); +} + +void EditorInspector::set_autoclear(bool p_enable) { + autoclear = p_enable; +} + +void EditorInspector::set_show_categories(bool p_show) { + show_categories = p_show; + update_tree(); +} + +void EditorInspector::set_use_doc_hints(bool p_enable) { + use_doc_hints = p_enable; + update_tree(); +} +void EditorInspector::set_hide_script(bool p_hide) { + hide_script = p_hide; + update_tree(); +} +void EditorInspector::set_use_filter(bool p_use) { + use_filter = p_use; + update_tree(); +} +void EditorInspector::register_text_enter(Node *p_line_edit) { + search_box = Object::cast_to<LineEdit>(p_line_edit); + if (search_box) + search_box->connect("text_changed", this, "_filter_changed"); +} + +void EditorInspector::_filter_changed(const String &p_text) { + + update_tree(); +} + +void EditorInspector::set_subsection_selectable(bool p_selectable) { +} + +void EditorInspector::set_property_selectable(bool p_selectable) { +} + +void EditorInspector::set_use_folding(bool p_enable) { + use_folding = p_enable; + update_tree(); +} + +void EditorInspector::collapse_all_folding() { + + for (List<EditorInspectorSection *>::Element *E = sections.front(); E; E = E->next()) { + E->get()->fold(); + } +} + +void EditorInspector::expand_all_folding() { + for (List<EditorInspectorSection *>::Element *E = sections.front(); E; E = E->next()) { + E->get()->unfold(); + } +} + +void EditorInspector::set_scroll_offset(int p_offset) { + set_v_scroll(p_offset); +} + +int EditorInspector::get_scroll_offset() const { + return get_v_scroll(); +} + +void EditorInspector::_edit_request_change(Object *p_object, const String &p_property) { + + if (object != p_object) //may be undoing/redoing for a non edited object, so ignore + return; + + if (changing) + return; + + if (p_property == String()) + update_tree_pending = true; + else { + pending.insert(p_property); + } +} + +void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field) { + + if (autoclear && editor_property_map.has(p_name)) { + for (List<EditorProperty *>::Element *E = editor_property_map[p_name].front(); E; E = E->next()) { + if (E->get()->is_checkable()) { + E->get()->set_checked(true); + } + } + } + + if (!undo_redo || Object::cast_to<ArrayPropertyEdit>(object) || Object::cast_to<DictionaryPropertyEdit>(object)) { //kind of hacky + + object->set(p_name, p_value); + if (p_refresh_all) + _edit_request_change(object, ""); + else + _edit_request_change(object, p_name); + + emit_signal(_prop_edited, p_name); + + } else if (Object::cast_to<MultiNodeEdit>(object)) { + + Object::cast_to<MultiNodeEdit>(object)->set_property_field(p_name, p_value, p_changed_field); + _edit_request_change(object, p_name); + emit_signal(_prop_edited, p_name); + } else { + + undo_redo->create_action(TTR("Set") + " " + p_name, UndoRedo::MERGE_ENDS); + undo_redo->add_do_property(object, p_name, p_value); + undo_redo->add_undo_property(object, p_name, object->get(p_name)); + + if (p_refresh_all) { + undo_redo->add_do_method(this, "_edit_request_change", object, ""); + undo_redo->add_undo_method(this, "_edit_request_change", object, ""); + } else { + + undo_redo->add_do_method(this, "_edit_request_change", object, p_name); + undo_redo->add_undo_method(this, "_edit_request_change", object, p_name); + } + + Resource *r = Object::cast_to<Resource>(object); + if (r) { + if (!r->is_edited() && String(p_name) != "resource/edited") { + undo_redo->add_do_method(r, "set_edited", true); + undo_redo->add_undo_method(r, "set_edited", false); + } + + if (String(p_name) == "resource_local_to_scene") { + bool prev = object->get(p_name); + bool next = p_value; + if (next) { + undo_redo->add_do_method(r, "setup_local_to_scene"); + } + if (prev) { + undo_redo->add_undo_method(r, "setup_local_to_scene"); + } + } + } + undo_redo->add_do_method(this, "emit_signal", _prop_edited, p_name); + undo_redo->add_undo_method(this, "emit_signal", _prop_edited, p_name); + changing++; + undo_redo->commit_action(); + changing--; + } + + if (editor_property_map.has(p_name)) { + for (List<EditorProperty *>::Element *E = editor_property_map[p_name].front(); E; E = E->next()) { + E->get()->update_reload_status(); + } + } +} + +void EditorInspector::_property_changed(const String &p_path, const Variant &p_value) { + + _edit_set(p_path, p_value, false, ""); +} + +void EditorInspector::_multiple_properties_changed(Vector<String> p_paths, Array p_values) { + + ERR_FAIL_COND(p_paths.size() == 0 || p_values.size() == 0); + ERR_FAIL_COND(p_paths.size() != p_values.size()); + String names; + for (int i = 0; i < p_paths.size(); i++) { + if (i > 0) + names += ","; + names += p_paths[i]; + } + undo_redo->create_action(TTR("Set Multiple:") + " " + names, UndoRedo::MERGE_ENDS); + for (int i = 0; i < p_paths.size(); i++) { + _edit_set(p_paths[i], p_values[i], false, ""); + } + changing++; + undo_redo->commit_action(); + changing--; +} + +void EditorInspector::_property_keyed(const String &p_path) { + + if (!object) + return; + + emit_signal("property_keyed", p_path, object->get(p_path), false); //second param is deprecated +} + +void EditorInspector::_property_checked(const String &p_path, bool p_checked) { + + if (!object) + return; + + //property checked + if (autoclear) { + + if (!p_checked) { + object->set(p_path, Variant()); + } else { + + Variant to_create; + List<PropertyInfo> pinfo; + object->get_property_list(&pinfo); + for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { + if (E->get().name == p_path) { + Variant::CallError ce; + to_create = Variant::construct(E->get().type, NULL, 0, ce); + break; + } + } + object->set(p_path, to_create); + } + + if (editor_property_map.has(p_path)) { + for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) { + E->get()->update_property(); + E->get()->update_reload_status(); + } + } + + } else { + emit_signal("property_toggled", p_path, p_checked); + } +} + +void EditorInspector::_property_selected(const String &p_path, int p_focusable) { + + property_selected = p_path; + property_focusable = p_focusable; + //deselect the others + for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) { + if (F->key() == property_selected) + continue; + for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) { + if (E->get()->is_selected()) + E->get()->deselect(); + } + } +} + +void EditorInspector::_object_id_selected(const String &p_path, ObjectID p_id) { + + emit_signal("object_id_selected", p_id); +} + +void EditorInspector::_resource_selected(const String &p_path, RES p_resource) { + emit_signal("resource_selected", p_resource, p_path); +} + +void EditorInspector::_node_removed(Node *p_node) { + + if (p_node == object) { + edit(NULL); + } +} + +void EditorInspector::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + + get_tree()->connect("node_removed", this, "_node_removed"); + add_style_override("bg", get_stylebox("bg", "Tree")); + } + if (p_what == NOTIFICATION_EXIT_TREE) { + + get_tree()->disconnect("node_removed", this, "_node_removed"); + edit(NULL); + } + + if (p_what == NOTIFICATION_PROCESS) { + + if (refresh_countdown > 0) { + refresh_countdown -= get_process_delta_time(); + if (refresh_countdown <= 0) { + for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) { + for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) { + E->get()->update_property(); + E->get()->update_reload_status(); + } + } + } + } + + changing++; + + if (update_tree_pending) { + + update_tree(); + update_tree_pending = false; + pending.clear(); + + } else { + + while (pending.size()) { + StringName prop = pending.front()->get(); + if (editor_property_map.has(prop)) { + for (List<EditorProperty *>::Element *E = editor_property_map[prop].front(); E; E = E->next()) { + E->get()->update_property(); + E->get()->update_reload_status(); + } + } + pending.erase(pending.front()); + } + } + + changing--; + } + + if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { + update_tree(); + } +} + +void EditorInspector::_changed_callback(Object *p_changed, const char *p_prop) { + //this is called when property change is notified via _change_notify() + _edit_request_change(p_changed, p_prop); +} + +void EditorInspector::_bind_methods() { + + ClassDB::bind_method("_multiple_properties_changed", &EditorInspector::_multiple_properties_changed); + ClassDB::bind_method("_property_changed", &EditorInspector::_property_changed); + ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change); + ClassDB::bind_method("_node_removed", &EditorInspector::_node_removed); + ClassDB::bind_method("_filter_changed", &EditorInspector::_filter_changed); + ClassDB::bind_method("_property_keyed", &EditorInspector::_property_keyed); + ClassDB::bind_method("_property_checked", &EditorInspector::_property_checked); + ClassDB::bind_method("_property_selected", &EditorInspector::_property_selected); + ClassDB::bind_method("_resource_selected", &EditorInspector::_resource_selected); + ClassDB::bind_method("_object_id_selected", &EditorInspector::_object_id_selected); + + ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property"))); + ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "res"), PropertyInfo(Variant::STRING, "prop"))); + ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::INT, "id"))); +} + +EditorInspector::EditorInspector() { + object = NULL; + undo_redo = NULL; + main_vbox = memnew(VBoxContainer); + main_vbox->set_h_size_flags(SIZE_EXPAND_FILL); + add_child(main_vbox); + main_vbox->set_name("pipirulo"); + set_h_scroll(false); + set_v_scroll(true); + + show_categories = false; + hide_script = true; + use_doc_hints = false; + capitalize_paths = false; + use_filter = false; + autoclear = false; + changing = 0; + use_folding = false; + update_all_pending = false; + update_tree_pending = false; + refresh_countdown = 0; + read_only = false; + search_box = NULL; + keying = false; + _prop_edited = "property_edited"; + set_process(true); + property_focusable = -1; +} diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h new file mode 100644 index 0000000000..410c76dbb6 --- /dev/null +++ b/editor/editor_inspector.h @@ -0,0 +1,313 @@ +/*************************************************************************/ +/* editor_inspector.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITOR_INSPECTOR_H +#define EDITOR_INSPECTOR_H + +#include "editor_data.h" +#include "scene/gui/scroll_container.h" + +class EditorProperty : public Container { + + GDCLASS(EditorProperty, Container) +public: + enum LabelLayout { + LABEL_LAYOUT_LEFT, + LABEL_LAYOUT_TOP, + }; + +private: + String label; + int text_size; + friend class EditorInspector; + Object *object; + StringName property; + + LabelLayout label_layout; + + int property_usage; + + bool read_only; + bool checkable; + bool checked; + bool draw_red; + bool keying; + + Rect2 keying_rect; + bool keying_hover; + Rect2 revert_rect; + bool revert_hover; + Rect2 check_rect; + bool check_hover; + + bool can_revert; + + bool _might_be_in_instance(); + bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage); + bool _is_instanced_node_with_original_property_different(); + bool _get_instanced_node_original_property(const StringName &p_prop, Variant &value); + void _focusable_focused(int p_index); + + bool selected; + int selected_focusable; + + Vector<Control *> focusables; + Control *label_reference; + +protected: + void _notification(int p_what); + static void _bind_methods(); + + void _gui_input(const Ref<InputEvent> &p_event); + +public: + virtual Size2 get_minimum_size() const; + + void set_label(const String &p_label); + String get_label() const; + + void set_read_only(bool p_read_only); + bool is_read_only() const; + + Object *get_edited_object(); + StringName get_edited_property(); + + virtual void update_property(); + void update_reload_status(); + + virtual bool use_keying_next() const; + + void set_checkable(bool p_checkable); + bool is_checkable() const; + + void set_checked(bool p_checked); + bool is_checked() const; + + void set_draw_red(bool p_draw_red); + bool is_draw_red() const; + + void set_keying(bool p_keying); + bool is_keying() const; + + void add_focusable(Control *p_control); + void select(int p_focusable = -1); + void deselect(); + bool is_selected() const; + + void set_label_reference(Control *p_control); + + virtual Variant get_drag_data(const Point2 &p_point); + + void set_label_layout(LabelLayout p_layout); + EditorProperty(); +}; + +class EditorInspectorPlugin : public Reference { + GDCLASS(EditorInspectorPlugin, Reference) + + friend class EditorInspector; + struct AddedEditor { + Control *property_editor; + Vector<String> properties; + String label; + }; + + List<AddedEditor> added_editors; + +protected: + static void _bind_methods(); + +public: + void add_custom_control(Control *control); + void add_property_editor(const String &p_for_property, Control *p_prop); + void add_property_editor_for_multiple_properties(const String &p_label, const Vector<String> &p_properties, Control *p_prop); + + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); + virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); + virtual void parse_end(); +}; + +class EditorInspectorCategory : public Control { + GDCLASS(EditorInspectorCategory, Control); + + friend class EditorInspector; + Ref<Texture> icon; + String label; + Color bg_color; + +protected: + void _notification(int p_what); + +public: + virtual Size2 get_minimum_size() const; + + EditorInspectorCategory(); +}; + +class EditorInspectorSection : public Container { + GDCLASS(EditorInspectorSection, Container); + + String label; + String section; + Object *object; + VBoxContainer *vbox; + Color bg_color; + bool foldable; + +protected: + void _notification(int p_what); + static void _bind_methods(); + void _gui_input(const Ref<InputEvent> &p_event); + +public: + virtual Size2 get_minimum_size() const; + + void setup(const String &p_section, const String &p_label, Object *p_object, const Color &p_bg_color, bool p_foldable); + VBoxContainer *get_vbox(); + void unfold(); + void fold(); + + Object *get_edited_object(); + + EditorInspectorSection(); +}; + +class EditorInspector : public ScrollContainer { + GDCLASS(EditorInspector, ScrollContainer); + + UndoRedo *undo_redo; + enum { + MAX_PLUGINS = 1024 + }; + static Ref<EditorInspectorPlugin> inspector_plugins[MAX_PLUGINS]; + static int inspector_plugin_count; + + VBoxContainer *main_vbox; + + //map use to cache the instanced editors + Map<StringName, List<EditorProperty *> > editor_property_map; + List<EditorInspectorSection *> sections; + Set<StringName> pending; + + void _clear(); + Object *object; + + // + + LineEdit *search_box; + bool show_categories; + bool hide_script; + bool use_doc_hints; + bool capitalize_paths; + bool use_filter; + bool autoclear; + bool use_folding; + int changing; + bool update_all_pending; + bool read_only; + bool keying; + + int refresh_countdown; + bool update_tree_pending; + StringName _prop_edited; + StringName property_selected; + int property_focusable; + + Map<StringName, Map<StringName, String> > descr_cache; + Map<StringName, String> class_descr_cache; + + void _edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field); + + void _property_changed(const String &p_path, const Variant &p_value); + void _multiple_properties_changed(Vector<String> p_paths, Array p_values); + void _property_keyed(const String &p_path); + void _property_checked(const String &p_path, bool p_checked); + + void _resource_selected(const String &p_path, RES p_resource); + void _property_selected(const String &p_path, int p_focusable); + void _object_id_selected(const String &p_path, ObjectID p_id); + + void _node_removed(Node *p_node); + + void _changed_callback(Object *p_changed, const char *p_prop); + void _edit_request_change(Object *p_changed, const String &p_prop); + + void _filter_changed(const String &p_text); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + static void add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin); + static void remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin); + static void cleanup_plugins(); + + void set_undo_redo(UndoRedo *p_undo_redo); + + String get_selected_path() const; + + void update_tree(); + void update_property(const String &p_prop); + + void refresh(); + + void edit(Object *p_object); + + void set_keying(bool p_active); + void set_read_only(bool p_read_only); + + bool is_capitalize_paths_enabled() const; + void set_enable_capitalize_paths(bool p_capitalize); + void set_autoclear(bool p_enable); + + void set_show_categories(bool p_show); + void set_use_doc_hints(bool p_enable); + void set_hide_script(bool p_hide); + + void set_use_filter(bool p_use); + void register_text_enter(Node *p_line_edit); + + void set_subsection_selectable(bool p_selectable); + void set_property_selectable(bool p_selectable); + + void set_use_folding(bool p_enable); + + void collapse_all_folding(); + void expand_all_folding(); + + void set_scroll_offset(int p_offset); + int get_scroll_offset() const; + + EditorInspector(); +}; + +#endif // INSPECTOR_H diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 3f0a09cfd9..49f70e3215 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -56,6 +56,7 @@ #include "editor/editor_file_system.h" #include "editor/editor_help.h" #include "editor/editor_initialize_ssl.h" +#include "editor/editor_properties.h" #include "editor/editor_settings.h" #include "editor/editor_themes.h" #include "editor/import/editor_import_collada.h" @@ -548,8 +549,8 @@ void EditorNode::_vp_resized() { void EditorNode::_node_renamed() { - if (property_editor) - property_editor->update_tree(); + if (inspector) + inspector->update_tree(); } void EditorNode::_editor_select_next() { @@ -1351,7 +1352,7 @@ void EditorNode::_dialog_action(String p_file) { void EditorNode::push_item(Object *p_object, const String &p_property) { if (!p_object) { - property_editor->edit(NULL); + inspector->edit(NULL); node_dock->set_node(NULL); scene_tree_dock->set_selected(NULL); return; @@ -1444,12 +1445,12 @@ void EditorNode::_property_editor_back() { void EditorNode::_menu_collapseall() { - property_editor->collapse_all_folding(); + inspector->collapse_all_folding(); } void EditorNode::_menu_expandall() { - property_editor->expand_all_folding(); + inspector->expand_all_folding(); } void EditorNode::_save_default_environment() { @@ -1515,7 +1516,7 @@ void EditorNode::_edit_current() { if (!current_obj) { scene_tree_dock->set_selected(NULL); - property_editor->edit(NULL); + inspector->edit(NULL); node_dock->set_node(NULL); object_menu->set_disabled(true); @@ -1536,7 +1537,7 @@ void EditorNode::_edit_current() { Resource *current_res = Object::cast_to<Resource>(current_obj); ERR_FAIL_COND(!current_res); scene_tree_dock->set_selected(NULL); - property_editor->edit(current_res); + inspector->edit(current_res); node_dock->set_node(NULL); object_menu->set_disabled(false); EditorNode::get_singleton()->get_import_dock()->set_edit_path(current_res->get_path()); @@ -1561,7 +1562,7 @@ void EditorNode::_edit_current() { Node *current_node = Object::cast_to<Node>(current_obj); ERR_FAIL_COND(!current_node); - property_editor->edit(current_node); + inspector->edit(current_node); if (current_node->is_inside_tree()) { node_dock->set_node(current_node); scene_tree_dock->set_selected(current_node); @@ -1585,7 +1586,7 @@ void EditorNode::_edit_current() { capitalize = false; } - property_editor->edit(current_obj); + inspector->edit(current_obj); node_dock->set_node(NULL); } @@ -1594,8 +1595,8 @@ void EditorNode::_edit_current() { property_editable_warning_dialog->set_text(editable_warning); } - if (property_editor->is_capitalize_paths_enabled() != capitalize) { - property_editor->set_enable_capitalize_paths(capitalize); + if (inspector->is_capitalize_paths_enabled() != capitalize) { + inspector->set_enable_capitalize_paths(capitalize); } /* Take care of PLUGIN EDITOR */ @@ -2939,7 +2940,7 @@ Dictionary EditorNode::_get_main_scene_state() { Dictionary state; state["main_tab"] = _get_current_main_editor(); state["scene_tree_offset"] = scene_tree_dock->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_value(); - state["property_edit_offset"] = get_property_editor()->get_scene_tree()->get_vscroll_bar()->get_value(); + state["property_edit_offset"] = get_inspector()->get_scroll_offset(); state["saved_version"] = saved_version; state["node_filter"] = scene_tree_dock->get_filter(); return state; @@ -2985,7 +2986,7 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) { if (p_state.has("scene_tree_offset")) scene_tree_dock->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->set_value(p_state["scene_tree_offset"]); if (p_state.has("property_edit_offset")) - get_property_editor()->get_scene_tree()->get_vscroll_bar()->set_value(p_state["property_edit_offset"]); + get_inspector()->set_scroll_offset(p_state["property_edit_offset"]); if (p_state.has("node_filter")) scene_tree_dock->set_filter(p_state["node_filter"]); @@ -3278,9 +3279,7 @@ void EditorNode::update_keying() { } } - property_editor->set_keying(valid); - - AnimationPlayerEditor::singleton->get_key_editor()->update_keying(); + inspector->set_keying(valid); } void EditorNode::_close_messages() { @@ -3425,6 +3424,9 @@ void EditorNode::register_editor_types() { ClassDB::register_class<EditorExportPlugin>(); ClassDB::register_class<EditorResourceConversionPlugin>(); ClassDB::register_class<EditorSceneImporter>(); + ClassDB::register_class<EditorInspector>(); + ClassDB::register_class<EditorInspectorPlugin>(); + ClassDB::register_class<EditorProperty>(); // FIXME: Is this stuff obsolete, or should it be ported to new APIs? ClassDB::register_class<EditorScenePostImport>(); @@ -4236,7 +4238,7 @@ void EditorNode::_scene_tab_changed(int p_tab) { void EditorNode::_toggle_search_bar(bool p_pressed) { - property_editor->set_use_filter(p_pressed); + inspector->set_use_filter(p_pressed); if (p_pressed) { @@ -4255,7 +4257,7 @@ void EditorNode::_clear_search_box() { return; search_box->clear(); - property_editor->update_tree(); + inspector->update_tree(); } ToolButton *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) { @@ -5007,6 +5009,12 @@ EditorNode::EditorNode() { ResourceFormatImporter::get_singleton()->add_importer(import_bitmap); } + { + Ref<EditorInspectorDefaultPlugin> eidp; + eidp.instance(); + EditorInspector::add_inspector_plugin(eidp); + } + _pvrtc_register_compressors(); editor_selection = memnew(EditorSelection); @@ -5665,21 +5673,21 @@ EditorNode::EditorNode() { property_editable_warning->hide(); property_editable_warning->connect("pressed", this, "_property_editable_warning_pressed"); - property_editor = memnew(PropertyEditor); - property_editor->set_autoclear(true); - property_editor->set_show_categories(true); - property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); - property_editor->set_use_doc_hints(true); - property_editor->set_hide_script(false); - property_editor->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true))); - property_editor->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false))); + inspector = memnew(EditorInspector); + inspector->set_autoclear(true); + inspector->set_show_categories(true); + inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); + inspector->set_use_doc_hints(true); + inspector->set_hide_script(false); + inspector->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true))); + inspector->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false))); - property_editor->hide_top_label(); - property_editor->register_text_enter(search_box); + // inspector->hide_top_label(); + inspector->register_text_enter(search_box); Button *property_editable_warning; - prop_editor_base->add_child(property_editor); - property_editor->set_undo_redo(&editor_data.get_undo_redo()); + prop_editor_base->add_child(inspector); + inspector->set_undo_redo(&editor_data.get_undo_redo()); import_dock = memnew(ImportDock); dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(import_dock); @@ -5815,8 +5823,8 @@ EditorNode::EditorNode() { file->connect("file_selected", this, "_dialog_action"); file_templates->connect("file_selected", this, "_dialog_action"); - property_editor->connect("resource_selected", this, "_resource_selected"); - property_editor->connect("property_keyed", this, "_property_keyed"); + inspector->connect("resource_selected", this, "_resource_selected"); + inspector->connect("property_keyed", this, "_property_keyed"); //plugin stuff @@ -6039,6 +6047,8 @@ EditorNode::EditorNode() { EditorNode::~EditorNode() { + EditorInspector::cleanup_plugins(); + remove_print_handler(&print_handler); memdelete(EditorHelp::get_doc_data()); memdelete(editor_selection); diff --git a/editor/editor_node.h b/editor/editor_node.h index f774fa0a2e..86b85663ab 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -37,6 +37,7 @@ #include "editor/editor_about.h" #include "editor/editor_data.h" #include "editor/editor_export.h" +#include "editor/editor_inspector.h" #include "editor/editor_log.h" #include "editor/editor_name_dialog.h" #include "editor/editor_path.h" @@ -80,7 +81,6 @@ #include "scene/gui/tool_button.h" #include "scene/gui/tree.h" #include "scene/gui/viewport_container.h" - /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -267,7 +267,7 @@ private: Button *property_back; Button *property_forward; SceneTreeDock *scene_tree_dock; - PropertyEditor *property_editor; + EditorInspector *inspector; Button *property_editable_warning; AcceptDialog *property_editable_warning_dialog; void _property_editable_warning_pressed(); @@ -640,7 +640,7 @@ public: EditorPluginList *get_editor_plugins_over() { return editor_plugins_over; } EditorPluginList *get_editor_plugins_force_over() { return editor_plugins_force_over; } EditorPluginList *get_editor_plugins_force_input_forwarding() { return editor_plugins_force_input_forwarding; } - PropertyEditor *get_property_editor() { return property_editor; } + EditorInspector *get_inspector() { return inspector; } VBoxContainer *get_property_editor_vb() { return prop_editor_vb; } ProjectSettingsEditor *get_project_settings() { return project_settings; } diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp new file mode 100644 index 0000000000..f3397d7980 --- /dev/null +++ b/editor/editor_properties.cpp @@ -0,0 +1,2469 @@ +/*************************************************************************/ +/* editor_properties.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_properties.h" +#include "editor/editor_resource_preview.h" +#include "editor_node.h" +#include "scene/main/viewport.h" +///////////////////// TEXT ///////////////////////// +void EditorPropertyText::_text_changed(const String &p_string) { + if (updating) + return; + + emit_signal("property_changed", get_edited_property(), p_string); +} + +void EditorPropertyText::update_property() { + String s = get_edited_object()->get(get_edited_property()); + updating = true; + text->set_text(s); + text->set_editable(!is_read_only()); + updating = false; +} + +void EditorPropertyText::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_text_changed", "txt"), &EditorPropertyText::_text_changed); +} + +EditorPropertyText::EditorPropertyText() { + text = memnew(LineEdit); + add_child(text); + add_focusable(text); + text->connect("text_changed", this, "_text_changed"); + updating = false; +} + +///////////////////// MULTILINE TEXT ///////////////////////// + +void EditorPropertyMultilineText::_big_text_changed() { + text->set_text(big_text->get_text()); + emit_signal("property_changed", get_edited_property(), big_text->get_text()); +} + +void EditorPropertyMultilineText::_text_changed() { + + emit_signal("property_changed", get_edited_property(), text->get_text()); +} + +void EditorPropertyMultilineText::_open_big_text() { + + if (!big_text_dialog) { + big_text = memnew(TextEdit); + big_text->connect("text_changed", this, "_big_text_changed"); + big_text_dialog = memnew(AcceptDialog); + big_text_dialog->add_child(big_text); + big_text_dialog->set_title("Edit Text:"); + add_child(big_text_dialog); + } + + big_text->set_text(text->get_text()); + big_text_dialog->popup_centered_ratio(); +} + +void EditorPropertyMultilineText::update_property() { + String t = get_edited_object()->get(get_edited_property()); + text->set_text(t); + if (big_text && big_text->is_visible_in_tree()) { + big_text->set_text(t); + } +} + +void EditorPropertyMultilineText::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_ENTER_TREE: { + Ref<Texture> df = get_icon("DistractionFree", "EditorIcons"); + open_big_text->set_icon(df); + Ref<Font> font = get_font("font", "Label"); + text->set_custom_minimum_size(Vector2(0, font->get_height() * 6)); + + } break; + } +} + +void EditorPropertyMultilineText::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_text_changed"), &EditorPropertyMultilineText::_text_changed); + ClassDB::bind_method(D_METHOD("_big_text_changed"), &EditorPropertyMultilineText::_big_text_changed); + ClassDB::bind_method(D_METHOD("_open_big_text"), &EditorPropertyMultilineText::_open_big_text); +} + +EditorPropertyMultilineText::EditorPropertyMultilineText() { + HBoxContainer *hb = memnew(HBoxContainer); + set_label_layout(LABEL_LAYOUT_TOP); + add_child(hb); + text = memnew(TextEdit); + text->connect("text_changed", this, "_text_changed"); + add_focusable(text); + hb->add_child(text); + text->set_h_size_flags(SIZE_EXPAND_FILL); + open_big_text = memnew(ToolButton); + open_big_text->connect("pressed", this, "_open_big_text"); + hb->add_child(open_big_text); + big_text_dialog = NULL; + big_text = NULL; +} + +///////////////////// TEXT ENUM ///////////////////////// + +void EditorPropertyTextEnum::_option_selected(int p_which) { + + emit_signal("property_changed", get_edited_property(), options->get_item_text(p_which)); +} + +void EditorPropertyTextEnum::update_property() { + + String which = get_edited_object()->get(get_edited_property()); + for (int i = 0; i < options->get_item_count(); i++) { + String t = options->get_item_text(i); + if (t == which) { + options->select(i); + return; + } + } +} + +void EditorPropertyTextEnum::setup(const Vector<String> &p_options) { + for (int i = 0; i < p_options.size(); i++) { + options->add_item(p_options[i], i); + } +} + +void EditorPropertyTextEnum::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_option_selected"), &EditorPropertyTextEnum::_option_selected); +} + +EditorPropertyTextEnum::EditorPropertyTextEnum() { + options = memnew(OptionButton); + options->set_clip_text(true); + add_child(options); + add_focusable(options); + options->connect("item_selected", this, "_option_selected"); +} +///////////////////// PATH ///////////////////////// + +void EditorPropertyPath::_path_selected(const String &p_path) { + + emit_signal("property_changed", get_edited_property(), p_path); + update_property(); +} +void EditorPropertyPath::_path_pressed() { + + if (!dialog) { + dialog = memnew(EditorFileDialog); + dialog->connect("file_selected", this, "_path_selected"); + dialog->connect("dir_selected", this, "_path_selected"); + add_child(dialog); + } + + String full_path = get_edited_object()->get(get_edited_property()); + + dialog->clear_filters(); + + if (global) { + dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + } else { + dialog->set_access(EditorFileDialog::ACCESS_RESOURCES); + } + + if (folder) { + dialog->set_mode(EditorFileDialog::MODE_OPEN_DIR); + dialog->set_current_dir(full_path); + } else { + dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + for (int i = 0; i < extensions.size(); i++) { + String e = extensions[i].strip_edges(); + if (e != String()) { + dialog->add_filter(extensions[i].strip_edges()); + } + } + dialog->set_current_path(full_path); + } + + dialog->popup_centered_ratio(); +} + +void EditorPropertyPath::update_property() { + + String full_path = get_edited_object()->get(get_edited_property()); + path->set_text(full_path); + path->set_tooltip(full_path); +} + +void EditorPropertyPath::setup(const Vector<String> &p_extensions, bool p_folder, bool p_global) { + + extensions = p_extensions; + folder = p_folder; + global = p_global; +} + +void EditorPropertyPath::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_path_pressed"), &EditorPropertyPath::_path_pressed); + ClassDB::bind_method(D_METHOD("_path_selected"), &EditorPropertyPath::_path_selected); +} + +EditorPropertyPath::EditorPropertyPath() { + path = memnew(Button); + path->set_clip_text(true); + add_child(path); + add_focusable(path); + dialog = NULL; + path->connect("pressed", this, "_path_pressed"); + folder = false; + global = false; +} + +///////////////////// MEMBER ///////////////////////// + +void EditorPropertyMember::_property_selected(const String &p_selected) { + + emit_signal("property_changed", get_edited_property(), p_selected); + update_property(); +} + +void EditorPropertyMember::_property_select() { + + if (!selector) { + selector = memnew(PropertySelector); + selector->connect("selected", this, "_property_selected"); + add_child(selector); + } + + String current = get_edited_object()->get(get_edited_property()); + + if (hint == MEMBER_METHOD_OF_VARIANT_TYPE) { + + Variant::Type type = Variant::NIL; + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (hint_text == Variant::get_type_name(Variant::Type(i))) { + type = Variant::Type(i); + } + } + if (type) + selector->select_method_from_basic_type(type, current); + + } else if (hint == MEMBER_METHOD_OF_BASE_TYPE) { + + selector->select_method_from_base_type(hint_text, current); + + } else if (hint == MEMBER_METHOD_OF_INSTANCE) { + + Object *instance = ObjectDB::get_instance(hint_text.to_int64()); + if (instance) + selector->select_method_from_instance(instance, current); + + } else if (hint == MEMBER_METHOD_OF_SCRIPT) { + + Object *obj = ObjectDB::get_instance(hint_text.to_int64()); + if (Object::cast_to<Script>(obj)) { + selector->select_method_from_script(Object::cast_to<Script>(obj), current); + } + + } else if (hint == MEMBER_PROPERTY_OF_VARIANT_TYPE) { + + Variant::Type type = Variant::NIL; + String tname = hint_text; + if (tname.find(".") != -1) + tname = tname.get_slice(".", 0); + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (tname == Variant::get_type_name(Variant::Type(i))) { + type = Variant::Type(Variant::Type(i)); + } + } + + if (type != Variant::NIL) + selector->select_property_from_basic_type(type, current); + + } else if (hint == MEMBER_PROPERTY_OF_BASE_TYPE) { + + selector->select_property_from_base_type(hint_text, current); + + } else if (hint == MEMBER_PROPERTY_OF_INSTANCE) { + + Object *instance = ObjectDB::get_instance(hint_text.to_int64()); + if (instance) + selector->select_property_from_instance(instance, current); + + } else if (hint == MEMBER_PROPERTY_OF_SCRIPT) { + + Object *obj = ObjectDB::get_instance(hint_text.to_int64()); + if (Object::cast_to<Script>(obj)) { + selector->select_property_from_script(Object::cast_to<Script>(obj), current); + } + } +} + +void EditorPropertyMember::setup(Type p_hint, const String &p_hint_text) { + hint = p_hint; + hint_text = p_hint_text; +} + +void EditorPropertyMember::update_property() { + + String full_path = get_edited_object()->get(get_edited_property()); + property->set_text(full_path); +} + +void EditorPropertyMember::_bind_methods() { + ClassDB::bind_method(D_METHOD("_property_selected"), &EditorPropertyMember::_property_selected); + ClassDB::bind_method(D_METHOD("_property_select"), &EditorPropertyMember::_property_select); +} + +EditorPropertyMember::EditorPropertyMember() { + selector = NULL; + property = memnew(Button); + property->set_clip_text(true); + add_child(property); + add_focusable(property); + property->connect("pressed", this, "_property_select"); +} + +///////////////////// CHECK ///////////////////////// +void EditorPropertyCheck::_checkbox_pressed() { + + emit_signal("property_changed", get_edited_property(), checkbox->is_pressed()); +} + +void EditorPropertyCheck::update_property() { + bool c = get_edited_object()->get(get_edited_property()); + checkbox->set_pressed(c); + checkbox->set_disabled(is_read_only()); +} + +void EditorPropertyCheck::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_checkbox_pressed"), &EditorPropertyCheck::_checkbox_pressed); +} + +EditorPropertyCheck::EditorPropertyCheck() { + checkbox = memnew(CheckBox); + checkbox->set_text(TTR("On")); + add_child(checkbox); + add_focusable(checkbox); + checkbox->connect("pressed", this, "_checkbox_pressed"); +} + +///////////////////// ENUM ///////////////////////// + +void EditorPropertyEnum::_option_selected(int p_which) { + + emit_signal("property_changed", get_edited_property(), p_which); +} + +void EditorPropertyEnum::update_property() { + + int which = get_edited_object()->get(get_edited_property()); + options->select(which); +} + +void EditorPropertyEnum::setup(const Vector<String> &p_options) { + for (int i = 0; i < p_options.size(); i++) { + options->add_item(p_options[i], i); + } +} + +void EditorPropertyEnum::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_option_selected"), &EditorPropertyEnum::_option_selected); +} + +EditorPropertyEnum::EditorPropertyEnum() { + options = memnew(OptionButton); + options->set_clip_text(true); + add_child(options); + add_focusable(options); + options->connect("item_selected", this, "_option_selected"); +} + +///////////////////// FLAGS ///////////////////////// + +void EditorPropertyFlags::_flag_toggled() { + + uint32_t value = 0; + for (int i = 0; i < flags.size(); i++) { + if (flags[i]->is_pressed()) { + uint32_t val = 1; + val <<= flag_indices[i]; + value |= val; + } + } + + emit_signal("property_changed", get_edited_property(), value); +} + +void EditorPropertyFlags::update_property() { + + uint32_t value = get_edited_object()->get(get_edited_property()); + + for (int i = 0; i < flags.size(); i++) { + uint32_t val = 1; + val <<= flag_indices[i]; + if (value & val) { + + flags[i]->set_pressed(true); + } else { + flags[i]->set_pressed(false); + } + } +} + +void EditorPropertyFlags::setup(const Vector<String> &p_options) { + ERR_FAIL_COND(flags.size()); + + bool first = true; + for (int i = 0; i < p_options.size(); i++) { + String option = p_options[i].strip_edges(); + if (option != "") { + CheckBox *cb = memnew(CheckBox); + cb->set_text(option); + cb->set_clip_text(true); + cb->connect("pressed", this, "_flag_toggled"); + add_focusable(cb); + vbox->add_child(cb); + flags.push_back(cb); + flag_indices.push_back(i); + if (first) { + set_label_reference(cb); + first = false; + } + } + } +} + +void EditorPropertyFlags::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_flag_toggled"), &EditorPropertyFlags::_flag_toggled); +} + +EditorPropertyFlags::EditorPropertyFlags() { + + vbox = memnew(VBoxContainer); + add_child(vbox); +} + +///////////////////// LAYERS ///////////////////////// + +class EditorPropertyLayersGrid : public Control { + GDCLASS(EditorPropertyLayersGrid, Control) +public: + uint32_t value; + Vector<Rect2> flag_rects; + Vector<String> names; + + virtual Size2 get_minimum_size() const { + Ref<Font> font = get_font("font", "Label"); + return Vector2(0, font->get_height() * 2); + } + + virtual String get_tooltip(const Point2 &p_pos) const { + for (int i = 0; i < flag_rects.size(); i++) { + if (flag_rects[i].has_point(p_pos) && i < names.size()) { + return names[i]; + } + } + return String(); + } + void _gui_input(const Ref<InputEvent> &p_ev) { + Ref<InputEventMouseButton> mb = p_ev; + if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { + for (int i = 0; i < flag_rects.size(); i++) { + if (flag_rects[i].has_point(mb->get_position())) { + //toggle + if (value & (1 << i)) { + value &= ~(1 << i); + } else { + value |= (1 << i); + } + emit_signal("flag_changed", value); + update(); + } + } + } + } + + void _notification(int p_what) { + if (p_what == NOTIFICATION_DRAW) { + + Rect2 rect; + rect.size = get_size(); + flag_rects.clear(); + + int bsize = (rect.size.height * 80 / 100) / 2; + + int h = bsize * 2 + 1; + int vofs = (rect.size.height - h) / 2; + + for (int i = 0; i < 2; i++) { + + Point2 ofs(4, vofs); + if (i == 1) + ofs.y += bsize + 1; + + ofs += rect.position; + for (int j = 0; j < 10; j++) { + + Point2 o = ofs + Point2(j * (bsize + 1), 0); + if (j >= 5) + o.x += 1; + + uint32_t idx = i * 10 + j; + bool on = value & (1 << idx); + Rect2 rect = Rect2(o, Size2(bsize, bsize)); + draw_rect(rect, Color(0, 0, 0, on ? 0.8 : 0.3)); + flag_rects.push_back(rect); + } + } + } + } + + void set_flag(uint32_t p_flag) { + value = p_flag; + update(); + } + + static void _bind_methods() { + + ClassDB::bind_method(D_METHOD("_gui_input"), &EditorPropertyLayersGrid::_gui_input); + ADD_SIGNAL(MethodInfo("flag_changed", PropertyInfo(Variant::INT, "flag"))); + } + + EditorPropertyLayersGrid() { + value = 0; + } +}; +void EditorPropertyLayers::_grid_changed(uint32_t p_grid) { + + emit_signal("property_changed", get_edited_property(), p_grid); +} + +void EditorPropertyLayers::update_property() { + + uint32_t value = get_edited_object()->get(get_edited_property()); + + grid->set_flag(value); +} + +void EditorPropertyLayers::setup(LayerType p_layer_type) { + + String basename; + switch (p_layer_type) { + case LAYER_RENDER_2D: + basename = "layer_names/2d_render"; + break; + case LAYER_PHYSICS_2D: + basename = "layer_names/2d_physics"; + break; + case LAYER_RENDER_3D: + basename = "layer_names/3d_render"; + break; + case LAYER_PHYSICS_3D: + basename = "layer_names/3d_physics"; + break; + } + + Vector<String> names; + for (int i = 0; i < 20; i++) { + String name; + + if (ProjectSettings::get_singleton()->has_setting(basename + "/layer_" + itos(i + 1))) { + name = ProjectSettings::get_singleton()->get(basename + "/layer_" + itos(i + 1)); + } + + if (name == "") { + name = "Layer " + itos(i + 1); + } + + names.push_back(name); + } + + grid->names = names; +} + +void EditorPropertyLayers::_button_pressed() { + + layers->clear(); + for (int i = 0; i < 20; i++) { + if (i == 5 || i == 10 || i == 15) { + layers->add_separator(); + } + layers->add_check_item(grid->names[i], i); + int idx = layers->get_item_index(i); + layers->set_item_checked(idx, grid->value & (1 << i)); + } + + Rect2 gp = button->get_global_rect(); + Vector2 popup_pos = gp.position - Vector2(layers->get_combined_minimum_size().x, 0); + layers->set_global_position(popup_pos); + layers->popup(); +} + +void EditorPropertyLayers::_menu_pressed(int p_menu) { + if (grid->value & (1 << p_menu)) { + grid->value &= ~(1 << p_menu); + } else { + grid->value |= (1 << p_menu); + } + grid->update(); + _grid_changed(grid->value); +} + +void EditorPropertyLayers::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_grid_changed"), &EditorPropertyLayers::_grid_changed); + ClassDB::bind_method(D_METHOD("_button_pressed"), &EditorPropertyLayers::_button_pressed); + ClassDB::bind_method(D_METHOD("_menu_pressed"), &EditorPropertyLayers::_menu_pressed); +} + +EditorPropertyLayers::EditorPropertyLayers() { + + HBoxContainer *hb = memnew(HBoxContainer); + add_child(hb); + grid = memnew(EditorPropertyLayersGrid); + grid->connect("flag_changed", this, "_grid_changed"); + grid->set_h_size_flags(SIZE_EXPAND_FILL); + hb->add_child(grid); + button = memnew(Button); + button->set_text(".."); + button->connect("pressed", this, "_button_pressed"); + hb->add_child(button); + set_label_layout(LABEL_LAYOUT_TOP); + layers = memnew(PopupMenu); + add_child(layers); + layers->connect("id_pressed", this, "_menu_pressed"); +} +///////////////////// INT ///////////////////////// + +void EditorPropertyInteger::_value_changed(double val) { + if (setting) + return; + emit_signal("property_changed", get_edited_property(), int(val)); +} + +void EditorPropertyInteger::update_property() { + int val = get_edited_object()->get(get_edited_property()); + setting = true; + spin->set_value(val); + setting = false; +} + +void EditorPropertyInteger::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyInteger::_value_changed); +} + +void EditorPropertyInteger::setup(int p_min, int p_max, bool p_allow_greater, bool p_allow_lesser) { + spin->set_min(p_min); + spin->set_max(p_max); + spin->set_step(1); + spin->set_allow_greater(p_allow_greater); + spin->set_allow_lesser(p_allow_lesser); +} + +EditorPropertyInteger::EditorPropertyInteger() { + spin = memnew(EditorSpinSlider); + add_child(spin); + add_focusable(spin); + spin->connect("value_changed", this, "_value_changed"); + setting = false; +} + +///////////////////// OBJECT ID ///////////////////////// + +void EditorPropertyObjectID::_edit_pressed() { + + emit_signal("object_id_selected", get_edited_property(), get_edited_object()->get(get_edited_property())); +} + +void EditorPropertyObjectID::update_property() { + String type = base_type; + if (type == "") + type = "Object"; + + String icon_type = type; + if (has_icon(icon_type, "EditorIcons")) { + type = icon_type; + } else { + type = "Object"; + } + + ObjectID id = get_edited_object()->get(get_edited_property()); + if (id != 0) { + edit->set_text(type + " ID: " + itos(id)); + edit->set_disabled(false); + edit->set_icon(get_icon(icon_type, "EditorIcons")); + } else { + edit->set_text(TTR("[Empty]")); + edit->set_disabled(true); + edit->set_icon(Ref<Texture>()); + } +} + +void EditorPropertyObjectID::setup(const String &p_base_type) { + base_type = p_base_type; +} + +void EditorPropertyObjectID::_bind_methods() { + ClassDB::bind_method(D_METHOD("_edit_pressed"), &EditorPropertyObjectID::_edit_pressed); +} + +EditorPropertyObjectID::EditorPropertyObjectID() { + edit = memnew(Button); + add_child(edit); + add_focusable(edit); + edit->connect("pressed", this, "_edit_pressed"); +} + +///////////////////// FLOAT ///////////////////////// + +void EditorPropertyFloat::_value_changed(double val) { + if (setting) + return; + + emit_signal("property_changed", get_edited_property(), val); +} + +void EditorPropertyFloat::update_property() { + double val = get_edited_object()->get(get_edited_property()); + setting = true; + spin->set_value(val); + setting = false; +} + +void EditorPropertyFloat::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyFloat::_value_changed); +} + +void EditorPropertyFloat::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range, bool p_greater, bool p_lesser) { + + spin->set_min(p_min); + spin->set_max(p_max); + spin->set_step(p_step); + spin->set_hide_slider(p_no_slider); + spin->set_exp_ratio(p_exp_range); + spin->set_allow_greater(p_greater); + spin->set_allow_lesser(p_lesser); +} + +EditorPropertyFloat::EditorPropertyFloat() { + spin = memnew(EditorSpinSlider); + add_child(spin); + add_focusable(spin); + spin->connect("value_changed", this, "_value_changed"); + setting = false; +} + +///////////////////// EASING ///////////////////////// + +void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) { + + Ref<InputEventMouseMotion> mm = p_ev; + + if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) { + + float rel = mm->get_relative().x; + if (rel == 0) + return; + + if (flip) + rel = -rel; + + float val = get_edited_object()->get(get_edited_property()); + if (val == 0) + return; + bool sg = val < 0; + val = Math::absf(val); + + val = Math::log(val) / Math::log((float)2.0); + //logspace + val += rel * 0.05; + + val = Math::pow(2.0f, val); + if (sg) + val = -val; + + emit_signal("property_changed", get_edited_property(), val); + easing_draw->update(); + } +} + +void EditorPropertyEasing::_draw_easing() { + + RID ci = easing_draw->get_canvas_item(); + + Size2 s = easing_draw->get_size(); + Rect2 r(Point2(), s); + r = r.grow(3); + get_stylebox("normal", "LineEdit")->draw(ci, r); + + int points = 48; + + float prev = 1.0; + float exp = get_edited_object()->get(get_edited_property()); + + Ref<Font> f = get_font("font", "Label"); + Color color = get_color("font_color", "Label"); + + for (int i = 1; i <= points; i++) { + + float ifl = i / float(points); + float iflp = (i - 1) / float(points); + + float h = 1.0 - Math::ease(ifl, exp); + + if (flip) { + ifl = 1.0 - ifl; + iflp = 1.0 - iflp; + } + + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(iflp * s.width, prev * s.height), Point2(ifl * s.width, h * s.height), color); + prev = h; + } + + f->draw(ci, Point2(10, 10 + f->get_ascent()), String::num(exp, 2), color); +} + +void EditorPropertyEasing::update_property() { + easing_draw->update(); +} + +void EditorPropertyEasing::_set_preset(float p_val) { + emit_signal("property_changed", get_edited_property(), p_val); + easing_draw->update(); +} + +void EditorPropertyEasing::setup(bool p_full, bool p_flip) { + + flip = p_flip; + if (p_full) { + HBoxContainer *hb2 = memnew(HBoxContainer); + vb->add_child(hb2); + button_out_in = memnew(ToolButton); + button_out_in->set_tooltip(TTR("Out-In")); + button_out_in->set_h_size_flags(SIZE_EXPAND_FILL); + button_out_in->connect("pressed", this, "_set_preset", varray(-0.5)); + hb2->add_child(button_out_in); + + button_in_out = memnew(ToolButton); + button_in_out->set_tooltip(TTR("In")); + button_in_out->set_h_size_flags(SIZE_EXPAND_FILL); + button_in_out->connect("pressed", this, "_set_preset", varray(-2)); + hb2->add_child(button_in_out); + } +} + +void EditorPropertyEasing::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_ENTER_TREE: { + easing_draw->set_custom_minimum_size(Size2(0, get_font("font", "Label")->get_height() * 2)); + button_linear->set_icon(get_icon("CurveLinear", "EditorIcons")); + button_out->set_icon(get_icon("CurveOut", "EditorIcons")); + button_in->set_icon(get_icon("CurveIn", "EditorIcons")); + button_constant->set_icon(get_icon("CurveConstant", "EditorIcons")); + if (button_out_in) + button_out_in->set_icon(get_icon("CurveOutIn", "EditorIcons")); + if (button_in_out) + button_in_out->set_icon(get_icon("CurveInOut", "EditorIcons")); + } break; + } +} + +void EditorPropertyEasing::_bind_methods() { + + ClassDB::bind_method("_draw_easing", &EditorPropertyEasing::_draw_easing); + ClassDB::bind_method("_drag_easing", &EditorPropertyEasing::_drag_easing); + ClassDB::bind_method("_set_preset", &EditorPropertyEasing::_set_preset); +} + +EditorPropertyEasing::EditorPropertyEasing() { + + vb = memnew(VBoxContainer); + add_child(vb); + HBoxContainer *hb = memnew(HBoxContainer); + set_label_reference(hb); + + vb->add_child(hb); + + button_linear = memnew(ToolButton); + button_linear->set_tooltip(TTR("Linear")); + button_linear->set_h_size_flags(SIZE_EXPAND_FILL); + button_linear->connect("pressed", this, "_set_preset", varray(1)); + hb->add_child(button_linear); + + button_constant = memnew(ToolButton); + button_constant->set_tooltip(TTR("Linear")); + button_constant->set_h_size_flags(SIZE_EXPAND_FILL); + button_constant->connect("pressed", this, "_set_preset", varray(0)); + hb->add_child(button_constant); + + button_out = memnew(ToolButton); + button_out->set_tooltip(TTR("Out")); + button_out->set_h_size_flags(SIZE_EXPAND_FILL); + button_out->connect("pressed", this, "_set_preset", varray(0.5)); + hb->add_child(button_out); + + button_in = memnew(ToolButton); + button_in->set_tooltip(TTR("In")); + button_in->set_h_size_flags(SIZE_EXPAND_FILL); + button_in->connect("pressed", this, "_set_preset", varray(2)); + hb->add_child(button_in); + + button_in_out = NULL; + button_out_in = NULL; + + easing_draw = memnew(Control); + easing_draw->connect("draw", this, "_draw_easing"); + easing_draw->connect("gui_input", this, "_drag_easing"); + easing_draw->set_default_cursor_shape(Control::CURSOR_MOVE); + vb->add_child(easing_draw); + + flip = false; +} + +///////////////////// VECTOR2 ///////////////////////// + +void EditorPropertyVector2::_value_changed(double val) { + if (setting) + return; + + Vector2 v2; + v2.x = spin[0]->get_value(); + v2.y = spin[1]->get_value(); + emit_signal("property_changed", get_edited_property(), v2); +} + +void EditorPropertyVector2::update_property() { + Vector2 val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val.x); + spin[1]->set_value(val.y); + setting = false; +} + +void EditorPropertyVector2::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector2::_value_changed); +} + +void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 2; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyVector2::EditorPropertyVector2() { + VBoxContainer *vb = memnew(VBoxContainer); + add_child(vb); + static const char *desc[2] = { "x", "y" }; + for (int i = 0; i < 2; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + vb->add_child(spin[i]); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + setting = false; +} + +///////////////////// RECT2 ///////////////////////// + +void EditorPropertyRect2::_value_changed(double val) { + if (setting) + return; + + Rect2 r2; + r2.position.x = spin[0]->get_value(); + r2.position.x = spin[1]->get_value(); + r2.size.y = spin[2]->get_value(); + r2.size.y = spin[3]->get_value(); + emit_signal("property_changed", get_edited_property(), r2); +} + +void EditorPropertyRect2::update_property() { + Rect2 val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val.position.x); + spin[1]->set_value(val.position.y); + spin[2]->set_value(val.size.x); + spin[3]->set_value(val.size.y); + setting = false; +} + +void EditorPropertyRect2::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyRect2::_value_changed); +} + +void EditorPropertyRect2::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 4; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyRect2::EditorPropertyRect2() { + VBoxContainer *vb = memnew(VBoxContainer); + add_child(vb); + static const char *desc[4] = { "x", "y", "w", "h" }; + for (int i = 0; i < 4; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + vb->add_child(spin[i]); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + setting = false; +} +///////////////////// VECTOR3 ///////////////////////// + +void EditorPropertyVector3::_value_changed(double val) { + if (setting) + return; + + Vector3 v3; + v3.x = spin[0]->get_value(); + v3.y = spin[1]->get_value(); + v3.z = spin[2]->get_value(); + emit_signal("property_changed", get_edited_property(), v3); +} + +void EditorPropertyVector3::update_property() { + Vector3 val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val.x); + spin[1]->set_value(val.y); + spin[2]->set_value(val.z); + setting = false; +} + +void EditorPropertyVector3::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector3::_value_changed); +} + +void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 3; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyVector3::EditorPropertyVector3() { + VBoxContainer *vb = memnew(VBoxContainer); + add_child(vb); + static const char *desc[3] = { "x", "y", "z" }; + for (int i = 0; i < 3; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + vb->add_child(spin[i]); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + setting = false; +} +///////////////////// PLANE ///////////////////////// + +void EditorPropertyPlane::_value_changed(double val) { + if (setting) + return; + + Plane p; + p.normal.x = spin[0]->get_value(); + p.normal.y = spin[1]->get_value(); + p.normal.z = spin[2]->get_value(); + p.d = spin[3]->get_value(); + emit_signal("property_changed", get_edited_property(), p); +} + +void EditorPropertyPlane::update_property() { + Plane val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val.normal.x); + spin[1]->set_value(val.normal.y); + spin[2]->set_value(val.normal.z); + spin[3]->set_value(val.d); + setting = false; +} + +void EditorPropertyPlane::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyPlane::_value_changed); +} + +void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 4; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyPlane::EditorPropertyPlane() { + VBoxContainer *vb = memnew(VBoxContainer); + add_child(vb); + static const char *desc[4] = { "x", "y", "z", "d" }; + for (int i = 0; i < 4; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + vb->add_child(spin[i]); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + setting = false; +} + +///////////////////// QUAT ///////////////////////// + +void EditorPropertyQuat::_value_changed(double val) { + if (setting) + return; + + Quat p; + p.x = spin[0]->get_value(); + p.y = spin[1]->get_value(); + p.z = spin[2]->get_value(); + p.w = spin[3]->get_value(); + emit_signal("property_changed", get_edited_property(), p); +} + +void EditorPropertyQuat::update_property() { + Quat val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val.x); + spin[1]->set_value(val.y); + spin[2]->set_value(val.z); + spin[3]->set_value(val.w); + setting = false; +} + +void EditorPropertyQuat::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyQuat::_value_changed); +} + +void EditorPropertyQuat::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 4; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyQuat::EditorPropertyQuat() { + VBoxContainer *vb = memnew(VBoxContainer); + add_child(vb); + static const char *desc[4] = { "x", "y", "z", "w" }; + for (int i = 0; i < 4; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + vb->add_child(spin[i]); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + setting = false; +} + +///////////////////// AABB ///////////////////////// + +void EditorPropertyAABB::_value_changed(double val) { + if (setting) + return; + + AABB p; + p.position.x = spin[0]->get_value(); + p.position.y = spin[1]->get_value(); + p.position.z = spin[2]->get_value(); + p.size.x = spin[3]->get_value(); + p.size.y = spin[4]->get_value(); + p.size.z = spin[5]->get_value(); + + emit_signal("property_changed", get_edited_property(), p); +} + +void EditorPropertyAABB::update_property() { + AABB val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val.position.x); + spin[1]->set_value(val.position.y); + spin[2]->set_value(val.position.z); + spin[3]->set_value(val.size.x); + spin[4]->set_value(val.size.y); + spin[5]->set_value(val.size.z); + + setting = false; +} + +void EditorPropertyAABB::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyAABB::_value_changed); +} + +void EditorPropertyAABB::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 6; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyAABB::EditorPropertyAABB() { + GridContainer *g = memnew(GridContainer); + g->set_columns(3); + add_child(g); + + static const char *desc[6] = { "x", "y", "z", "w", "h", "d" }; + for (int i = 0; i < 6; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + g->add_child(spin[i]); + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + set_label_layout(LABEL_LAYOUT_TOP); + setting = false; +} + +///////////////////// TRANSFORM2D ///////////////////////// + +void EditorPropertyTransform2D::_value_changed(double val) { + if (setting) + return; + + Transform2D p; + p[0][0] = spin[0]->get_value(); + p[0][1] = spin[1]->get_value(); + p[1][0] = spin[2]->get_value(); + p[1][1] = spin[3]->get_value(); + p[2][0] = spin[4]->get_value(); + p[2][1] = spin[5]->get_value(); + + emit_signal("property_changed", get_edited_property(), p); +} + +void EditorPropertyTransform2D::update_property() { + Transform2D val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val[0][0]); + spin[1]->set_value(val[0][1]); + spin[2]->set_value(val[1][0]); + spin[3]->set_value(val[1][1]); + spin[4]->set_value(val[2][0]); + spin[5]->set_value(val[2][1]); + + setting = false; +} + +void EditorPropertyTransform2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyTransform2D::_value_changed); +} + +void EditorPropertyTransform2D::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 6; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyTransform2D::EditorPropertyTransform2D() { + GridContainer *g = memnew(GridContainer); + g->set_columns(2); + add_child(g); + + static const char *desc[6] = { "xx", "xy", "yx", "yy", "ox", "oy" }; + for (int i = 0; i < 6; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + g->add_child(spin[i]); + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + set_label_layout(LABEL_LAYOUT_TOP); + setting = false; +} + +///////////////////// BASIS ///////////////////////// + +void EditorPropertyBasis::_value_changed(double val) { + if (setting) + return; + + Basis p; + p[0][0] = spin[0]->get_value(); + p[1][0] = spin[1]->get_value(); + p[2][0] = spin[2]->get_value(); + p[0][1] = spin[3]->get_value(); + p[1][1] = spin[4]->get_value(); + p[2][1] = spin[5]->get_value(); + p[0][2] = spin[6]->get_value(); + p[1][2] = spin[7]->get_value(); + p[2][2] = spin[8]->get_value(); + + emit_signal("property_changed", get_edited_property(), p); +} + +void EditorPropertyBasis::update_property() { + Basis val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val[0][0]); + spin[1]->set_value(val[1][0]); + spin[2]->set_value(val[2][0]); + spin[3]->set_value(val[0][1]); + spin[4]->set_value(val[1][1]); + spin[5]->set_value(val[2][1]); + spin[6]->set_value(val[0][2]); + spin[7]->set_value(val[1][2]); + spin[8]->set_value(val[2][2]); + + setting = false; +} + +void EditorPropertyBasis::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyBasis::_value_changed); +} + +void EditorPropertyBasis::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 9; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyBasis::EditorPropertyBasis() { + GridContainer *g = memnew(GridContainer); + g->set_columns(3); + add_child(g); + + static const char *desc[9] = { "xx", "xy", "xz", "yx", "yy", "yz", "zx", "zy", "zz" }; + for (int i = 0; i < 9; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + g->add_child(spin[i]); + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + set_label_layout(LABEL_LAYOUT_TOP); + setting = false; +} + +///////////////////// TRANSFORM ///////////////////////// + +void EditorPropertyTransform::_value_changed(double val) { + if (setting) + return; + + Transform p; + p.basis[0][0] = spin[0]->get_value(); + p.basis[1][0] = spin[1]->get_value(); + p.basis[2][0] = spin[2]->get_value(); + p.basis[0][1] = spin[3]->get_value(); + p.basis[1][1] = spin[4]->get_value(); + p.basis[2][1] = spin[5]->get_value(); + p.basis[0][2] = spin[6]->get_value(); + p.basis[1][2] = spin[7]->get_value(); + p.basis[2][2] = spin[8]->get_value(); + p.origin[0] = spin[9]->get_value(); + p.origin[1] = spin[10]->get_value(); + p.origin[2] = spin[11]->get_value(); + + emit_signal("property_changed", get_edited_property(), p); +} + +void EditorPropertyTransform::update_property() { + Transform val = get_edited_object()->get(get_edited_property()); + setting = true; + spin[0]->set_value(val.basis[0][0]); + spin[1]->set_value(val.basis[1][0]); + spin[2]->set_value(val.basis[2][0]); + spin[3]->set_value(val.basis[0][1]); + spin[4]->set_value(val.basis[1][1]); + spin[5]->set_value(val.basis[2][1]); + spin[6]->set_value(val.basis[0][2]); + spin[7]->set_value(val.basis[1][2]); + spin[8]->set_value(val.basis[2][2]); + spin[9]->set_value(val.origin[0]); + spin[10]->set_value(val.origin[1]); + spin[11]->set_value(val.origin[2]); + + setting = false; +} + +void EditorPropertyTransform::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyTransform::_value_changed); +} + +void EditorPropertyTransform::setup(double p_min, double p_max, double p_step, bool p_no_slider) { + for (int i = 0; i < 12; i++) { + spin[i]->set_min(p_min); + spin[i]->set_max(p_max); + spin[i]->set_step(p_step); + spin[i]->set_hide_slider(p_no_slider); + } +} + +EditorPropertyTransform::EditorPropertyTransform() { + GridContainer *g = memnew(GridContainer); + g->set_columns(3); + add_child(g); + + static const char *desc[12] = { "xx", "xy", "xz", "yx", "yy", "yz", "zx", "zy", "zz", "ox", "oy", "oz" }; + for (int i = 0; i < 12; i++) { + spin[i] = memnew(EditorSpinSlider); + spin[i]->set_label(desc[i]); + g->add_child(spin[i]); + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + add_focusable(spin[i]); + spin[i]->connect("value_changed", this, "_value_changed"); + } + set_label_reference(spin[0]); //show text and buttons around this + set_label_layout(LABEL_LAYOUT_TOP); + setting = false; +} + +////////////// COLOR PICKER ////////////////////// + +void EditorPropertyColor::_color_changed(const Color &p_color) { + + emit_signal("property_changed", get_edited_property(), p_color); +} + +void EditorPropertyColor::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_color_changed"), &EditorPropertyColor::_color_changed); +} + +void EditorPropertyColor::update_property() { + + picker->set_pick_color(get_edited_object()->get(get_edited_property())); +} + +void EditorPropertyColor::setup(bool p_show_alpha) { + picker->set_edit_alpha(p_show_alpha); +} + +EditorPropertyColor::EditorPropertyColor() { + + picker = memnew(ColorPickerButton); + add_child(picker); + picker->set_flat(true); + picker->connect("color_changed", this, "_color_changed"); +} + +////////////// NODE PATH ////////////////////// + +void EditorPropertyNodePath::_node_selected(const NodePath &p_path) { + + emit_signal("property_changed", get_edited_property(), p_path); + update_property(); +} + +void EditorPropertyNodePath::_node_assign() { + if (!scene_tree) { + scene_tree = memnew(SceneTreeDialog); + add_child(scene_tree); + scene_tree->connect("selected", this, "_node_selected"); + } + scene_tree->popup_centered_ratio(); +} + +void EditorPropertyNodePath::_node_clear() { + + emit_signal("property_changed", get_edited_property(), NodePath()); + update_property(); +} + +void EditorPropertyNodePath::update_property() { + + NodePath p = get_edited_object()->get(get_edited_property()); + + assign->set_tooltip(p); + if (p == NodePath()) { + assign->set_icon(Ref<Texture>()); + assign->set_text(TTR("Assign..")); + assign->set_flat(false); + return; + } + assign->set_flat(true); + + Node *base_node = NULL; + if (base_hint != NodePath()) { + if (get_tree()->get_root()->has_node(base_hint)) { + base_node = get_tree()->get_root()->get_node(base_hint); + } + } else { + base_node = Object::cast_to<Node>(get_edited_object()); + } + + if (!base_node || !base_node->has_node(p)) { + assign->set_icon(Ref<Texture>()); + assign->set_text(p); + return; + } + + Node *target_node = base_node->get_node(p); + ERR_FAIL_COND(!target_node); + + assign->set_text(target_node->get_name()); + + Ref<Texture> icon; + if (has_icon(target_node->get_class(), "EditorIcons")) + icon = get_icon(target_node->get_class(), "EditorIcons"); + else + icon = get_icon("Node", "EditorIcons"); + + assign->set_icon(icon); +} + +void EditorPropertyNodePath::setup(const NodePath &p_base_hint) { + + base_hint = p_base_hint; +} + +void EditorPropertyNodePath::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Ref<Texture> t = get_icon("Clear", "EditorIcons"); + clear->set_icon(t); + } +} + +void EditorPropertyNodePath::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_node_selected"), &EditorPropertyNodePath::_node_selected); + ClassDB::bind_method(D_METHOD("_node_assign"), &EditorPropertyNodePath::_node_assign); + ClassDB::bind_method(D_METHOD("_node_clear"), &EditorPropertyNodePath::_node_clear); +} + +EditorPropertyNodePath::EditorPropertyNodePath() { + + HBoxContainer *hbc = memnew(HBoxContainer); + add_child(hbc); + assign = memnew(Button); + assign->set_flat(true); + assign->set_h_size_flags(SIZE_EXPAND_FILL); + assign->set_clip_text(true); + assign->connect("pressed", this, "_node_assign"); + hbc->add_child(assign); + + clear = memnew(Button); + clear->set_flat(true); + clear->connect("pressed", this, "_node_clear"); + hbc->add_child(clear); + + scene_tree = NULL; //do not allocate unnecesarily +} + +////////////// RESOURCE ////////////////////// + +void EditorPropertyResource::_file_selected(const String &p_path) { + + RES res = ResourceLoader::load(p_path); + emit_signal("property_changed", get_edited_property(), res); + update_property(); +} + +void EditorPropertyResource::_menu_option(int p_which) { + + // scene_tree->popup_centered_ratio(); + switch (p_which) { + case OBJ_MENU_LOAD: { + + if (!file) { + file = memnew(EditorFileDialog); + file->connect("file_selected", this, "_file_selected"); + add_child(file); + } + file->set_mode(EditorFileDialog::MODE_OPEN_FILE); + String type = base_type; + + List<String> extensions; + for (int i = 0; i < type.get_slice_count(","); i++) { + + ResourceLoader::get_recognized_extensions_for_type(type.get_slice(",", i), &extensions); + } + + Set<String> valid_extensions; + for (List<String>::Element *E = extensions.front(); E; E = E->next()) { + valid_extensions.insert(E->get()); + } + + file->clear_filters(); + for (Set<String>::Element *E = valid_extensions.front(); E; E = E->next()) { + + file->add_filter("*." + E->get() + " ; " + E->get().to_upper()); + } + + file->popup_centered_ratio(); + } break; + + case OBJ_MENU_EDIT: { + + RES res = get_edited_object()->get(get_edited_property()); + + if (!res.is_null()) { + + emit_signal("resource_selected", get_edited_property(), res); + } + } break; + case OBJ_MENU_CLEAR: { + + emit_signal("property_changed", get_edited_property(), RES()); + update_property(); + + } break; + + case OBJ_MENU_MAKE_UNIQUE: { + + RES res_orig = get_edited_object()->get(get_edited_property()); + if (res_orig.is_null()) + return; + + List<PropertyInfo> property_list; + res_orig->get_property_list(&property_list); + List<Pair<String, Variant> > propvalues; + + for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { + + Pair<String, Variant> p; + PropertyInfo &pi = E->get(); + if (pi.usage & PROPERTY_USAGE_STORAGE) { + + p.first = pi.name; + p.second = res_orig->get(pi.name); + } + + propvalues.push_back(p); + } + + String orig_type = res_orig->get_class(); + + Object *inst = ClassDB::instance(orig_type); + + Ref<Resource> res = Ref<Resource>(Object::cast_to<Resource>(inst)); + + ERR_FAIL_COND(res.is_null()); + + for (List<Pair<String, Variant> >::Element *E = propvalues.front(); E; E = E->next()) { + + Pair<String, Variant> &p = E->get(); + res->set(p.first, p.second); + } + + emit_signal("property_changed", get_edited_property(), res); + update_property(); + + } break; + + case OBJ_MENU_COPY: { + RES res = get_edited_object()->get(get_edited_property()); + + EditorSettings::get_singleton()->set_resource_clipboard(res); + + } break; + case OBJ_MENU_PASTE: { + + RES res = EditorSettings::get_singleton()->get_resource_clipboard(); + emit_signal("property_changed", get_edited_property(), res); + update_property(); + + } break; + case OBJ_MENU_NEW_SCRIPT: { + + if (Object::cast_to<Node>(get_edited_object())) { + EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(Object::cast_to<Node>(get_edited_object())); + } + + } break; + case OBJ_MENU_SHOW_IN_FILE_SYSTEM: { + RES res = get_edited_object()->get(get_edited_property()); + + FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock(); + file_system_dock->navigate_to_path(res->get_path()); + // Ensure that the FileSystem dock is visible. + TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control(); + tab_container->set_current_tab(file_system_dock->get_position_in_parent()); + } break; + default: { + + RES res = get_edited_object()->get(get_edited_property()); + + if (p_which >= CONVERT_BASE_ID) { + + int to_type = p_which - CONVERT_BASE_ID; + + Vector<Ref<EditorResourceConversionPlugin> > conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(res); + + ERR_FAIL_INDEX(to_type, conversions.size()); + + Ref<Resource> new_res = conversions[to_type]->convert(res); + + emit_signal("property_changed", get_edited_property(), new_res); + update_property(); + break; + } + ERR_FAIL_COND(inheritors_array.empty()); + + String intype = inheritors_array[p_which - TYPE_BASE_ID]; + + if (intype == "ViewportTexture") { + + if (!scene_tree) { + scene_tree = memnew(SceneTreeDialog); + add_child(scene_tree); + scene_tree->connect("selected", this, "_viewport_selected"); + scene_tree->set_title(TTR("Pick a Viewport")); + } + scene_tree->popup_centered_ratio(); + + return; + } + + Object *obj = ClassDB::instance(intype); + + if (!obj) { + obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource"); + } + + ERR_BREAK(!obj); + Resource *resp = Object::cast_to<Resource>(obj); + ERR_BREAK(!resp); + if (get_edited_object() && base_type != String() && base_type == "Script") { + //make visual script the right type + res->call("set_instance_base_type", get_edited_object()->get_class()); + } + + res = Ref<Resource>(resp); + emit_signal("property_changed", get_edited_property(), res); + update_property(); + + } break; + } +} + +void EditorPropertyResource::_resource_preview(const String &p_path, const Ref<Texture> &p_preview, ObjectID p_obj) { + + RES p = get_edited_object()->get(get_edited_property()); + if (p.is_valid() && p->get_instance_id() == p_obj) { + if (p_preview.is_valid()) { + assign->set_icon(p_preview); + } + } +} + +void EditorPropertyResource::_update_menu() { + //////////////////// UPDATE MENU ////////////////////////// + RES res = get_edited_object()->get(get_edited_property()); + + menu->clear(); + + if (get_edited_property() == "script" && base_type == "Script" && Object::cast_to<Node>(get_edited_object())) { + menu->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT); + menu->add_separator(); + } else if (base_type != "") { + int idx = 0; + + Vector<EditorData::CustomType> custom_resources; + + if (EditorNode::get_editor_data().get_custom_types().has("Resource")) { + custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"]; + } + + for (int i = 0; i < base_type.get_slice_count(","); i++) { + + String base = base_type.get_slice(",", i); + + Set<String> valid_inheritors; + valid_inheritors.insert(base); + List<StringName> inheritors; + ClassDB::get_inheriters_from_class(base.strip_edges(), &inheritors); + + for (int i = 0; i < custom_resources.size(); i++) { + inheritors.push_back(custom_resources[i].name); + } + + List<StringName>::Element *E = inheritors.front(); + while (E) { + valid_inheritors.insert(E->get()); + E = E->next(); + } + + for (Set<String>::Element *E = valid_inheritors.front(); E; E = E->next()) { + String t = E->get(); + + bool is_custom_resource = false; + Ref<Texture> icon; + if (!custom_resources.empty()) { + for (int i = 0; i < custom_resources.size(); i++) { + if (custom_resources[i].name == t) { + is_custom_resource = true; + if (custom_resources[i].icon.is_valid()) + icon = custom_resources[i].icon; + break; + } + } + } + + if (!is_custom_resource && !ClassDB::can_instance(t)) + continue; + + inheritors_array.push_back(t); + + int id = TYPE_BASE_ID + idx; + + if (!icon.is_valid() && has_icon(t, "EditorIcons")) { + icon = get_icon(t, "EditorIcons"); + } + + if (icon.is_valid()) { + + menu->add_icon_item(icon, vformat(TTR("New %s"), t), id); + } else { + + menu->add_item(vformat(TTR("New %s"), t), id); + } + + idx++; + } + } + + if (menu->get_item_count()) + menu->add_separator(); + } + + menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Load"), OBJ_MENU_LOAD); + + if (!res.is_null()) { + + menu->add_icon_item(get_icon("Edit", "EditorIcons"), TTR("Edit"), OBJ_MENU_EDIT); + menu->add_icon_item(get_icon("Clear", "EditorIcons"), TTR("Clear"), OBJ_MENU_CLEAR); + menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE); + RES r = res; + if (r.is_valid() && r->get_path().is_resource_file()) { + menu->add_separator(); + menu->add_item(TTR("Show in File System"), OBJ_MENU_SHOW_IN_FILE_SYSTEM); + } + } else { + } + + RES cb = EditorSettings::get_singleton()->get_resource_clipboard(); + bool paste_valid = false; + if (cb.is_valid()) { + if (base_type == "") + paste_valid = true; + else + for (int i = 0; i < base_type.get_slice_count(","); i++) + if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) { + paste_valid = true; + break; + } + } + + if (!res.is_null() || paste_valid) { + menu->add_separator(); + + if (!res.is_null()) { + + menu->add_item(TTR("Copy"), OBJ_MENU_COPY); + } + + if (paste_valid) { + + menu->add_item(TTR("Paste"), OBJ_MENU_PASTE); + } + } + + if (!res.is_null()) { + + Vector<Ref<EditorResourceConversionPlugin> > conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(res); + if (conversions.size()) { + menu->add_separator(); + } + for (int i = 0; i < conversions.size(); i++) { + String what = conversions[i]->converts_to(); + Ref<Texture> icon; + if (has_icon(what, "EditorIcons")) { + + icon = get_icon(what, "EditorIcons"); + } else { + + icon = get_icon(what, "Resource"); + } + + menu->add_icon_item(icon, vformat(TTR("Convert To %s"), what), CONVERT_BASE_ID + i); + } + } + + Rect2 gt = get_global_rect(); + int ms = menu->get_combined_minimum_size().width; + Vector2 popup_pos = gt.position + gt.size - Vector2(ms, 0); + menu->set_position(popup_pos); + menu->popup(); +} + +void EditorPropertyResource::update_property() { + + RES res = get_edited_object()->get(get_edited_property()); + + if (res == RES()) { + assign->set_icon(Ref<Texture>()); + assign->set_text(TTR("[empty]")); + assign->set_disabled(true); + } else { + assign->set_disabled(false); + + Ref<Texture> icon; + if (has_icon(res->get_class(), "EditorIcons")) + icon = get_icon(res->get_class(), "EditorIcons"); + else + icon = get_icon("Node", "EditorIcons"); + + assign->set_icon(icon); + + if (res->get_name() != String()) { + assign->set_text(res->get_name()); + } else if (res->get_path().is_resource_file()) { + assign->set_text(res->get_name()); + assign->set_tooltip(res->get_path()); + } else { + assign->set_text(res->get_class()); + } + + if (res->get_path().is_resource_file()) { + assign->set_tooltip(res->get_path()); + } + + //preview will override the above, so called at the end + EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_resource_preview", res->get_instance_id()); + } +} + +void EditorPropertyResource::_resource_selected() { + RES res = get_edited_object()->get(get_edited_property()); + + if (!res.is_null()) { + + emit_signal("resource_selected", get_edited_property(), res); + } +} + +void EditorPropertyResource::setup(const String &p_base_type) { + base_type = p_base_type; +} + +void EditorPropertyResource::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Ref<Texture> t = get_icon("select_arrow", "Tree"); + edit->set_icon(t); + } +} + +void EditorPropertyResource::_viewport_selected(const NodePath &p_path) { + + Node *to_node = get_node(p_path); + if (!Object::cast_to<Viewport>(to_node)) { + EditorNode::get_singleton()->show_warning(TTR("Selected node is not a Viewport!")); + return; + } + + Ref<ViewportTexture> vt; + vt.instance(); + vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node)); + vt->setup_local_to_scene(); + + emit_signal("property_changed", get_edited_property(), vt); + update_property(); +} +void EditorPropertyResource::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_file_selected"), &EditorPropertyResource::_file_selected); + ClassDB::bind_method(D_METHOD("_menu_option"), &EditorPropertyResource::_menu_option); + ClassDB::bind_method(D_METHOD("_update_menu"), &EditorPropertyResource::_update_menu); + ClassDB::bind_method(D_METHOD("_resource_preview"), &EditorPropertyResource::_resource_preview); + ClassDB::bind_method(D_METHOD("_resource_selected"), &EditorPropertyResource::_resource_selected); + ClassDB::bind_method(D_METHOD("_viewport_selected"), &EditorPropertyResource::_viewport_selected); +} + +EditorPropertyResource::EditorPropertyResource() { + + HBoxContainer *hbc = memnew(HBoxContainer); + add_child(hbc); + assign = memnew(Button); + assign->set_flat(true); + assign->set_h_size_flags(SIZE_EXPAND_FILL); + assign->set_clip_text(true); + assign->connect("pressed", this, "_resource_selected"); + hbc->add_child(assign); + + menu = memnew(PopupMenu); + add_child(menu); + edit = memnew(Button); + edit->set_flat(true); + menu->connect("id_pressed", this, "_menu_option"); + edit->connect("pressed", this, "_update_menu"); + hbc->add_child(edit); + + file = NULL; + scene_tree = NULL; +} + +////////////// DEFAULT PLUGIN ////////////////////// + +bool EditorInspectorDefaultPlugin::can_handle(Object *p_object) { + return true; //can handle everything +} + +void EditorInspectorDefaultPlugin::parse_begin(Object *p_object) { + //do none +} + +bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { + + switch (p_type) { + + // atomic types + case Variant::BOOL: { + EditorPropertyCheck *editor = memnew(EditorPropertyCheck); + add_property_editor(p_path, editor); + } break; + case Variant::INT: { + + if (p_hint == PROPERTY_HINT_ENUM) { + EditorPropertyEnum *editor = memnew(EditorPropertyEnum); + Vector<String> options = p_hint_text.split(","); + editor->setup(options); + add_property_editor(p_path, editor); + + } else if (p_hint == PROPERTY_HINT_FLAGS) { + EditorPropertyFlags *editor = memnew(EditorPropertyFlags); + Vector<String> options = p_hint_text.split(","); + editor->setup(options); + add_property_editor(p_path, editor); + + } else if (p_hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || p_hint == PROPERTY_HINT_LAYERS_2D_RENDER || p_hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || p_hint == PROPERTY_HINT_LAYERS_3D_RENDER) { + + EditorPropertyLayers::LayerType lt; + switch (p_hint) { + case PROPERTY_HINT_LAYERS_2D_RENDER: + lt = EditorPropertyLayers::LAYER_RENDER_2D; + break; + case PROPERTY_HINT_LAYERS_2D_PHYSICS: + lt = EditorPropertyLayers::LAYER_PHYSICS_2D; + break; + case PROPERTY_HINT_LAYERS_3D_RENDER: + lt = EditorPropertyLayers::LAYER_RENDER_3D; + break; + case PROPERTY_HINT_LAYERS_3D_PHYSICS: + lt = EditorPropertyLayers::LAYER_PHYSICS_3D; + break; + default: {} //compiler could be smarter here and realize this cant happen + } + EditorPropertyLayers *editor = memnew(EditorPropertyLayers); + editor->setup(lt); + add_property_editor(p_path, editor); + } else if (p_hint == PROPERTY_HINT_OBJECT_ID) { + + EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); + editor->setup(p_hint_text); + add_property_editor(p_path, editor); + + } else { + EditorPropertyInteger *editor = memnew(EditorPropertyInteger); + int min = 0, max = 65535; + bool greater = true, lesser = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + greater = false; //if using ranged, asume false by default + lesser = false; + min = p_hint_text.get_slice(",", 0).to_int(); + max = p_hint_text.get_slice(",", 1).to_int(); + for (int i = 2; i < p_hint_text.get_slice_count(","); i++) { + String slice = p_hint_text.get_slice(",", i).strip_edges(); + if (slice == "or_greater") { + greater = true; + } + if (slice == "or_lesser") { + lesser = true; + } + } + } + + editor->setup(min, max, greater, lesser); + + add_property_editor(p_path, editor); + } + } break; + case Variant::REAL: { + + if (p_hint == PROPERTY_HINT_EXP_EASING) { + EditorPropertyEasing *editor = memnew(EditorPropertyEasing); + bool full = true; + bool flip = false; + Vector<String> hints = p_hint_text.split(","); + for (int i = 0; i < hints.size(); i++) { + String h = hints[i].strip_edges(); + if (h == "attenuation") { + flip = true; + } + if (h == "inout") { + full = true; + } + } + + editor->setup(full, flip); + add_property_editor(p_path, editor); + + } else { + EditorPropertyFloat *editor = memnew(EditorPropertyFloat); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + bool exp_range = false; + bool greater = true, lesser = true; + + if ((p_hint == PROPERTY_HINT_RANGE || p_hint == PROPERTY_HINT_EXP_RANGE) && p_hint_text.get_slice_count(",") >= 2) { + greater = false; //if using ranged, asume false by default + lesser = false; + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + exp_range = p_hint == PROPERTY_HINT_EXP_RANGE; + for (int i = 2; i < p_hint_text.get_slice_count(","); i++) { + String slice = p_hint_text.get_slice(",", i).strip_edges(); + if (slice == "or_greater") { + greater = true; + } + if (slice == "or_lesser") { + lesser = true; + } + } + } + + editor->setup(min, max, step, hide_slider, exp_range, greater, lesser); + + add_property_editor(p_path, editor); + } + } break; + case Variant::STRING: { + + if (p_hint == PROPERTY_HINT_ENUM) { + EditorPropertyTextEnum *editor = memnew(EditorPropertyTextEnum); + Vector<String> options = p_hint_text.split(","); + editor->setup(options); + add_property_editor(p_path, editor); + } else if (p_hint == PROPERTY_HINT_MULTILINE_TEXT) { + EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText); + add_property_editor(p_path, editor); + } else if (p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_FILE || p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE) { + + Vector<String> extensions = p_hint_text.split(","); + bool global = p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE; + bool folder = p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_GLOBAL_DIR; + EditorPropertyPath *editor = memnew(EditorPropertyPath); + editor->setup(extensions, folder, global); + add_property_editor(p_path, editor); + } else if (p_hint == PROPERTY_HINT_METHOD_OF_VARIANT_TYPE || + p_hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE || + p_hint == PROPERTY_HINT_METHOD_OF_INSTANCE || + p_hint == PROPERTY_HINT_METHOD_OF_SCRIPT || + p_hint == PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE || + p_hint == PROPERTY_HINT_PROPERTY_OF_BASE_TYPE || + p_hint == PROPERTY_HINT_PROPERTY_OF_INSTANCE || + p_hint == PROPERTY_HINT_PROPERTY_OF_SCRIPT) { + + EditorPropertyMember *editor = memnew(EditorPropertyMember); + + EditorPropertyMember::Type type = EditorPropertyMember::MEMBER_METHOD_OF_BASE_TYPE; + switch (p_hint) { + case PROPERTY_HINT_METHOD_OF_BASE_TYPE: type = EditorPropertyMember::MEMBER_METHOD_OF_BASE_TYPE; break; + case PROPERTY_HINT_METHOD_OF_INSTANCE: type = EditorPropertyMember::MEMBER_METHOD_OF_INSTANCE; break; + case PROPERTY_HINT_METHOD_OF_SCRIPT: type = EditorPropertyMember::MEMBER_METHOD_OF_SCRIPT; break; + case PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE: type = EditorPropertyMember::MEMBER_PROPERTY_OF_VARIANT_TYPE; break; + case PROPERTY_HINT_PROPERTY_OF_BASE_TYPE: type = EditorPropertyMember::MEMBER_PROPERTY_OF_BASE_TYPE; break; + case PROPERTY_HINT_PROPERTY_OF_INSTANCE: type = EditorPropertyMember::MEMBER_PROPERTY_OF_INSTANCE; break; + case PROPERTY_HINT_PROPERTY_OF_SCRIPT: type = EditorPropertyMember::MEMBER_PROPERTY_OF_SCRIPT; break; + default: {} + } + editor->setup(type, p_hint_text); + add_property_editor(p_path, editor); + + } else { + + EditorPropertyText *editor = memnew(EditorPropertyText); + add_property_editor(p_path, editor); + } + } break; + + // math types + + case Variant::VECTOR2: { + EditorPropertyVector2 *editor = memnew(EditorPropertyVector2); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + + } break; // 5 + case Variant::RECT2: { + EditorPropertyRect2 *editor = memnew(EditorPropertyRect2); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + } break; + case Variant::VECTOR3: { + EditorPropertyVector3 *editor = memnew(EditorPropertyVector3); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + + } break; + case Variant::TRANSFORM2D: { + EditorPropertyTransform2D *editor = memnew(EditorPropertyTransform2D); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + + } break; + case Variant::PLANE: { + EditorPropertyPlane *editor = memnew(EditorPropertyPlane); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + } break; + case Variant::QUAT: { + EditorPropertyQuat *editor = memnew(EditorPropertyQuat); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + } break; // 10 + case Variant::AABB: { + EditorPropertyAABB *editor = memnew(EditorPropertyAABB); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + } break; + case Variant::BASIS: { + EditorPropertyBasis *editor = memnew(EditorPropertyBasis); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + } break; + case Variant::TRANSFORM: { + EditorPropertyTransform *editor = memnew(EditorPropertyTransform); + double min = -65535, max = 65535, step = 0.001; + bool hide_slider = true; + + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + min = p_hint_text.get_slice(",", 0).to_double(); + max = p_hint_text.get_slice(",", 1).to_double(); + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_double(); + } + hide_slider = false; + } + + editor->setup(min, max, step, hide_slider); + add_property_editor(p_path, editor); + + } break; + + // misc types + case Variant::COLOR: { + EditorPropertyColor *editor = memnew(EditorPropertyColor); + editor->setup(p_hint != PROPERTY_HINT_COLOR_NO_ALPHA); + add_property_editor(p_path, editor); + } break; + case Variant::NODE_PATH: { + + EditorPropertyNodePath *editor = memnew(EditorPropertyNodePath); + if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && p_hint_text != String()) { + editor->setup(p_hint_text); + } + add_property_editor(p_path, editor); + + } break; // 15 + case Variant::_RID: { + } break; + case Variant::OBJECT: { + EditorPropertyResource *editor = memnew(EditorPropertyResource); + editor->setup(p_hint == PROPERTY_HINT_RESOURCE_TYPE ? p_hint_text : "Resource"); + add_property_editor(p_path, editor); + + } break; + case Variant::DICTIONARY: { + } break; + case Variant::ARRAY: { + } break; + + // arrays + case Variant::POOL_BYTE_ARRAY: { + } break; // 20 + case Variant::POOL_INT_ARRAY: { + } break; + case Variant::POOL_REAL_ARRAY: { + } break; + case Variant::POOL_STRING_ARRAY: { + } break; + case Variant::POOL_VECTOR2_ARRAY: { + } break; + case Variant::POOL_VECTOR3_ARRAY: { + } break; // 25 + case Variant::POOL_COLOR_ARRAY: { + } break; + default: {} + } + + return false; //can be overriden, although it will most likely be last anyway +} + +void EditorInspectorDefaultPlugin::parse_end() { + //do none +} diff --git a/editor/editor_properties.h b/editor/editor_properties.h new file mode 100644 index 0000000000..cf0c735b37 --- /dev/null +++ b/editor/editor_properties.h @@ -0,0 +1,520 @@ +/*************************************************************************/ +/* editor_properties.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITOR_PROPERTIES_H +#define EDITOR_PROPERTIES_H + +#include "editor/create_dialog.h" +#include "editor/editor_file_system.h" +#include "editor/editor_inspector.h" +#include "editor/editor_spin_slider.h" +#include "editor/property_selector.h" +#include "editor/scene_tree_editor.h" +#include "scene/gui/color_picker.h" + +class EditorPropertyText : public EditorProperty { + GDCLASS(EditorPropertyText, EditorProperty) + LineEdit *text; + + bool updating; + void _text_changed(const String &p_string); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + EditorPropertyText(); +}; + +class EditorPropertyMultilineText : public EditorProperty { + GDCLASS(EditorPropertyMultilineText, EditorProperty) + TextEdit *text; + + AcceptDialog *big_text_dialog; + TextEdit *big_text; + Button *open_big_text; + + void _big_text_changed(); + void _text_changed(); + void _open_big_text(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + virtual void update_property(); + EditorPropertyMultilineText(); +}; + +class EditorPropertyTextEnum : public EditorProperty { + GDCLASS(EditorPropertyTextEnum, EditorProperty) + OptionButton *options; + + void _option_selected(int p_which); + +protected: + static void _bind_methods(); + +public: + void setup(const Vector<String> &p_options); + virtual void update_property(); + EditorPropertyTextEnum(); +}; + +class EditorPropertyPath : public EditorProperty { + GDCLASS(EditorPropertyPath, EditorProperty) + Vector<String> extensions; + bool folder; + bool global; + EditorFileDialog *dialog; + Button *path; + + void _path_selected(const String &p_path); + void _path_pressed(); + +protected: + static void _bind_methods(); + +public: + void setup(const Vector<String> &p_extensions, bool p_folder, bool p_global); + virtual void update_property(); + EditorPropertyPath(); +}; + +class EditorPropertyMember : public EditorProperty { + GDCLASS(EditorPropertyMember, EditorProperty) +public: + enum Type { + MEMBER_METHOD_OF_VARIANT_TYPE, ///< a method of a type + MEMBER_METHOD_OF_BASE_TYPE, ///< a method of a base type + MEMBER_METHOD_OF_INSTANCE, ///< a method of an instance + MEMBER_METHOD_OF_SCRIPT, ///< a method of a script & base + MEMBER_PROPERTY_OF_VARIANT_TYPE, ///< a property of a type + MEMBER_PROPERTY_OF_BASE_TYPE, ///< a property of a base type + MEMBER_PROPERTY_OF_INSTANCE, ///< a property of an instance + MEMBER_PROPERTY_OF_SCRIPT, ///< a property of a script & base + + }; + +private: + Type hint; + PropertySelector *selector; + Button *property; + String hint_text; + + void _property_selected(const String &p_selected); + void _property_select(); + +protected: + static void _bind_methods(); + +public: + void setup(Type p_hint, const String &p_hint_text); + virtual void update_property(); + EditorPropertyMember(); +}; + +class EditorPropertyCheck : public EditorProperty { + GDCLASS(EditorPropertyCheck, EditorProperty) + CheckBox *checkbox; + + void _checkbox_pressed(); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + EditorPropertyCheck(); +}; + +class EditorPropertyEnum : public EditorProperty { + GDCLASS(EditorPropertyEnum, EditorProperty) + OptionButton *options; + + void _option_selected(int p_which); + +protected: + static void _bind_methods(); + +public: + void setup(const Vector<String> &p_options); + virtual void update_property(); + EditorPropertyEnum(); +}; + +class EditorPropertyFlags : public EditorProperty { + GDCLASS(EditorPropertyFlags, EditorProperty) + VBoxContainer *vbox; + Vector<CheckBox *> flags; + Vector<int> flag_indices; + + void _flag_toggled(); + +protected: + static void _bind_methods(); + +public: + void setup(const Vector<String> &p_options); + virtual void update_property(); + EditorPropertyFlags(); +}; + +class EditorPropertyLayersGrid; + +class EditorPropertyLayers : public EditorProperty { + GDCLASS(EditorPropertyLayers, EditorProperty) +public: + enum LayerType { + LAYER_PHYSICS_2D, + LAYER_RENDER_2D, + LAYER_PHYSICS_3D, + LAYER_RENDER_3D, + }; + +private: + EditorPropertyLayersGrid *grid; + void _grid_changed(uint32_t p_grid); + LayerType layer_type; + PopupMenu *layers; + Button *button; + + void _button_pressed(); + void _menu_pressed(int p_menu); + +protected: + static void _bind_methods(); + +public: + void setup(LayerType p_layer_type); + virtual void update_property(); + EditorPropertyLayers(); +}; + +class EditorPropertyInteger : public EditorProperty { + GDCLASS(EditorPropertyInteger, EditorProperty) + EditorSpinSlider *spin; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(int p_min, int p_max, bool p_allow_greater, bool p_allow_lesser); + EditorPropertyInteger(); +}; + +class EditorPropertyObjectID : public EditorProperty { + GDCLASS(EditorPropertyObjectID, EditorProperty) + Button *edit; + String base_type; + void _edit_pressed(); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(const String &p_base_type); + EditorPropertyObjectID(); +}; + +class EditorPropertyFloat : public EditorProperty { + GDCLASS(EditorPropertyFloat, EditorProperty) + EditorSpinSlider *spin; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range, bool p_greater, bool p_lesser); + EditorPropertyFloat(); +}; + +class EditorPropertyEasing : public EditorProperty { + GDCLASS(EditorPropertyEasing, EditorProperty) + Control *easing_draw; + ToolButton *button_out, *button_in, *button_linear, *button_constant; + ToolButton *button_in_out, *button_out_in; + VBoxContainer *vb; + + bool flip; + + void _drag_easing(const Ref<InputEvent> &p_ev); + void _draw_easing(); + void _notification(int p_what); + void _set_preset(float p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(bool p_full, bool p_flip); + EditorPropertyEasing(); +}; + +class EditorPropertyVector2 : public EditorProperty { + GDCLASS(EditorPropertyVector2, EditorProperty) + EditorSpinSlider *spin[2]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyVector2(); +}; + +class EditorPropertyRect2 : public EditorProperty { + GDCLASS(EditorPropertyRect2, EditorProperty) + EditorSpinSlider *spin[4]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyRect2(); +}; + +class EditorPropertyVector3 : public EditorProperty { + GDCLASS(EditorPropertyVector3, EditorProperty) + EditorSpinSlider *spin[3]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyVector3(); +}; + +class EditorPropertyPlane : public EditorProperty { + GDCLASS(EditorPropertyPlane, EditorProperty) + EditorSpinSlider *spin[4]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyPlane(); +}; + +class EditorPropertyQuat : public EditorProperty { + GDCLASS(EditorPropertyQuat, EditorProperty) + EditorSpinSlider *spin[4]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyQuat(); +}; + +class EditorPropertyAABB : public EditorProperty { + GDCLASS(EditorPropertyAABB, EditorProperty) + EditorSpinSlider *spin[6]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyAABB(); +}; + +class EditorPropertyTransform2D : public EditorProperty { + GDCLASS(EditorPropertyTransform2D, EditorProperty) + EditorSpinSlider *spin[6]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyTransform2D(); +}; + +class EditorPropertyBasis : public EditorProperty { + GDCLASS(EditorPropertyBasis, EditorProperty) + EditorSpinSlider *spin[9]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyBasis(); +}; + +class EditorPropertyTransform : public EditorProperty { + GDCLASS(EditorPropertyTransform, EditorProperty) + EditorSpinSlider *spin[12]; + bool setting; + void _value_changed(double p_val); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider); + EditorPropertyTransform(); +}; + +class EditorPropertyColor : public EditorProperty { + GDCLASS(EditorPropertyColor, EditorProperty) + ColorPickerButton *picker; + void _color_changed(const Color &p_color); + +protected: + static void _bind_methods(); + +public: + virtual void update_property(); + void setup(bool p_show_alpha); + EditorPropertyColor(); +}; + +class EditorPropertyNodePath : public EditorProperty { + GDCLASS(EditorPropertyNodePath, EditorProperty) + Button *assign; + Button *clear; + SceneTreeDialog *scene_tree; + NodePath base_hint; + + void _node_selected(const NodePath &p_path); + void _node_assign(); + void _node_clear(); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + virtual void update_property(); + void setup(const NodePath &p_base_hint); + EditorPropertyNodePath(); +}; + +class EditorPropertyResource : public EditorProperty { + GDCLASS(EditorPropertyResource, EditorProperty) + + enum MenuOption { + + OBJ_MENU_LOAD = 0, + OBJ_MENU_EDIT = 1, + OBJ_MENU_CLEAR = 2, + OBJ_MENU_MAKE_UNIQUE = 3, + OBJ_MENU_COPY = 4, + OBJ_MENU_PASTE = 5, + OBJ_MENU_NEW_SCRIPT = 6, + OBJ_MENU_SHOW_IN_FILE_SYSTEM = 7, + TYPE_BASE_ID = 100, + CONVERT_BASE_ID = 1000 + + }; + + Button *assign; + Button *edit; + PopupMenu *menu; + EditorFileDialog *file; + Vector<String> inheritors_array; + + String base_type; + + SceneTreeDialog *scene_tree; + + void _file_selected(const String &p_path); + void _menu_option(int p_which); + void _resource_preview(const String &p_path, const Ref<Texture> &p_preview, ObjectID p_obj); + void _resource_selected(); + void _viewport_selected(const NodePath &p_path); + + void _update_menu(); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + virtual void update_property(); + void setup(const String &p_base_type); + EditorPropertyResource(); +}; + +/////////////////////////////////////////////////// +/// \brief The EditorInspectorDefaultPlugin class +/// +class EditorInspectorDefaultPlugin : public EditorInspectorPlugin { + GDCLASS(EditorInspectorDefaultPlugin, EditorInspectorPlugin) + +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); + virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); + virtual void parse_end(); +}; + +#endif // EDITOR_PROPERTIES_H diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 68705fa29d..fe0392334c 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -383,6 +383,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/files/trim_trailing_whitespace_on_save", false); _initial_set("text_editor/completion/idle_parse_delay", 2); _initial_set("text_editor/tools/create_signal_callbacks", true); + _initial_set("text_editor/tools/sort_members_outline_alphabetically", false); _initial_set("text_editor/files/autosave_interval_secs", 0); _initial_set("text_editor/cursor/block_caret", false); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp new file mode 100644 index 0000000000..087dcd649f --- /dev/null +++ b/editor/editor_spin_slider.cpp @@ -0,0 +1,345 @@ +/*************************************************************************/ +/* editor_spin_slider.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_spin_slider.h" +#include "editor_scale.h" +#include "os/input.h" +String EditorSpinSlider::get_text_value() const { + int zeros = Math::step_decimals(get_step()); + return String::num(get_value(), zeros); +} +void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) { + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) { + + if (mb->is_pressed()) { + + if (updown_offset != -1 && mb->get_position().x > updown_offset) { + //there is an updown, so use it. + if (mb->get_position().y < get_size().height / 2) { + set_value(get_value() + get_step()); + } else { + set_value(get_value() - get_step()); + } + return; + } else { + + grabbing_spinner_attempt = true; + grabbing_spinner = false; + grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position(); + } + } else { + + if (grabbing_spinner_attempt) { + + if (grabbing_spinner) { + + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos); + update(); + } else { + Rect2 gr = get_global_rect(); + value_input->set_text(get_text_value()); + value_input->set_position(gr.position); + value_input->set_size(gr.size); + value_input->call_deferred("show_modal"); + value_input->call_deferred("grab_focus"); + value_input->call_deferred("select_all"); + } + + grabbing_spinner = false; + grabbing_spinner_attempt = false; + } + } + } + + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + + if (grabbing_spinner_attempt) { + + if (!grabbing_spinner) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + grabbing_spinner = true; + } + + double v = get_value(); + + double diff_x = mm->get_relative().x; + diff_x = Math::pow(ABS(diff_x), 1.8) * SGN(diff_x); + diff_x *= 0.1; + + v += diff_x * get_step(); + + set_value(v); + + } else if (updown_offset != -1) { + bool new_hover = (mm->get_position().x > updown_offset); + if (new_hover != hover_updown) { + hover_updown = new_hover; + update(); + } + } + } + + Ref<InputEventKey> k = p_event; + if (k.is_valid() && k->is_pressed() && k->is_action("ui_accept")) { + Rect2 gr = get_global_rect(); + value_input->set_text(get_text_value()); + value_input->set_position(gr.position); + value_input->set_size(gr.size); + value_input->call_deferred("show_modal"); + value_input->call_deferred("grab_focus"); + value_input->call_deferred("select_all"); + } +} + +void EditorSpinSlider::_value_input_closed() { + set_value(value_input->get_text().to_double()); +} + +void EditorSpinSlider::_value_input_entered(const String &p_text) { + set_value(p_text.to_double()); + value_input->hide(); +} + +void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) { + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) { + + if (mb->is_pressed()) { + + grabbing_grabber = true; + grabbing_ratio = get_as_ratio(); + grabbing_from = grabber->get_transform().xform(mb->get_position()).x; + } else { + grabbing_grabber = false; + } + } + + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid() && grabbing_grabber) { + + float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range); + set_as_ratio(grabbing_ratio + grabbing_ofs); + update(); + } +} + +void EditorSpinSlider::_notification(int p_what) { + + if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_OUT || p_what == MainLoop::NOTIFICATION_WM_FOCUS_OUT) { + if (grabbing_spinner) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + grabbing_spinner = false; + grabbing_spinner_attempt = false; + } + } + + if (p_what == NOTIFICATION_DRAW) { + + updown_offset = -1; + + Ref<StyleBox> sb = get_stylebox("normal", "LineEdit"); + draw_style_box(sb, Rect2(Vector2(), get_size())); + Ref<Font> font = get_font("font", "LineEdit"); + + int avail_width = get_size().width - sb->get_minimum_size().width - sb->get_minimum_size().width; + avail_width -= font->get_string_size(label).width; + Ref<Texture> updown = get_icon("updown", "SpinBox"); + + if (get_step() == 1) { + avail_width -= updown->get_width(); + } + + if (has_focus()) { + Ref<StyleBox> focus = get_stylebox("focus", "LineEdit"); + draw_style_box(focus, Rect2(Vector2(), get_size())); + } + + String numstr = get_text_value(); + + int vofs = (get_size().height - font->get_height()) / 2 + font->get_ascent(); + + Color fc = get_color("font_color", "LineEdit"); + + int label_ofs = sb->get_offset().x + avail_width; + draw_string(font, Vector2(label_ofs, vofs), label, fc * Color(1, 1, 1, 0.5)); + draw_string(font, Vector2(sb->get_offset().x, vofs), numstr, fc, avail_width); + + if (get_step() == 1) { + Ref<Texture> updown = get_icon("updown", "SpinBox"); + int updown_vofs = (get_size().height - updown->get_height()) / 2; + updown_offset = get_size().width - sb->get_margin(MARGIN_RIGHT) - updown->get_width(); + Color c(1, 1, 1); + if (hover_updown) { + c *= Color(1.2, 1.2, 1.2); + } + draw_texture(updown, Vector2(updown_offset, updown_vofs), c); + if (grabber->is_visible()) { + grabber->hide(); + } + } else if (!hide_slider) { + int grabber_w = 4 * EDSCALE; + int width = get_size().width - sb->get_minimum_size().width - grabber_w; + int ofs = sb->get_offset().x; + int svofs = (get_size().height + vofs) / 2 - 1; + Color c = fc; + c.a = 0.2; + + draw_rect(Rect2(ofs, svofs + 1, width, 2 * EDSCALE), c); + int gofs = get_as_ratio() * width; + c.a = 0.9; + Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE); + draw_rect(grabber_rect, c); + + bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner; + if (grabber->is_visible() != display_grabber) { + if (display_grabber) { + grabber->show(); + } else { + grabber->hide(); + } + } + + if (display_grabber) { + Ref<Texture> grabber_tex; + if (mouse_over_grabber) { + grabber_tex = get_icon("grabber_highlight", "HSlider"); + } else { + grabber_tex = get_icon("grabber", "HSlider"); + } + + if (grabber->get_texture() != grabber_tex) { + grabber->set_texture(grabber_tex); + } + + grabber->set_size(Size2(0, 0)); + grabber->set_position(get_global_position() + grabber_rect.position + grabber_rect.size * 0.5 - grabber->get_size() * 0.5); + grabber_range = width; + } + } + } + + if (p_what == NOTIFICATION_MOUSE_ENTER) { + + mouse_over_spin = true; + update(); + } + if (p_what == NOTIFICATION_MOUSE_EXIT) { + + mouse_over_spin = false; + update(); + } +} + +Size2 EditorSpinSlider::get_minimum_size() const { + + Ref<StyleBox> sb = get_stylebox("normal", "LineEdit"); + Ref<Font> font = get_font("font", "LineEdit"); + + Size2 ms = sb->get_minimum_size(); + ms.height += font->get_height(); + + return ms; +} + +void EditorSpinSlider::set_hide_slider(bool p_hide) { + hide_slider = p_hide; + update(); +} + +bool EditorSpinSlider::is_hiding_slider() const { + return hide_slider; +} + +void EditorSpinSlider::set_label(const String &p_label) { + label = p_label; + update(); +} + +String EditorSpinSlider::get_label() const { + return label; +} + +void EditorSpinSlider::_grabber_mouse_entered() { + mouse_over_grabber = true; + update(); +} + +void EditorSpinSlider::_grabber_mouse_exited() { + mouse_over_grabber = false; + update(); +} + +void EditorSpinSlider::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_label", "label"), &EditorSpinSlider::set_label); + ClassDB::bind_method(D_METHOD("get_label"), &EditorSpinSlider::get_label); + + ClassDB::bind_method(D_METHOD("_gui_input"), &EditorSpinSlider::_gui_input); + ClassDB::bind_method(D_METHOD("_grabber_mouse_entered"), &EditorSpinSlider::_grabber_mouse_entered); + ClassDB::bind_method(D_METHOD("_grabber_mouse_exited"), &EditorSpinSlider::_grabber_mouse_exited); + ClassDB::bind_method(D_METHOD("_grabber_gui_input"), &EditorSpinSlider::_grabber_gui_input); + ClassDB::bind_method(D_METHOD("_value_input_closed"), &EditorSpinSlider::_value_input_closed); + ClassDB::bind_method(D_METHOD("_value_input_entered"), &EditorSpinSlider::_value_input_entered); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label"); +} + +EditorSpinSlider::EditorSpinSlider() { + + grabbing_spinner_attempt = false; + grabbing_spinner = false; + + set_focus_mode(FOCUS_ALL); + updown_offset = -1; + hover_updown = false; + grabber = memnew(TextureRect); + add_child(grabber); + grabber->hide(); + grabber->set_as_toplevel(true); + grabber->set_mouse_filter(MOUSE_FILTER_STOP); + grabber->connect("mouse_entered", this, "_grabber_mouse_entered"); + grabber->connect("mouse_exited", this, "_grabber_mouse_exited"); + grabber->connect("gui_input", this, "_grabber_gui_input"); + mouse_over_spin = false; + mouse_over_grabber = false; + grabbing_grabber = false; + grabber_range = 1; + value_input = memnew(LineEdit); + add_child(value_input); + value_input->set_as_toplevel(true); + value_input->hide(); + value_input->connect("modal_closed", this, "_value_input_closed"); + value_input->connect("text_entered", this, "_value_input_entered"); + hide_slider = false; +} diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h new file mode 100644 index 0000000000..4956990dc2 --- /dev/null +++ b/editor/editor_spin_slider.h @@ -0,0 +1,87 @@ +/*************************************************************************/ +/* editor_spin_slider.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITOR_SPIN_SLIDER_H +#define EDITOR_SPIN_SLIDER_H + +#include "scene/gui/line_edit.h" +#include "scene/gui/range.h" +#include "scene/gui/texture_rect.h" + +class EditorSpinSlider : public Range { + GDCLASS(EditorSpinSlider, Range) + + String label; + int updown_offset; + bool hover_updown; + bool mouse_hover; + + TextureRect *grabber; + int grabber_range; + + bool mouse_over_spin; + bool mouse_over_grabber; + + bool grabbing_grabber; + int grabbing_from; + float grabbing_ratio; + + bool grabbing_spinner_attempt; + bool grabbing_spinner; + Vector2 grabbing_spinner_mouse_pos; + + LineEdit *value_input; + + void _grabber_gui_input(const Ref<InputEvent> &p_event); + void _value_input_closed(); + void _value_input_entered(const String &); + + bool hide_slider; + +protected: + void _notification(int p_what); + void _gui_input(const Ref<InputEvent> &p_event); + static void _bind_methods(); + void _grabber_mouse_entered(); + void _grabber_mouse_exited(); + +public: + String get_text_value() const; + void set_label(const String &p_label); + String get_label() const; + + void set_hide_slider(bool p_hide); + bool is_hiding_slider() const; + + virtual Size2 get_minimum_size() const; + EditorSpinSlider(); +}; + +#endif // EDITOR_SPIN_SLIDER_H diff --git a/editor/icons/icon_GUI_slider_grabber.svg b/editor/icons/icon_GUI_slider_grabber.svg index b1dcf980a5..b8e6f0a654 100644 --- a/editor/icons/icon_GUI_slider_grabber.svg +++ b/editor/icons/icon_GUI_slider_grabber.svg @@ -1,5 +1,82 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 15.999999" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<circle cx="8" cy="1044.4" r="3" fill="#fff" fill-opacity=".78431" stroke-linejoin="round" stroke-opacity=".39216" stroke-width="3"/> -</g> +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 15.999999" + id="svg8" + sodipodi:docname="icon_GUI_slider_grabber.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1211" + inkscape:window-height="644" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="-5.7627119" + inkscape:cy="8" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g6" /> + <g + transform="translate(0 -1036.4)" + id="g6"> + <path + transform="translate(0 1036.4)" + d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 2a5 5 0 0 1 0.5 0.025391 5 5 0 0 1 0.49414 0.074219 5 5 0 0 1 0.48438 0.12305 5 5 0 0 1 0.46875 0.17188 5 5 0 0 1 0.44922 0.2168 5 5 0 0 1 0.42578 0.26172 5 5 0 0 1 0.39844 0.30273 5 5 0 0 1 0.36524 0.33984 5 5 0 0 1 0.33008 0.37695 5 5 0 0 1 0.29102 0.40625 5 5 0 0 1 0.24805 0.43359 5 5 0 0 1 0.20508 0.45508 5 5 0 0 1 0.1582 0.47461 5 5 0 0 1 0.10938 0.48828 5 5 0 0 1 0.060547 0.49609 5 5 0 0 1 0.011719 0.35352 5 5 0 0 1 -0.025391 0.5 5 5 0 0 1 -0.074218 0.49414 5 5 0 0 1 -0.12305 0.48438 5 5 0 0 1 -0.17188 0.46875 5 5 0 0 1 -0.2168 0.44922 5 5 0 0 1 -0.26172 0.42578 5 5 0 0 1 -0.30273 0.39844 5 5 0 0 1 -0.33984 0.36524 5 5 0 0 1 -0.37695 0.33008 5 5 0 0 1 -0.40625 0.29102 5 5 0 0 1 -0.43359 0.24805 5 5 0 0 1 -0.45508 0.20508 5 5 0 0 1 -0.47461 0.1582 5 5 0 0 1 -0.48828 0.10938 5 5 0 0 1 -0.49609 0.060547 5 5 0 0 1 -0.35352 0.011719 5 5 0 0 1 -0.5 -0.025391 5 5 0 0 1 -0.49414 -0.074218 5 5 0 0 1 -0.48438 -0.12305 5 5 0 0 1 -0.46875 -0.17188 5 5 0 0 1 -0.44922 -0.2168 5 5 0 0 1 -0.42578 -0.26172 5 5 0 0 1 -0.39844 -0.30273 5 5 0 0 1 -0.36523 -0.33984 5 5 0 0 1 -0.33008 -0.37695 5 5 0 0 1 -0.29102 -0.40625 5 5 0 0 1 -0.24805 -0.43359 5 5 0 0 1 -0.20508 -0.45508 5 5 0 0 1 -0.1582 -0.47461 5 5 0 0 1 -0.10938 -0.48828 5 5 0 0 1 -0.060547 -0.49609 5 5 0 0 1 -0.011719 -0.35352 5 5 0 0 1 0.025391 -0.5 5 5 0 0 1 0.074219 -0.49414 5 5 0 0 1 0.12305 -0.48438 5 5 0 0 1 0.17188 -0.46875 5 5 0 0 1 0.2168 -0.44922 5 5 0 0 1 0.26172 -0.42578 5 5 0 0 1 0.30273 -0.39844 5 5 0 0 1 0.33984 -0.36523 5 5 0 0 1 0.37695 -0.33008 5 5 0 0 1 0.40625 -0.29102 5 5 0 0 1 0.43359 -0.24805 5 5 0 0 1 0.45508 -0.20508 5 5 0 0 1 0.47461 -0.1582 5 5 0 0 1 0.48828 -0.10938 5 5 0 0 1 0.49609 -0.060547 5 5 0 0 1 0.35352 -0.011719z" + fill="#e0e0e0" + id="path2" + style="fill:#e0e0e0;fill-opacity:0.28925619" /> + <circle + cx="8" + cy="1044.4" + r="3" + fill="#fff" + fill-opacity=".58824" + stroke-linecap="round" + stroke-linejoin="round" + stroke-opacity=".32549" + stroke-width="3" + id="circle4" /> + </g> + <g + transform="translate(-0.06779632,-1036.4)" + id="g18"> + <circle + style="fill:#ffffff;fill-opacity:0.78430996;stroke-width:3;stroke-linejoin:round;stroke-opacity:0.39216003" + cx="8" + cy="1044.4" + r="3" + id="circle16" /> + </g> </svg> diff --git a/editor/icons/icon_GUI_slider_grabber_hl.svg b/editor/icons/icon_GUI_slider_grabber_hl.svg index 73252751ce..a04ac44cf6 100644 --- a/editor/icons/icon_GUI_slider_grabber_hl.svg +++ b/editor/icons/icon_GUI_slider_grabber_hl.svg @@ -1,6 +1,80 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 15.999999" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 2a5 5 0 0 1 0.5 0.025391 5 5 0 0 1 0.49414 0.074219 5 5 0 0 1 0.48438 0.12305 5 5 0 0 1 0.46875 0.17188 5 5 0 0 1 0.44922 0.2168 5 5 0 0 1 0.42578 0.26172 5 5 0 0 1 0.39844 0.30273 5 5 0 0 1 0.36524 0.33984 5 5 0 0 1 0.33008 0.37695 5 5 0 0 1 0.29102 0.40625 5 5 0 0 1 0.24805 0.43359 5 5 0 0 1 0.20508 0.45508 5 5 0 0 1 0.1582 0.47461 5 5 0 0 1 0.10938 0.48828 5 5 0 0 1 0.060547 0.49609 5 5 0 0 1 0.011719 0.35352 5 5 0 0 1 -0.025391 0.5 5 5 0 0 1 -0.074218 0.49414 5 5 0 0 1 -0.12305 0.48438 5 5 0 0 1 -0.17188 0.46875 5 5 0 0 1 -0.2168 0.44922 5 5 0 0 1 -0.26172 0.42578 5 5 0 0 1 -0.30273 0.39844 5 5 0 0 1 -0.33984 0.36524 5 5 0 0 1 -0.37695 0.33008 5 5 0 0 1 -0.40625 0.29102 5 5 0 0 1 -0.43359 0.24805 5 5 0 0 1 -0.45508 0.20508 5 5 0 0 1 -0.47461 0.1582 5 5 0 0 1 -0.48828 0.10938 5 5 0 0 1 -0.49609 0.060547 5 5 0 0 1 -0.35352 0.011719 5 5 0 0 1 -0.5 -0.025391 5 5 0 0 1 -0.49414 -0.074218 5 5 0 0 1 -0.48438 -0.12305 5 5 0 0 1 -0.46875 -0.17188 5 5 0 0 1 -0.44922 -0.2168 5 5 0 0 1 -0.42578 -0.26172 5 5 0 0 1 -0.39844 -0.30273 5 5 0 0 1 -0.36523 -0.33984 5 5 0 0 1 -0.33008 -0.37695 5 5 0 0 1 -0.29102 -0.40625 5 5 0 0 1 -0.24805 -0.43359 5 5 0 0 1 -0.20508 -0.45508 5 5 0 0 1 -0.1582 -0.47461 5 5 0 0 1 -0.10938 -0.48828 5 5 0 0 1 -0.060547 -0.49609 5 5 0 0 1 -0.011719 -0.35352 5 5 0 0 1 0.025391 -0.5 5 5 0 0 1 0.074219 -0.49414 5 5 0 0 1 0.12305 -0.48438 5 5 0 0 1 0.17188 -0.46875 5 5 0 0 1 0.2168 -0.44922 5 5 0 0 1 0.26172 -0.42578 5 5 0 0 1 0.30273 -0.39844 5 5 0 0 1 0.33984 -0.36523 5 5 0 0 1 0.37695 -0.33008 5 5 0 0 1 0.40625 -0.29102 5 5 0 0 1 0.43359 -0.24805 5 5 0 0 1 0.45508 -0.20508 5 5 0 0 1 0.47461 -0.1582 5 5 0 0 1 0.48828 -0.10938 5 5 0 0 1 0.49609 -0.060547 5 5 0 0 1 0.35352 -0.011719z" fill="#e0e0e0"/> -<circle cx="8" cy="1044.4" r="3" fill="#fff" fill-opacity=".58824" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".32549" stroke-width="3"/> -</g> +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 15.999999" + id="svg8" + sodipodi:docname="icon_GUI_slider_grabber_hl.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="944" + inkscape:window-height="480" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="8" + inkscape:cy="8" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(0 -1036.4)" + id="g6"> + <path + transform="translate(0 1036.4)" + d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 2a5 5 0 0 1 0.5 0.025391 5 5 0 0 1 0.49414 0.074219 5 5 0 0 1 0.48438 0.12305 5 5 0 0 1 0.46875 0.17188 5 5 0 0 1 0.44922 0.2168 5 5 0 0 1 0.42578 0.26172 5 5 0 0 1 0.39844 0.30273 5 5 0 0 1 0.36524 0.33984 5 5 0 0 1 0.33008 0.37695 5 5 0 0 1 0.29102 0.40625 5 5 0 0 1 0.24805 0.43359 5 5 0 0 1 0.20508 0.45508 5 5 0 0 1 0.1582 0.47461 5 5 0 0 1 0.10938 0.48828 5 5 0 0 1 0.060547 0.49609 5 5 0 0 1 0.011719 0.35352 5 5 0 0 1 -0.025391 0.5 5 5 0 0 1 -0.074218 0.49414 5 5 0 0 1 -0.12305 0.48438 5 5 0 0 1 -0.17188 0.46875 5 5 0 0 1 -0.2168 0.44922 5 5 0 0 1 -0.26172 0.42578 5 5 0 0 1 -0.30273 0.39844 5 5 0 0 1 -0.33984 0.36524 5 5 0 0 1 -0.37695 0.33008 5 5 0 0 1 -0.40625 0.29102 5 5 0 0 1 -0.43359 0.24805 5 5 0 0 1 -0.45508 0.20508 5 5 0 0 1 -0.47461 0.1582 5 5 0 0 1 -0.48828 0.10938 5 5 0 0 1 -0.49609 0.060547 5 5 0 0 1 -0.35352 0.011719 5 5 0 0 1 -0.5 -0.025391 5 5 0 0 1 -0.49414 -0.074218 5 5 0 0 1 -0.48438 -0.12305 5 5 0 0 1 -0.46875 -0.17188 5 5 0 0 1 -0.44922 -0.2168 5 5 0 0 1 -0.42578 -0.26172 5 5 0 0 1 -0.39844 -0.30273 5 5 0 0 1 -0.36523 -0.33984 5 5 0 0 1 -0.33008 -0.37695 5 5 0 0 1 -0.29102 -0.40625 5 5 0 0 1 -0.24805 -0.43359 5 5 0 0 1 -0.20508 -0.45508 5 5 0 0 1 -0.1582 -0.47461 5 5 0 0 1 -0.10938 -0.48828 5 5 0 0 1 -0.060547 -0.49609 5 5 0 0 1 -0.011719 -0.35352 5 5 0 0 1 0.025391 -0.5 5 5 0 0 1 0.074219 -0.49414 5 5 0 0 1 0.12305 -0.48438 5 5 0 0 1 0.17188 -0.46875 5 5 0 0 1 0.2168 -0.44922 5 5 0 0 1 0.26172 -0.42578 5 5 0 0 1 0.30273 -0.39844 5 5 0 0 1 0.33984 -0.36523 5 5 0 0 1 0.37695 -0.33008 5 5 0 0 1 0.40625 -0.29102 5 5 0 0 1 0.43359 -0.24805 5 5 0 0 1 0.45508 -0.20508 5 5 0 0 1 0.47461 -0.1582 5 5 0 0 1 0.48828 -0.10938 5 5 0 0 1 0.49609 -0.060547 5 5 0 0 1 0.35352 -0.011719z" + fill="#e0e0e0" + id="path2" /> + <circle + cx="8" + cy="1044.4" + r="3" + fill="#fff" + fill-opacity=".58824" + stroke-linecap="round" + stroke-linejoin="round" + stroke-opacity=".32549" + stroke-width="3" + id="circle4" /> + </g> + <g + transform="translate(-0.06779632,-1036.4)" + id="g18"> + <circle + style="fill:#ffffff;fill-opacity:0.78430996;stroke-width:3;stroke-linejoin:round;stroke-opacity:0.39216003" + cx="8" + cy="1044.4" + r="3" + id="circle16" /> + </g> </svg> diff --git a/editor/import/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp index a5d3959952..7b330936f6 100644 --- a/editor/import/resource_importer_bitmask.cpp +++ b/editor/import/resource_importer_bitmask.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* resource_importer_bitmask.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "resource_importer_bitmask.h" #include "core/image.h" #include "editor/editor_file_system.h" diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h index 8a3cafa7ce..f3537df819 100644 --- a/editor/import/resource_importer_bitmask.h +++ b/editor/import/resource_importer_bitmask.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* resource_importer_bitmask.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 RESOURCE_IMPORTER_BITMASK_H #define RESOURCE_IMPORTER_BITMASK_H diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp index 73e78ddf2a..173be01586 100644 --- a/editor/multi_node_edit.cpp +++ b/editor/multi_node_edit.cpp @@ -80,8 +80,8 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, ur->add_undo_property(n, name, n->get(name)); } - ur->add_do_method(EditorNode::get_singleton()->get_property_editor(), "refresh"); - ur->add_undo_method(EditorNode::get_singleton()->get_property_editor(), "refresh"); + ur->add_do_method(EditorNode::get_singleton()->get_inspector(), "refresh"); + ur->add_undo_method(EditorNode::get_singleton()->get_inspector(), "refresh"); ur->commit_action(); return true; diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index b387972558..23c5e36a92 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -85,7 +85,7 @@ void AnimationPlayerEditor::_notification(int p_what) { } frame->set_value(player->get_current_animation_position()); key_editor->set_anim_pos(player->get_current_animation_position()); - EditorNode::get_singleton()->get_property_editor()->refresh(); + EditorNode::get_singleton()->get_inspector()->refresh(); } else if (last_active) { //need the last frame after it stopped @@ -1073,7 +1073,7 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) updating = false; _seek_value_changed(p_pos, !p_drag); - EditorNode::get_singleton()->get_property_editor()->refresh(); + EditorNode::get_singleton()->get_inspector()->refresh(); //seekit } diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 0ff316a286..d21c84eb61 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -936,41 +936,43 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int if (to > p_page_count) to = p_page_count; - Color gray = Color(0.65, 0.65, 0.65); - hbc->add_spacer(); - hbc->add_constant_override("separation", 10); + hbc->add_constant_override("separation", 5); + Button *first = memnew(Button); + first->set_text(TTR("First")); if (p_page != 0) { - LinkButton *first = memnew(LinkButton); - first->set_text(TTR("first")); - first->add_color_override("font_color", gray); - first->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); first->connect("pressed", this, "_search", varray(0)); - hbc->add_child(first); + } else { + first->set_disabled(true); + first->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(first); + Button *prev = memnew(Button); + prev->set_text(TTR("Previous")); if (p_page > 0) { - LinkButton *prev = memnew(LinkButton); - prev->set_text(TTR("prev")); - prev->add_color_override("font_color", gray); - prev->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); prev->connect("pressed", this, "_search", varray(p_page - 1)); - hbc->add_child(prev); + } else { + prev->set_disabled(true); + prev->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(prev); + hbc->add_child(memnew(VSeparator)); for (int i = from; i < to; i++) { if (i == p_page) { - Label *current = memnew(Label); + Button *current = memnew(Button); current->set_text(itos(i + 1)); + current->set_disabled(true); + current->set_focus_mode(Control::FOCUS_NONE); + hbc->add_child(current); } else { - LinkButton *current = memnew(LinkButton); - current->add_color_override("font_color", gray); - current->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); + Button *current = memnew(Button); current->set_text(itos(i + 1)); current->connect("pressed", this, "_search", varray(i)); @@ -978,28 +980,26 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int } } + Button *next = memnew(Button); + next->set_text(TTR("Next")); if (p_page < p_page_count - 1) { - LinkButton *next = memnew(LinkButton); - next->set_text(TTR("next")); - next->add_color_override("font_color", gray); - next->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); next->connect("pressed", this, "_search", varray(p_page + 1)); - - hbc->add_child(next); + } else { + next->set_disabled(true); + next->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(memnew(VSeparator)); + hbc->add_child(next); + Button *last = memnew(Button); + last->set_text(TTR("Last")); if (p_page != p_page_count - 1) { - LinkButton *last = memnew(LinkButton); - last->set_text(TTR("last")); - last->add_color_override("font_color", gray); - last->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - hbc->add_child(last); last->connect("pressed", this, "_search", varray(p_page_count - 1)); + } else { + last->set_disabled(true); + last->set_focus_mode(Control::FOCUS_NONE); } - - Label *totals = memnew(Label); - totals->set_text("( " + itos(from * p_page_len) + " - " + itos(from * p_page_len + p_current_items - 1) + " / " + itos(p_total_items) + " )"); - hbc->add_child(totals); + hbc->add_child(last); hbc->add_spacer(); diff --git a/editor/plugins/cube_grid_theme_editor_plugin.cpp b/editor/plugins/cube_grid_theme_editor_plugin.cpp index 81f45b9f55..68d5ea5247 100644 --- a/editor/plugins/cube_grid_theme_editor_plugin.cpp +++ b/editor/plugins/cube_grid_theme_editor_plugin.cpp @@ -198,7 +198,7 @@ void MeshLibraryEditor::_menu_cbk(int p_option) { } break; case MENU_OPTION_REMOVE_ITEM: { - String p = editor->get_property_editor()->get_selected_path(); + String p = editor->get_inspector()->get_selected_path(); if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) { to_erase = p.get_slice("/", 3).to_int(); diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp index 8b44f672b0..f75fb0d109 100644 --- a/editor/plugins/item_list_editor_plugin.cpp +++ b/editor/plugins/item_list_editor_plugin.cpp @@ -388,7 +388,7 @@ ItemListEditor::ItemListEditor() { vbc->add_child(property_editor); property_editor->set_v_size_flags(SIZE_EXPAND_FILL); - tree = property_editor->get_scene_tree(); + tree = property_editor->get_property_tree(); } ItemListEditor::~ItemListEditor() { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index fa674e1e34..ac250f085d 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1182,6 +1182,7 @@ void ScriptEditor::_notification(int p_what) { script_forward->set_icon(get_icon("Forward", "EditorIcons")); script_back->set_icon(get_icon("Back", "EditorIcons")); + members_overview_alphabeta_sort_button->set_icon(get_icon("Sort", "EditorIcons")); } break; case NOTIFICATION_READY: { @@ -1408,12 +1409,19 @@ void ScriptEditor::_update_members_overview_visibility() { } if (members_overview_enabled && se->show_members_overview()) { + members_overview_buttons_hbox->set_visible(true); members_overview->set_visible(true); } else { + members_overview_buttons_hbox->set_visible(false); members_overview->set_visible(false); } } +void ScriptEditor::_toggle_members_overview_alpha_sort(bool p_alphabetic_sort) { + EditorSettings::get_singleton()->set("text_editor/tools/sort_members_outline_alphabetically", p_alphabetic_sort); + _update_members_overview(); +} + void ScriptEditor::_update_members_overview() { members_overview->clear(); @@ -1423,6 +1431,10 @@ void ScriptEditor::_update_members_overview() { } Vector<String> functions = se->get_functions(); + if (EditorSettings::get_singleton()->get("text_editor/tools/sort_members_outline_alphabetically")) { + functions.sort(); + } + for (int i = 0; i < functions.size(); i++) { members_overview->add_item(functions[i].get_slice(":", 0)); members_overview->set_item_metadata(i, functions[i].get_slice(":", 1).to_int() - 1); @@ -1445,6 +1457,7 @@ void ScriptEditor::_update_help_overview_visibility() { } if (help_overview_enabled) { + members_overview_buttons_hbox->set_visible(false); help_overview->set_visible(true); } else { help_overview->set_visible(false); @@ -2596,6 +2609,8 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts); ClassDB::bind_method("_unhandled_input", &ScriptEditor::_unhandled_input); ClassDB::bind_method("_script_list_gui_input", &ScriptEditor::_script_list_gui_input); + ClassDB::bind_method("_toggle_members_overview_alpha_sort", &ScriptEditor::_toggle_members_overview_alpha_sort); + ClassDB::bind_method("_update_members_overview", &ScriptEditor::_update_members_overview); ClassDB::bind_method("_script_changed", &ScriptEditor::_script_changed); ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts); ClassDB::bind_method("_on_find_in_files_requested", &ScriptEditor::_on_find_in_files_requested); @@ -2656,14 +2671,33 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { add_child(context_menu); context_menu->connect("id_pressed", this, "_menu_option"); + members_overview_vbox = memnew(VBoxContainer); + members_overview_vbox->set_custom_minimum_size(Size2(0, 90)); + members_overview_vbox->set_v_size_flags(SIZE_EXPAND_FILL); + + list_split->add_child(members_overview_vbox); + members_overview_buttons_hbox = memnew(HBoxContainer); + members_overview_vbox->add_child(members_overview_buttons_hbox); + + members_overview_alphabeta_sort_button = memnew(ToolButton); + members_overview_alphabeta_sort_button->set_tooltip(TTR("Sort alphabetically")); + members_overview_alphabeta_sort_button->set_toggle_mode(true); + members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/tools/sort_members_outline_alphabetically")); + members_overview_alphabeta_sort_button->connect("toggled", this, "_toggle_members_overview_alpha_sort"); + + members_overview_buttons_hbox->add_child(members_overview_alphabeta_sort_button); + members_overview = memnew(ItemList); - list_split->add_child(members_overview); + members_overview_vbox->add_child(members_overview); + members_overview->set_allow_reselect(true); members_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing members_overview->set_v_size_flags(SIZE_EXPAND_FILL); + members_overview->set_allow_rmb_select(true); + members_overview->set_drag_forwarding(this); help_overview = memnew(ItemList); - list_split->add_child(help_overview); + members_overview_vbox->add_child(help_overview); help_overview->set_allow_reselect(true); help_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing help_overview->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 9f37b18d7d..a2ff47cd99 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -199,6 +199,9 @@ class ScriptEditor : public PanelContainer { ItemList *script_list; HSplitContainer *script_split; ItemList *members_overview; + VBoxContainer *members_overview_vbox; + HBoxContainer *members_overview_buttons_hbox; + ToolButton *members_overview_alphabeta_sort_button; bool members_overview_enabled; ItemList *help_overview; bool help_overview_enabled; @@ -318,6 +321,7 @@ class ScriptEditor : public PanelContainer { void _update_members_overview_visibility(); void _update_members_overview(); + void _toggle_members_overview_alpha_sort(bool p_alphabetic_sort); void _update_script_names(); bool _sort_list_on_update; diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index e372f792d6..08bfebefbd 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skeleton_2d_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "skeleton_2d_editor_plugin.h" #include "canvas_item_editor_plugin.h" diff --git a/editor/plugins/skeleton_2d_editor_plugin.h b/editor/plugins/skeleton_2d_editor_plugin.h index bbe2a3a6f2..26ab4328b0 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.h +++ b/editor/plugins/skeleton_2d_editor_plugin.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skeleton_2d_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 SKELETON_2D_EDITOR_PLUGIN_H #define SKELETON_2D_EDITOR_PLUGIN_H diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index 49816fe2ae..66673cca00 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* sprite_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "sprite_editor_plugin.h" #include "canvas_item_editor_plugin.h" diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_editor_plugin.h index 17aa3eb1f9..238227e4a0 100644 --- a/editor/plugins/sprite_editor_plugin.h +++ b/editor/plugins/sprite_editor_plugin.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* sprite_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 SPRITE_EDITOR_PLUGIN_H #define SPRITE_EDITOR_PLUGIN_H diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index a4265b4e32..82fd727620 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -785,7 +785,7 @@ void ProjectSettingsEditor::popup_project_settings() { void ProjectSettingsEditor::_item_selected() { - TreeItem *ti = globals_editor->get_property_editor()->get_scene_tree()->get_selected(); + TreeItem *ti = globals_editor->get_property_editor()->get_property_tree()->get_selected(); if (!ti) return; if (!ti->get_parent()) @@ -1727,7 +1727,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { //globals_editor->hide_top_label(); globals_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); globals_editor->register_search_box(search_box); - globals_editor->get_property_editor()->get_scene_tree()->connect("cell_selected", this, "_item_selected"); + globals_editor->get_property_editor()->get_property_tree()->connect("cell_selected", this, "_item_selected"); globals_editor->get_property_editor()->connect("property_toggled", this, "_item_checked", varray(), CONNECT_DEFERRED); globals_editor->get_property_editor()->connect("property_edited", this, "_settings_prop_edited"); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index e0063925b1..e912ebe03a 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -4212,7 +4212,7 @@ void PropertyEditor::_bind_methods() { ADD_SIGNAL(MethodInfo("property_edited", PropertyInfo(Variant::STRING, "property"))); } -Tree *PropertyEditor::get_scene_tree() { +Tree *PropertyEditor::get_property_tree() { return tree; } @@ -4695,7 +4695,7 @@ SectionedPropertyEditor::SectionedPropertyEditor() { editor->set_v_size_flags(SIZE_EXPAND_FILL); right_vb->add_child(editor, true); - editor->get_scene_tree()->set_column_titles_visible(false); + editor->get_property_tree()->set_column_titles_visible(false); editor->hide_top_label(); diff --git a/editor/property_editor.h b/editor/property_editor.h index 017a190adb..56743822d2 100644 --- a/editor/property_editor.h +++ b/editor/property_editor.h @@ -275,7 +275,7 @@ public: String get_selected_path() const; - Tree *get_scene_tree(); + Tree *get_property_tree(); Label *get_top_label(); void hide_top_label(); void update_tree(); @@ -309,6 +309,7 @@ public: void collapse_all_folding(); void expand_all_folding(); + PropertyEditor(); ~PropertyEditor(); }; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 8b99a3d503..f5cee4cd65 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -732,7 +732,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (node) { node->set_scene_inherited_state(Ref<SceneState>()); scene_tree->update_tree(); - EditorNode::get_singleton()->get_property_editor()->update_tree(); + EditorNode::get_singleton()->get_inspector()->update_tree(); } } } break; diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 64d278c0c5..dd79ae63d6 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -70,8 +70,18 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i } else if (p_id == BUTTON_VISIBILITY) { undo_redo->create_action(TTR("Toggle Visible")); - undo_redo->add_do_method(this, "toggle_visible", n); - undo_redo->add_undo_method(this, "toggle_visible", n); + _toggle_visible(n); + List<Node *> selection = editor_selection->get_selected_node_list(); + if (selection.size() > 1) { + for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { + Node *nv = E->get(); + ERR_FAIL_COND(!nv); + if (nv == n) { + continue; + } + _toggle_visible(nv); + } + } undo_redo->commit_action(); } else if (p_id == BUTTON_LOCK) { @@ -118,33 +128,13 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i } } void SceneTreeEditor::_toggle_visible(Node *p_node) { - if (p_node->is_class("Spatial")) { - bool v = bool(p_node->call("is_visible")); - p_node->call("set_visible", !v); - } else if (p_node->is_class("CanvasItem")) { + if (p_node->has_method("is_visible") && p_node->has_method("set_visible")) { bool v = bool(p_node->call("is_visible")); - if (v) { - p_node->call("hide"); - } else { - p_node->call("show"); - } + undo_redo->add_do_method(p_node, "set_visible", !v); + undo_redo->add_undo_method(p_node, "set_visible", v); } } -void SceneTreeEditor::toggle_visible(Node *p_node) { - _toggle_visible(p_node); - List<Node *> selection = editor_selection->get_selected_node_list(); - if (selection.size() > 1) { - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - Node *nv = E->get(); - ERR_FAIL_COND(!nv); - if (nv == p_node) { - continue; - } - _toggle_visible(nv); - } - } -} bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { if (!p_node) @@ -968,8 +958,6 @@ void SceneTreeEditor::_bind_methods() { ClassDB::bind_method("_cell_collapsed", &SceneTreeEditor::_cell_collapsed); ClassDB::bind_method("_rmb_select", &SceneTreeEditor::_rmb_select); ClassDB::bind_method("_warning_changed", &SceneTreeEditor::_warning_changed); - ClassDB::bind_method("_toggle_visible", &SceneTreeEditor::_toggle_visible); - ClassDB::bind_method("toggle_visible", &SceneTreeEditor::toggle_visible); ClassDB::bind_method("_node_script_changed", &SceneTreeEditor::_node_script_changed); ClassDB::bind_method("_node_visibility_changed", &SceneTreeEditor::_node_visibility_changed); diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index b63eb2a1f0..896fd6c431 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -70,8 +70,6 @@ class SceneTreeEditor : public Control { void _compute_hash(Node *p_node, uint64_t &hash); - void toggle_visible(Node *p_node); - bool _add_nodes(Node *p_node, TreeItem *p_parent); void _test_update_tree(); void _update_tree(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index a83de1627d..9ce4305683 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1851,7 +1851,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { ppeer = Ref<PacketPeerStream>(memnew(PacketPeerStream)); ppeer->set_input_buffer_max_size(1024 * 1024 * 8); //8mb should be enough editor = p_editor; - editor->get_property_editor()->connect("object_id_selected", this, "_scene_tree_property_select_object"); + editor->get_inspector()->connect("object_id_selected", this, "_scene_tree_property_select_object"); tabs = memnew(TabContainer); tabs->set_tab_align(TabContainer::ALIGN_LEFT); @@ -1936,7 +1936,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { inspector = memnew(PropertyEditor); inspector->set_h_size_flags(SIZE_EXPAND_FILL); inspector->hide_top_label(); - inspector->get_scene_tree()->set_column_title(0, TTR("Variable")); + inspector->get_property_tree()->set_column_title(0, TTR("Variable")); inspector->set_enable_capitalize_paths(false); inspector->set_read_only(true); inspector->connect("object_id_selected", this, "_scene_tree_property_select_object"); diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index 61d67d7089..687c517180 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -3261,19 +3261,19 @@ msgid "Download for this asset is already in progress!" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -msgid "first" +msgid "First" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -msgid "prev" +msgid "Previous" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -msgid "next" +msgid "Next" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -msgid "last" +msgid "Last" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp diff --git a/main/main.cpp b/main/main.cpp index 92b4e31679..c287bc81cb 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -82,6 +82,8 @@ #include "version.h" #include "version_hash.gen.h" +#include "main/timer_sync.h" + static ProjectSettings *globals = NULL; static Engine *engine = NULL; static InputMap *input_map = NULL; @@ -1221,227 +1223,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) { } // everything the main loop needs to know about frame timings -struct _FrameTime { - float animation_step; // time to advance animations for (argument to process()) - int physics_steps; // number of times to iterate the physics engine - - void clamp_animation(float min_animation_step, float max_animation_step) { - if (animation_step < min_animation_step) { - animation_step = min_animation_step; - } else if (animation_step > max_animation_step) { - animation_step = max_animation_step; - } - } -}; - -class _TimerSync { - // wall clock time measured on the main thread - uint64_t last_cpu_ticks_usec; - uint64_t current_cpu_ticks_usec; - - // logical game time since last physics timestep - float time_accum; - - // current difference between wall clock time and reported sum of animation_steps - float time_deficit; - - // number of frames back for keeping accumulated physics steps roughly constant. - // value of 12 chosen because that is what is required to make 144 Hz monitors - // behave well with 60 Hz physics updates. The only worse commonly available refresh - // would be 85, requiring CONTROL_STEPS = 17. - static const int CONTROL_STEPS = 12; - - // sum of physics steps done over the last (i+1) frames - int accumulated_physics_steps[CONTROL_STEPS]; - - // typical value for accumulated_physics_steps[i] is either this or this plus one - int typical_physics_steps[CONTROL_STEPS]; - -protected: - // returns the fraction of p_frame_slice required for the timer to overshoot - // before advance_core considers changing the physics_steps return from - // the typical values as defined by typical_physics_steps - float get_physics_jitter_fix() { - return Engine::get_singleton()->get_physics_jitter_fix(); - } - - // gets our best bet for the average number of physics steps per render frame - // return value: number of frames back this data is consistent - int get_average_physics_steps(float &p_min, float &p_max) { - p_min = typical_physics_steps[0]; - p_max = p_min + 1; - - for (int i = 1; i < CONTROL_STEPS; ++i) { - const float typical_lower = typical_physics_steps[i]; - const float current_min = typical_lower / (i + 1); - if (current_min > p_max) - return i; // bail out of further restrictions would void the interval - else if (current_min > p_min) - p_min = current_min; - const float current_max = (typical_lower + 1) / (i + 1); - if (current_max < p_min) - return i; - else if (current_max < p_max) - p_max = current_max; - } - - return CONTROL_STEPS; - } - - // advance physics clock by p_animation_step, return appropriate number of steps to simulate - _FrameTime advance_core(float p_frame_slice, int p_iterations_per_second, float p_animation_step) { - _FrameTime ret; - - ret.animation_step = p_animation_step; - - // simple determination of number of physics iteration - time_accum += ret.animation_step; - ret.physics_steps = floor(time_accum * p_iterations_per_second); - - int min_typical_steps = typical_physics_steps[0]; - int max_typical_steps = min_typical_steps + 1; - - // given the past recorded steps and typcial steps to match, calculate bounds for this - // step to be typical - bool update_typical = false; - - for (int i = 0; i < CONTROL_STEPS - 1; ++i) { - int steps_left_to_match_typical = typical_physics_steps[i + 1] - accumulated_physics_steps[i]; - if (steps_left_to_match_typical > max_typical_steps || - steps_left_to_match_typical + 1 < min_typical_steps) { - update_typical = true; - break; - } - - if (steps_left_to_match_typical > min_typical_steps) - min_typical_steps = steps_left_to_match_typical; - if (steps_left_to_match_typical + 1 < max_typical_steps) - max_typical_steps = steps_left_to_match_typical + 1; - } - - // try to keep it consistent with previous iterations - if (ret.physics_steps < min_typical_steps) { - const int max_possible_steps = floor((time_accum)*p_iterations_per_second + get_physics_jitter_fix()); - if (max_possible_steps < min_typical_steps) { - ret.physics_steps = max_possible_steps; - update_typical = true; - } else { - ret.physics_steps = min_typical_steps; - } - } else if (ret.physics_steps > max_typical_steps) { - const int min_possible_steps = floor((time_accum)*p_iterations_per_second - get_physics_jitter_fix()); - if (min_possible_steps > max_typical_steps) { - ret.physics_steps = min_possible_steps; - update_typical = true; - } else { - ret.physics_steps = max_typical_steps; - } - } - - time_accum -= ret.physics_steps * p_frame_slice; - - // keep track of accumulated step counts - for (int i = CONTROL_STEPS - 2; i >= 0; --i) { - accumulated_physics_steps[i + 1] = accumulated_physics_steps[i] + ret.physics_steps; - } - accumulated_physics_steps[0] = ret.physics_steps; - - if (update_typical) { - for (int i = CONTROL_STEPS - 1; i >= 0; --i) { - if (typical_physics_steps[i] > accumulated_physics_steps[i]) { - typical_physics_steps[i] = accumulated_physics_steps[i]; - } else if (typical_physics_steps[i] < accumulated_physics_steps[i] - 1) { - typical_physics_steps[i] = accumulated_physics_steps[i] - 1; - } - } - } - - return ret; - } - - // calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero - _FrameTime advance_checked(float p_frame_slice, int p_iterations_per_second, float p_animation_step) { - if (fixed_fps != -1) - p_animation_step = 1.0 / fixed_fps; - - // compensate for last deficit - p_animation_step += time_deficit; - - _FrameTime ret = advance_core(p_frame_slice, p_iterations_per_second, p_animation_step); - - // we will do some clamping on ret.animation_step and need to sync those changes to time_accum, - // that's easiest if we just remember their fixed difference now - const double animation_minus_accum = ret.animation_step - time_accum; - - // first, least important clamping: keep ret.animation_step consistent with typical_physics_steps. - // this smoothes out the animation steps and culls small but quick variations. - { - float min_average_physics_steps, max_average_physics_steps; - int consistent_steps = get_average_physics_steps(min_average_physics_steps, max_average_physics_steps); - if (consistent_steps > 3) { - ret.clamp_animation(min_average_physics_steps * p_frame_slice, max_average_physics_steps * p_frame_slice); - } - } - - // second clamping: keep abs(time_deficit) < jitter_fix * frame_slise - float max_clock_deviation = get_physics_jitter_fix() * p_frame_slice; - ret.clamp_animation(p_animation_step - max_clock_deviation, p_animation_step + max_clock_deviation); - - // last clamping: make sure time_accum is between 0 and p_frame_slice for consistency between physics and animation - ret.clamp_animation(animation_minus_accum, animation_minus_accum + p_frame_slice); - - // restore time_accum - time_accum = ret.animation_step - animation_minus_accum; - - // track deficit - time_deficit = p_animation_step - ret.animation_step; - - return ret; - } - - // determine wall clock step since last iteration - float get_cpu_animation_step() { - uint64_t cpu_ticks_elapsed = current_cpu_ticks_usec - last_cpu_ticks_usec; - last_cpu_ticks_usec = current_cpu_ticks_usec; - - return cpu_ticks_elapsed / 1000000.0; - } - -public: - explicit _TimerSync() : - last_cpu_ticks_usec(0), - current_cpu_ticks_usec(0), - time_accum(0), - time_deficit(0) { - for (int i = CONTROL_STEPS - 1; i >= 0; --i) { - typical_physics_steps[i] = i; - accumulated_physics_steps[i] = i; - } - } - - // start the clock - void init(uint64_t p_cpu_ticks_usec) { - current_cpu_ticks_usec = last_cpu_ticks_usec = p_cpu_ticks_usec; - } - - // set measured wall clock time - void set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec) { - current_cpu_ticks_usec = p_cpu_ticks_usec; - } - - // advance one frame, return timesteps to take - _FrameTime advance(float p_frame_slice, int p_iterations_per_second) { - float cpu_animation_step = get_cpu_animation_step(); - - return advance_checked(p_frame_slice, p_iterations_per_second, cpu_animation_step); - } - - void before_start_render() { - VisualServer::get_singleton()->sync(); - } -}; -static _TimerSync _timer_sync; +static MainTimerSync main_timer_sync; bool Main::start() { @@ -1457,7 +1240,7 @@ bool Main::start() { String _export_preset; bool export_debug = false; - _timer_sync.init(OS::get_singleton()->get_ticks_usec()); + main_timer_sync.init(OS::get_singleton()->get_ticks_usec()); List<String> args = OS::get_singleton()->get_cmdline_args(); for (int i = 0; i < args.size(); i++) { @@ -1958,15 +1741,16 @@ bool Main::iteration() { uint64_t ticks = OS::get_singleton()->get_ticks_usec(); Engine::get_singleton()->_frame_ticks = ticks; - _timer_sync.set_cpu_ticks_usec(ticks); + main_timer_sync.set_cpu_ticks_usec(ticks); + main_timer_sync.set_fixed_fps(fixed_fps); uint64_t ticks_elapsed = ticks - last_ticks; int physics_fps = Engine::get_singleton()->get_iterations_per_second(); float frame_slice = 1.0 / physics_fps; - _FrameTime advance = _timer_sync.advance(frame_slice, physics_fps); - double step = advance.animation_step; + MainFrameTime advance = main_timer_sync.advance(frame_slice, physics_fps); + double step = advance.idle_step; Engine::get_singleton()->_frame_step = step; @@ -2030,7 +1814,7 @@ bool Main::iteration() { OS::get_singleton()->get_main_loop()->idle(step * time_scale); message_queue->flush(); - _timer_sync.before_start_render(); //sync if still drawing from previous frames. + VisualServer::get_singleton()->sync(); //sync if still drawing from previous frames. if (OS::get_singleton()->can_draw() && !disable_render_loop) { diff --git a/main/timer_sync.cpp b/main/timer_sync.cpp new file mode 100644 index 0000000000..9f4f6ed271 --- /dev/null +++ b/main/timer_sync.cpp @@ -0,0 +1,223 @@ +/*************************************************************************/ +/* timer_sync.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "timer_sync.h" + +void MainFrameTime::clamp_idle(float min_idle_step, float max_idle_step) { + if (idle_step < min_idle_step) { + idle_step = min_idle_step; + } else if (idle_step > max_idle_step) { + idle_step = max_idle_step; + } +} + +///////////////////////////////// + +// returns the fraction of p_frame_slice required for the timer to overshoot +// before advance_core considers changing the physics_steps return from +// the typical values as defined by typical_physics_steps +float MainTimerSync::get_physics_jitter_fix() { + return Engine::get_singleton()->get_physics_jitter_fix(); +} + +// gets our best bet for the average number of physics steps per render frame +// return value: number of frames back this data is consistent +int MainTimerSync::get_average_physics_steps(float &p_min, float &p_max) { + p_min = typical_physics_steps[0]; + p_max = p_min + 1; + + for (int i = 1; i < CONTROL_STEPS; ++i) { + const float typical_lower = typical_physics_steps[i]; + const float current_min = typical_lower / (i + 1); + if (current_min > p_max) + return i; // bail out of further restrictions would void the interval + else if (current_min > p_min) + p_min = current_min; + const float current_max = (typical_lower + 1) / (i + 1); + if (current_max < p_min) + return i; + else if (current_max < p_max) + p_max = current_max; + } + + return CONTROL_STEPS; +} + +// advance physics clock by p_idle_step, return appropriate number of steps to simulate +MainFrameTime MainTimerSync::advance_core(float p_frame_slice, int p_iterations_per_second, float p_idle_step) { + MainFrameTime ret; + + ret.idle_step = p_idle_step; + + // simple determination of number of physics iteration + time_accum += ret.idle_step; + ret.physics_steps = floor(time_accum * p_iterations_per_second); + + int min_typical_steps = typical_physics_steps[0]; + int max_typical_steps = min_typical_steps + 1; + + // given the past recorded steps and typcial steps to match, calculate bounds for this + // step to be typical + bool update_typical = false; + + for (int i = 0; i < CONTROL_STEPS - 1; ++i) { + int steps_left_to_match_typical = typical_physics_steps[i + 1] - accumulated_physics_steps[i]; + if (steps_left_to_match_typical > max_typical_steps || + steps_left_to_match_typical + 1 < min_typical_steps) { + update_typical = true; + break; + } + + if (steps_left_to_match_typical > min_typical_steps) + min_typical_steps = steps_left_to_match_typical; + if (steps_left_to_match_typical + 1 < max_typical_steps) + max_typical_steps = steps_left_to_match_typical + 1; + } + + // try to keep it consistent with previous iterations + if (ret.physics_steps < min_typical_steps) { + const int max_possible_steps = floor((time_accum)*p_iterations_per_second + get_physics_jitter_fix()); + if (max_possible_steps < min_typical_steps) { + ret.physics_steps = max_possible_steps; + update_typical = true; + } else { + ret.physics_steps = min_typical_steps; + } + } else if (ret.physics_steps > max_typical_steps) { + const int min_possible_steps = floor((time_accum)*p_iterations_per_second - get_physics_jitter_fix()); + if (min_possible_steps > max_typical_steps) { + ret.physics_steps = min_possible_steps; + update_typical = true; + } else { + ret.physics_steps = max_typical_steps; + } + } + + time_accum -= ret.physics_steps * p_frame_slice; + + // keep track of accumulated step counts + for (int i = CONTROL_STEPS - 2; i >= 0; --i) { + accumulated_physics_steps[i + 1] = accumulated_physics_steps[i] + ret.physics_steps; + } + accumulated_physics_steps[0] = ret.physics_steps; + + if (update_typical) { + for (int i = CONTROL_STEPS - 1; i >= 0; --i) { + if (typical_physics_steps[i] > accumulated_physics_steps[i]) { + typical_physics_steps[i] = accumulated_physics_steps[i]; + } else if (typical_physics_steps[i] < accumulated_physics_steps[i] - 1) { + typical_physics_steps[i] = accumulated_physics_steps[i] - 1; + } + } + } + + return ret; +} + +// calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero +MainFrameTime MainTimerSync::advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step) { + if (fixed_fps != -1) + p_idle_step = 1.0 / fixed_fps; + + // compensate for last deficit + p_idle_step += time_deficit; + + MainFrameTime ret = advance_core(p_frame_slice, p_iterations_per_second, p_idle_step); + + // we will do some clamping on ret.idle_step and need to sync those changes to time_accum, + // that's easiest if we just remember their fixed difference now + const double idle_minus_accum = ret.idle_step - time_accum; + + // first, least important clamping: keep ret.idle_step consistent with typical_physics_steps. + // this smoothes out the idle steps and culls small but quick variations. + { + float min_average_physics_steps, max_average_physics_steps; + int consistent_steps = get_average_physics_steps(min_average_physics_steps, max_average_physics_steps); + if (consistent_steps > 3) { + ret.clamp_idle(min_average_physics_steps * p_frame_slice, max_average_physics_steps * p_frame_slice); + } + } + + // second clamping: keep abs(time_deficit) < jitter_fix * frame_slise + float max_clock_deviation = get_physics_jitter_fix() * p_frame_slice; + ret.clamp_idle(p_idle_step - max_clock_deviation, p_idle_step + max_clock_deviation); + + // last clamping: make sure time_accum is between 0 and p_frame_slice for consistency between physics and idle + ret.clamp_idle(idle_minus_accum, idle_minus_accum + p_frame_slice); + + // restore time_accum + time_accum = ret.idle_step - idle_minus_accum; + + // track deficit + time_deficit = p_idle_step - ret.idle_step; + + return ret; +} + +// determine wall clock step since last iteration +float MainTimerSync::get_cpu_idle_step() { + uint64_t cpu_ticks_elapsed = current_cpu_ticks_usec - last_cpu_ticks_usec; + last_cpu_ticks_usec = current_cpu_ticks_usec; + + return cpu_ticks_elapsed / 1000000.0; +} + +MainTimerSync::MainTimerSync() : + last_cpu_ticks_usec(0), + current_cpu_ticks_usec(0), + time_accum(0), + time_deficit(0), + fixed_fps(0) { + for (int i = CONTROL_STEPS - 1; i >= 0; --i) { + typical_physics_steps[i] = i; + accumulated_physics_steps[i] = i; + } +} + +// start the clock +void MainTimerSync::init(uint64_t p_cpu_ticks_usec) { + current_cpu_ticks_usec = last_cpu_ticks_usec = p_cpu_ticks_usec; +} + +// set measured wall clock time +void MainTimerSync::set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec) { + current_cpu_ticks_usec = p_cpu_ticks_usec; +} + +void MainTimerSync::set_fixed_fps(int p_fixed_fps) { + fixed_fps = p_fixed_fps; +} + +// advance one frame, return timesteps to take +MainFrameTime MainTimerSync::advance(float p_frame_slice, int p_iterations_per_second) { + float cpu_idle_step = get_cpu_idle_step(); + + return advance_checked(p_frame_slice, p_iterations_per_second, cpu_idle_step); +} diff --git a/main/timer_sync.h b/main/timer_sync.h new file mode 100644 index 0000000000..75fbe6a9dc --- /dev/null +++ b/main/timer_sync.h @@ -0,0 +1,101 @@ +/*************************************************************************/ +/* timer_sync.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 TIMER_SYNC_H +#define TIMER_SYNC_H + +#include "core/engine.h" + +struct MainFrameTime { + float idle_step; // time to advance idles for (argument to process()) + int physics_steps; // number of times to iterate the physics engine + + void clamp_idle(float min_idle_step, float max_idle_step); +}; + +class MainTimerSync { + // wall clock time measured on the main thread + uint64_t last_cpu_ticks_usec; + uint64_t current_cpu_ticks_usec; + + // logical game time since last physics timestep + float time_accum; + + // current difference between wall clock time and reported sum of idle_steps + float time_deficit; + + // number of frames back for keeping accumulated physics steps roughly constant. + // value of 12 chosen because that is what is required to make 144 Hz monitors + // behave well with 60 Hz physics updates. The only worse commonly available refresh + // would be 85, requiring CONTROL_STEPS = 17. + static const int CONTROL_STEPS = 12; + + // sum of physics steps done over the last (i+1) frames + int accumulated_physics_steps[CONTROL_STEPS]; + + // typical value for accumulated_physics_steps[i] is either this or this plus one + int typical_physics_steps[CONTROL_STEPS]; + + int fixed_fps; + +protected: + // returns the fraction of p_frame_slice required for the timer to overshoot + // before advance_core considers changing the physics_steps return from + // the typical values as defined by typical_physics_steps + float get_physics_jitter_fix(); + + // gets our best bet for the average number of physics steps per render frame + // return value: number of frames back this data is consistent + int get_average_physics_steps(float &p_min, float &p_max); + + // advance physics clock by p_idle_step, return appropriate number of steps to simulate + MainFrameTime advance_core(float p_frame_slice, int p_iterations_per_second, float p_idle_step); + + // calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero + MainFrameTime advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step); + + // determine wall clock step since last iteration + float get_cpu_idle_step(); + +public: + MainTimerSync(); + + // start the clock + void init(uint64_t p_cpu_ticks_usec); + // set measured wall clock time + void set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec); + //set fixed fps + void set_fixed_fps(int p_fixed_fps); + + // advance one frame, return timesteps to take + MainFrameTime advance(float p_frame_slice, int p_iterations_per_second); +}; + +#endif // TIMER_SYNC_H diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index c1fe11d6aa..4e6e701bfd 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* csg.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "csg.h" #include "face3.h" #include "geometry.h" diff --git a/modules/csg/csg.h b/modules/csg/csg.h index bb67e1fb36..53303a6533 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* csg.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 CSG_H #define CSG_H diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 06cbaab3b0..2150320c4a 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* csg_gizmos.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "csg_gizmos.h" /////////// diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index b5e394ecad..68e916823b 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* csg_gizmos.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 CSG_GIZMOS_H #define CSG_GIZMOS_H diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 22bc79ef43..82db1871da 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* csg_shape.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "csg_shape.h" #include "scene/3d/path.h" @@ -966,9 +996,9 @@ void CSGBox::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox::set_material); ClassDB::bind_method(D_METHOD("get_material"), &CSGBox::get_material); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "width", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_width", "get_width"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_height", "get_height"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_depth", "get_depth"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "width", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); } @@ -1178,8 +1208,8 @@ void CSGCylinder::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder::set_smooth_faces); ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder::get_smooth_faces); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cone"), "set_cone", "is_cone"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); @@ -1403,8 +1433,8 @@ void CSGTorus::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus::set_smooth_faces); ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus::get_smooth_faces); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_inner_radius", "get_inner_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_outer_radius", "get_outer_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "inner_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_inner_radius", "get_inner_radius"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "outer_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_outer_radius", "get_outer_radius"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_sides", "get_ring_sides"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); @@ -1978,11 +2008,11 @@ void CSGPolygon::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Depth,Spin,Path"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_depth", "get_depth"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees"); ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node"), "set_path_node", "get_path_node"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "path_interval", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001"), "set_path_interval", "get_path_interval"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index c1d2cce606..cbb5c7e041 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* csg_shape.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 CSG_SHAPE_H #define CSG_SHAPE_H diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index bbe245951e..161e62c81f 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -782,7 +782,7 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { } if (Engine::get_singleton()->is_editor_hint()) { - EditorNode::get_singleton()->get_property_editor()->update_tree(); + EditorNode::get_singleton()->get_inspector()->update_tree(); NodeDock::singleton->update_lists(); } } diff --git a/modules/mono/glue/builtin_types_glue.h b/modules/mono/glue/builtin_types_glue.h index 460de84b65..ef9f152682 100644 --- a/modules/mono/glue/builtin_types_glue.h +++ b/modules/mono/glue/builtin_types_glue.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* builtin_types_glue.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 BUILTIN_TYPES_GLUE_H #define BUILTIN_TYPES_GLUE_H diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index eb10c5e99f..dfaa873b13 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -268,7 +268,7 @@ protected: if (String(p_name) == "export") { script->set_variable_export(var, p_value); - EditorNode::get_singleton()->get_property_editor()->update_tree(); + EditorNode::get_singleton()->get_inspector()->update_tree(); return true; } diff --git a/modules/webp/SCsub b/modules/webp/SCsub index ea7af1bf9e..21ae0ce7c2 100644 --- a/modules/webp/SCsub +++ b/modules/webp/SCsub @@ -78,10 +78,12 @@ if env['builtin_libwebp']: "dsp/upsampling_msa.c", "dsp/upsampling_neon.c", "dsp/upsampling_sse2.c", + "dsp/upsampling_sse41.c", "dsp/yuv.c", "dsp/yuv_mips32.c", "dsp/yuv_mips_dsp_r2.c", "dsp/yuv_sse2.c", + "dsp/yuv_sse41.c", "enc/alpha_enc.c", "enc/analysis_enc.c", "enc/backward_references_cost_enc.c", diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub index 5991075e29..98988d97fd 100644 --- a/platform/javascript/SCsub +++ b/platform/javascript/SCsub @@ -30,8 +30,8 @@ zip_files = env.InstallAs([ zip_dir.File('godot.wasm'), zip_dir.File('godot.html') ], [ - js_wrapped, - wasm, - '#misc/dist/html/default.html' + js_wrapped, + wasm, + '#misc/dist/html/default.html' ]) env.Zip('#bin/godot', zip_files, ZIPROOT=zip_dir, ZIPSUFFIX='${PROGSUFFIX}${ZIPSUFFIX}', ZIPCOMSTR='Archving $SOURCES as $TARGET') diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index a48cb872ee..fc909f6619 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -1,5 +1,4 @@ import os -import string import sys @@ -39,7 +38,7 @@ def configure(env): ## Build type - if env['target'] == 'release' or env['target'] == 'profile': + if env['target'] != 'debug': # Use -Os to prioritize optimizing for reduced file size. This is # particularly valuable for the web platform because it directly # decreases download time. @@ -48,17 +47,11 @@ def configure(env): # run-time performance. env.Append(CCFLAGS=['-Os']) env.Append(LINKFLAGS=['-Os']) - if env['target'] == 'profile': + if env['target'] == 'release_debug': + env.Append(CPPDEFINES=['DEBUG_ENABLED']) + # Retain function names for backtraces at the cost of file size. env.Append(LINKFLAGS=['--profiling-funcs']) - - elif env['target'] == 'release_debug': - env.Append(CPPDEFINES=['DEBUG_ENABLED']) - env.Append(CCFLAGS=['-O2']) - env.Append(LINKFLAGS=['-O2']) - # Retain function names for backtraces at the cost of file size. - env.Append(LINKFLAGS=['--profiling-funcs']) - - elif env['target'] == 'debug': + else: env.Append(CPPDEFINES=['DEBUG_ENABLED']) env.Append(CCFLAGS=['-O1', '-g']) env.Append(LINKFLAGS=['-O1', '-g']) diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index bb914b90fc..c375374dce 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -666,11 +666,11 @@ void Area2D::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point"); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_gravity_distance_scale", "get_gravity_distance_scale"); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_vec"), "set_gravity_vector", "get_gravity_vector"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.001"), "set_gravity", "get_gravity"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_linear_damp", "get_linear_damp"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_angular_damp", "get_angular_damp"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_linear_damp", "get_linear_damp"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_angular_damp", "get_angular_damp"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring"); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable"); diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index f998f23d3b..54541293fd 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -461,8 +461,8 @@ void AudioStreamPlayer2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "1,65536,1"), "set_max_distance", "get_max_distance"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING), "set_attenuation", "get_attenuation"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "1,4096,1,or_greater"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index d172da5bd9..3b86ca76ea 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -91,8 +91,8 @@ Transform2D Camera2D::get_camera_transform() { if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) { if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint()) { - camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT])); - camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT])); + camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_LEFT])); + camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_RIGHT])); } else { if (h_ofs < 0) { @@ -104,8 +104,8 @@ Transform2D Camera2D::get_camera_transform() { if (v_drag_enabled && !Engine::get_singleton()->is_editor_hint()) { - camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP])); - camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM])); + camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_TOP])); + camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_BOTTOM])); } else { diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index adbb227d0c..9f21fe1a1f 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* mesh_instance_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "mesh_instance_2d.h" void MeshInstance2D::_notification(int p_what) { diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h index d1d1ade0ae..c9889c1c03 100644 --- a/scene/2d/mesh_instance_2d.h +++ b/scene/2d/mesh_instance_2d.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* mesh_instance_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 MESH_INSTANCE_2D_H #define MESH_INSTANCE_2D_H diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 7eaa5bb88c..1da1d44b17 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -367,9 +367,9 @@ void Particles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 7377591f7d..658b998d17 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -299,7 +299,7 @@ void PathFollow2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead); ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_EXP_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 2363c791fa..0595cc43b8 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skeleton_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "skeleton_2d.h" void Bone2D::_notification(int p_what) { diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index cd270dac85..b86cf3be81 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skeleton_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 SKELETON_2D_H #define SKELETON_2D_H diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 21f471039f..6ea980ec97 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -711,7 +711,7 @@ void Area::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_gravity_distance_scale", "get_gravity_distance_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_linear_damp", "get_linear_damp"); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index c2a50ec7bb..e7b3645001 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -898,7 +898,7 @@ void AudioStreamPlayer3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,65536,1"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 9de189c158..e11e8abe5b 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -480,8 +480,8 @@ void Camera::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "near"), "set_znear", "get_znear"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "far"), "set_zfar", "get_zfar"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_znear", "get_znear"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar"); BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL); diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 240bd631a1..7c42638107 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -375,7 +375,7 @@ void DirectionalLight::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE); ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE); BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL); BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS); @@ -428,8 +428,8 @@ void OmniLight::_bind_methods() { ClassDB::bind_method(D_METHOD("get_shadow_detail"), &OmniLight::get_shadow_detail); ADD_GROUP("Omni", "omni_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_detail", PROPERTY_HINT_ENUM, "Vertical,Horizontal"), "set_shadow_detail", "get_shadow_detail"); @@ -450,8 +450,8 @@ OmniLight::OmniLight() : void SpotLight::_bind_methods() { ADD_GROUP("Spot", "spot_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_SPOT_ATTENUATION); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION); } diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index a39ac5a8f5..7b5eb8ebc3 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -324,11 +324,11 @@ void Particles::_bind_methods() { ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); @@ -1460,26 +1460,26 @@ void ParticlesMaterial::_bind_methods() { ADD_GROUP("Gravity", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); ADD_GROUP("Initial Velocity", "initial_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY); ADD_GROUP("Angular Velocity", "angular_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY); ADD_GROUP("Orbit Velocity", "orbit_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY); ADD_GROUP("Linear Accel", "linear_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL); ADD_GROUP("Radial Accel", "radial_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL); ADD_GROUP("Tangential Accel", "tangential_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL); ADD_GROUP("Damping", ""); @@ -1487,11 +1487,11 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1"), "set_param", "get_param", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE); ADD_GROUP("Scale", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE); ADD_GROUP("Color", ""); @@ -1503,7 +1503,7 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION); ADD_GROUP("Animation", "anim_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET); diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index 57d79c960f..154dcb4259 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -230,7 +230,7 @@ void PathFollow::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow::set_loop); ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow::has_loop); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_EXP_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 0577a23ea6..5056fb2fe4 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1400,7 +1400,7 @@ void PhysicalBone::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) JointData::_get_property_list(p_list); p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater")); p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index 2178da02b5..7e3a87cbd4 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -240,7 +240,7 @@ void ReflectionProbe::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once,Always"), "set_update_mode", "get_update_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,16384,0.1"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "extents"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "origin_offset"), "set_origin_offset", "get_origin_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "box_projection"), "set_enable_box_projection", "is_box_projection_enabled"); diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index a239e7e871..ee8d249981 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -924,7 +924,7 @@ void VehicleBody::_bind_methods() { ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody::get_steering); ADD_GROUP("Motion", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01"), "set_engine_force", "get_engine_force"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering"); } diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 6f34f3e49f..34891832e2 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -656,8 +656,9 @@ ColorPicker::ColorPicker() : void ColorPickerButton::_color_changed(const Color &p_color) { + color = p_color; update(); - emit_signal("color_changed", p_color); + emit_signal("color_changed", color); } void ColorPickerButton::_modal_closed() { @@ -667,6 +668,7 @@ void ColorPickerButton::_modal_closed() { void ColorPickerButton::pressed() { + _update_picker(); popup->set_position(get_global_position() - picker->get_combined_minimum_size()); popup->popup(); picker->set_focus_on_line_edit(); @@ -679,37 +681,44 @@ void ColorPickerButton::_notification(int p_what) { Ref<StyleBox> normal = get_stylebox("normal"); Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size()); draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true); - draw_rect(r, picker->get_pick_color()); + draw_rect(r, color); } - if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) { + if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST && popup) { popup->hide(); } } void ColorPickerButton::set_pick_color(const Color &p_color) { - picker->set_pick_color(p_color); + color = p_color; + if (picker) { + picker->set_pick_color(p_color); + } + update(); - emit_signal("color_changed", p_color); } Color ColorPickerButton::get_pick_color() const { - return picker->get_pick_color(); + return color; } void ColorPickerButton::set_edit_alpha(bool p_show) { - picker->set_edit_alpha(p_show); + edit_alpha = p_show; + if (picker) { + picker->set_edit_alpha(p_show); + } } bool ColorPickerButton::is_editing_alpha() const { - return picker->is_editing_alpha(); + return edit_alpha; } -ColorPicker *ColorPickerButton::get_picker() const { +ColorPicker *ColorPickerButton::get_picker() { + _update_picker(); return picker; } @@ -718,6 +727,19 @@ PopupPanel *ColorPickerButton::get_popup() const { return popup; } +void ColorPickerButton::_update_picker() { + if (!picker) { + popup = memnew(PopupPanel); + picker = memnew(ColorPicker); + popup->add_child(picker); + add_child(popup); + picker->connect("color_changed", this, "_color_changed"); + popup->connect("modal_closed", this, "_modal_closed"); + picker->set_pick_color(color); + picker->set_edit_alpha(edit_alpha); + } +} + void ColorPickerButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPickerButton::set_pick_color); @@ -737,12 +759,10 @@ void ColorPickerButton::_bind_methods() { ColorPickerButton::ColorPickerButton() { - popup = memnew(PopupPanel); - picker = memnew(ColorPicker); - popup->add_child(picker); - - picker->connect("color_changed", this, "_color_changed"); - popup->connect("modal_closed", this, "_modal_closed"); - - add_child(popup); + //Initialization is now done deferred + //this improves performance in the inspector as the color picker + //can be expensive to initialize + picker = NULL; + popup = NULL; + edit_alpha = true; } diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 7d1a554ada..6b63e5fe60 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -118,12 +118,16 @@ class ColorPickerButton : public Button { PopupPanel *popup; ColorPicker *picker; + Color color; + bool edit_alpha; void _color_changed(const Color &p_color); void _modal_closed(); virtual void pressed(); + void _update_picker(); + protected: void _notification(int); static void _bind_methods(); @@ -135,7 +139,7 @@ public: void set_edit_alpha(bool p_show); bool is_editing_alpha() const; - ColorPicker *get_picker() const; + ColorPicker *get_picker(); PopupPanel *get_popup() const; ColorPickerButton(); diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 7cb0ad5707..177582c87c 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -34,9 +34,9 @@ void Container::_child_minsize_changed() { - Size2 ms = get_combined_minimum_size(); - if (ms.width > get_size().width || ms.height > get_size().height) - minimum_size_changed(); + //Size2 ms = get_combined_minimum_size(); + //if (ms.width > get_size().width || ms.height > get_size().height) { + minimum_size_changed(); queue_sort(); } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index b7c1d35fd7..3097ecaf16 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -155,12 +155,21 @@ Size2 Control::get_custom_minimum_size() const { return data.custom_minimum_size; } -Size2 Control::get_combined_minimum_size() const { +void Control::_update_minimum_size_cache() { Size2 minsize = get_minimum_size(); minsize.x = MAX(minsize.x, data.custom_minimum_size.x); minsize.y = MAX(minsize.y, data.custom_minimum_size.y); - return minsize; + data.minimum_size_cache = minsize; + data.minimum_size_valid = true; +} + +Size2 Control::get_combined_minimum_size() const { + + if (!data.minimum_size_valid) { + const_cast<Control *>(this)->_update_minimum_size_cache(); + } + return data.minimum_size_cache; } Size2 Control::_edit_get_minimum_size() const { @@ -259,14 +268,17 @@ void Control::_update_minimum_size() { if (!is_inside_tree()) return; - data.pending_min_size_update = false; Size2 minsize = get_combined_minimum_size(); if (minsize.x > data.size_cache.x || minsize.y > data.size_cache.y) { _size_changed(); } - emit_signal(SceneStringNames::get_singleton()->minimum_size_changed); + data.updating_last_minimum_size = false; + + if (minsize != data.last_minimum_size) { + emit_signal(SceneStringNames::get_singleton()->minimum_size_changed); + } } bool Control::_get(const StringName &p_name, Variant &r_ret) const { @@ -437,8 +449,12 @@ void Control::_notification(int p_notification) { case NOTIFICATION_ENTER_TREE: { - _size_changed(); - + } break; + case NOTIFICATION_POST_ENTER_TREE: { + if (is_visible_in_tree()) { + data.minimum_size_valid = false; + _size_changed(); + } } break; case NOTIFICATION_EXIT_TREE: { @@ -620,13 +636,12 @@ void Control::_notification(int p_notification) { if (is_inside_tree()) { _modal_stack_remove(); - minimum_size_changed(); } //remove key focus //remove modalness } else { - + data.minimum_size_valid = false; _size_changed(); } @@ -2464,17 +2479,25 @@ void Control::minimum_size_changed() { if (!is_inside_tree() || data.block_minimum_size_adjust) return; - if (data.pending_min_size_update) + Control *invalidate = this; + + //invalidate cache upwards + while (invalidate && invalidate->data.minimum_size_valid) { + invalidate->data.minimum_size_valid = false; + if (invalidate->is_set_as_toplevel()) + break; // do not go further up + invalidate = invalidate->data.parent; + } + + if (!is_visible_in_tree()) + return; + + if (data.updating_last_minimum_size) return; - data.pending_min_size_update = true; - MessageQueue::get_singleton()->push_call(this, "_update_minimum_size"); + data.updating_last_minimum_size = true; - if (!is_toplevel_control()) { - Control *pc = get_parent_control(); - if (pc) - pc->minimum_size_changed(); - } + MessageQueue::get_singleton()->push_call(this, "_update_minimum_size"); } int Control::get_v_size_flags() const { @@ -2985,7 +3008,6 @@ Control::Control() { data.h_size_flags = SIZE_FILL; data.v_size_flags = SIZE_FILL; data.expand = 1; - data.pending_min_size_update = false; data.rotation = 0; data.parent_canvas_item = NULL; data.scale = Vector2(1, 1); @@ -2995,6 +3017,8 @@ Control::Control() { data.disable_visibility_clip = false; data.h_grow = GROW_DIRECTION_END; data.v_grow = GROW_DIRECTION_END; + data.minimum_size_valid = false; + data.updating_last_minimum_size = false; data.clip_contents = false; for (int i = 0; i < 4; i++) { diff --git a/scene/gui/control.h b/scene/gui/control.h index b5453e60f5..9124256624 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -148,6 +148,11 @@ private: Point2 pos_cache; Size2 size_cache; + Size2 minimum_size_cache; + bool minimum_size_valid; + + Size2 last_minimum_size; + bool updating_last_minimum_size; float margin[4]; float anchor[4]; @@ -164,7 +169,6 @@ private: int h_size_flags; int v_size_flags; float expand; - bool pending_min_size_update; Point2 custom_minimum_size; bool pass_on_modal_close_click; @@ -244,6 +248,8 @@ private: void _modal_stack_remove(); void _modal_set_prev_focus_owner(ObjectID p_prev); + void _update_minimum_size_cache(); + protected: virtual void add_child_notify(Node *p_child); virtual void remove_child_notify(Node *p_child); diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index cd6c6bb65c..4062e48640 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -71,10 +71,10 @@ void Range::set_value(double p_val) { p_val = Math::round(p_val); } - if (p_val > shared->max - shared->page) + if (!shared->allow_greater && p_val > shared->max - shared->page) p_val = shared->max - shared->page; - if (p_val < shared->min) + if (!shared->allow_lesser && p_val < shared->min) p_val = shared->min; if (shared->val == p_val) @@ -136,9 +136,9 @@ void Range::set_as_ratio(double p_value) { double v; - if (shared->exp_ratio && get_min() > 0) { + if (shared->exp_ratio && get_min() >= 0) { - double exp_min = Math::log(get_min()) / Math::log((double)2); + double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2); double exp_max = Math::log(get_max()) / Math::log((double)2); v = Math::pow(2, exp_min + (exp_max - exp_min) * p_value); } else { @@ -151,21 +151,24 @@ void Range::set_as_ratio(double p_value) { v = percent + get_min(); } } + v = CLAMP(v, get_min(), get_max()); set_value(v); } double Range::get_as_ratio() const { - if (shared->exp_ratio && get_min() > 0) { + if (shared->exp_ratio && get_min() >= 0) { - double exp_min = Math::log(get_min()) / Math::log((double)2); + double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2); double exp_max = Math::log(get_max()) / Math::log((double)2); - double v = Math::log(get_value()) / Math::log((double)2); + float value = CLAMP(get_value(), shared->min, shared->max); + double v = Math::log(value) / Math::log((double)2); return (v - exp_min) / (exp_max - exp_min); } else { - return (get_value() - get_min()) / (get_max() - get_min()); + float value = CLAMP(get_value(), shared->min, shared->max); + return (value - get_min()) / (get_max() - get_min()); } } @@ -193,6 +196,8 @@ void Range::unshare() { nshared->val = shared->val; nshared->step = shared->step; nshared->page = shared->page; + nshared->allow_greater = shared->allow_greater; + nshared->allow_lesser = shared->allow_lesser; _unref_shared(); _ref_shared(nshared); } @@ -236,6 +241,10 @@ void Range::_bind_methods() { ClassDB::bind_method(D_METHOD("is_using_rounded_values"), &Range::is_using_rounded_values); ClassDB::bind_method(D_METHOD("set_exp_ratio", "enabled"), &Range::set_exp_ratio); ClassDB::bind_method(D_METHOD("is_ratio_exp"), &Range::is_ratio_exp); + ClassDB::bind_method(D_METHOD("set_allow_greater", "allow"), &Range::set_allow_greater); + ClassDB::bind_method(D_METHOD("is_greater_allowed"), &Range::is_greater_allowed); + ClassDB::bind_method(D_METHOD("set_allow_lesser", "allow"), &Range::set_allow_lesser); + ClassDB::bind_method(D_METHOD("is_lesser_allowed"), &Range::is_lesser_allowed); ClassDB::bind_method(D_METHOD("share", "with"), &Range::_share); ClassDB::bind_method(D_METHOD("unshare"), &Range::unshare); @@ -251,6 +260,8 @@ void Range::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "ratio", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_as_ratio", "get_as_ratio"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exp_edit"), "set_exp_ratio", "is_ratio_exp"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rounded"), "set_use_rounded_values", "is_using_rounded_values"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "allow_greater"), "set_allow_greater", "is_greater_allowed"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed"); } void Range::set_use_rounded_values(bool p_enable) { @@ -273,6 +284,22 @@ bool Range::is_ratio_exp() const { return shared->exp_ratio; } +void Range::set_allow_greater(bool p_allow) { + shared->allow_greater = p_allow; +} + +bool Range::is_greater_allowed() const { + return shared->allow_greater; +} + +void Range::set_allow_lesser(bool p_allow) { + shared->allow_lesser = p_allow; +} + +bool Range::is_lesser_allowed() const { + return shared->allow_lesser; +} + Range::Range() { shared = memnew(Shared); shared->min = 0; @@ -282,6 +309,8 @@ Range::Range() { shared->page = 0; shared->owners.insert(this); shared->exp_ratio = false; + shared->allow_greater = false; + shared->allow_lesser = false; _rounded_values = false; } diff --git a/scene/gui/range.h b/scene/gui/range.h index de9383afd8..125f559248 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -43,6 +43,8 @@ class Range : public Control { double val, min, max; double step, page; bool exp_ratio; + bool allow_greater; + bool allow_lesser; Set<Range *> owners; void emit_value_changed(); void emit_changed(const char *p_what = ""); @@ -86,6 +88,12 @@ public: void set_exp_ratio(bool p_enable); bool is_ratio_exp() const; + void set_allow_greater(bool p_allow); + bool is_greater_allowed() const; + + void set_allow_lesser(bool p_allow); + bool is_lesser_allowed() const; + void share(Range *p_range); void unshare(); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index a1dcf3b002..2dd5c64378 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -37,6 +37,7 @@ bool ScrollContainer::clips_input() const { Size2 ScrollContainer::get_minimum_size() const { + Ref<StyleBox> sb = get_stylebox("bg"); Size2 min_size; for (int i = 0; i < get_child_count(); i++) { @@ -64,8 +65,9 @@ Size2 ScrollContainer::get_minimum_size() const { if (v_scroll->is_visible_in_tree()) { min_size.x += v_scroll->get_minimum_size().x; } + min_size += sb->get_minimum_size(); return min_size; -}; +} void ScrollContainer::_cancel_drag() { set_physics_process_internal(false); @@ -233,6 +235,12 @@ void ScrollContainer::_notification(int p_what) { child_max_size = Size2(0, 0); Size2 size = get_size(); + Point2 ofs; + + Ref<StyleBox> sb = get_stylebox("bg"); + size -= sb->get_minimum_size(); + ofs += sb->get_offset(); + if (h_scroll->is_visible_in_tree()) size.y -= h_scroll->get_minimum_size().y; @@ -268,6 +276,7 @@ void ScrollContainer::_notification(int p_what) { else r.size.height = minsize.height; } + r.position += ofs; fit_child_in_rect(c, r); } update(); @@ -275,6 +284,9 @@ void ScrollContainer::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { + Ref<StyleBox> sb = get_stylebox("bg"); + draw_style_box(sb, Rect2(Vector2(), get_size())); + update_scrollbars(); } @@ -353,6 +365,8 @@ void ScrollContainer::_notification(int p_what) { void ScrollContainer::update_scrollbars() { Size2 size = get_size(); + Ref<StyleBox> sb = get_stylebox("bg"); + size -= sb->get_minimum_size(); Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 553c2b7c39..c6ff8489c0 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -302,7 +302,7 @@ void TextEdit::Text::remove(int p_at) { text.remove(p_at); } -int TextEdit::Text::get_char_width(char c, char next_c, int px) const { +int TextEdit::Text::get_char_width(CharType c, CharType next_c, int px) const { int tab_w = font->get_char_size(' ').width * indent_size; int w = 0; @@ -3620,7 +3620,7 @@ void TextEdit::adjust_viewport_to_cursor() { visible_width -= v_scroll->get_combined_minimum_size().width; visible_width -= 20; // give it a little more space - if (is_wrap_enabled()) { + if (!is_wrap_enabled()) { // adjust x offset int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]); @@ -5995,7 +5995,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line); ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden", "wrap_index"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true), DEFVAL(0)); ClassDB::bind_method(D_METHOD("cursor_get_column"), &TextEdit::cursor_get_column); ClassDB::bind_method(D_METHOD("cursor_get_line"), &TextEdit::cursor_get_line); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 6f4eb01a70..5c82d1ac20 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -95,7 +95,7 @@ public: void set_color_regions(const Vector<ColorRegion> *p_regions) { color_regions = p_regions; } int get_line_width(int p_line) const; int get_max_width(bool p_exclude_hidden = false) const; - int get_char_width(char c, char next_c, int px) const; + int get_char_width(CharType c, CharType next_c, int px) const; void set_line_wrap_amount(int p_line, int p_wrap_amount) const; int get_line_wrap_amount(int p_line) const; const Map<int, ColorRegionInfo> &get_color_region_info(int p_line) const; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index e6ea4e4b4a..3643aedb85 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -176,6 +176,9 @@ void Node::_propagate_ready() { data.children[i]->_propagate_ready(); } data.blocked--; + + notification(NOTIFICATION_POST_ENTER_TREE); + if (data.ready_first) { data.ready_first = false; notification(NOTIFICATION_READY); diff --git a/scene/main/node.h b/scene/main/node.h index 4ff1247e14..540f34cba7 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -237,6 +237,7 @@ public: NOTIFICATION_TRANSLATION_CHANGED = 24, NOTIFICATION_INTERNAL_PROCESS = 25, NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26, + NOTIFICATION_POST_ENTER_TREE = 27, }; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 295f131db3..f631fd6f3a 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -72,6 +72,9 @@ void ViewportTexture::setup_local_to_scene() { vp->viewport_textures.insert(this); VS::get_singleton()->texture_set_proxy(proxy, vp->texture_rid); + + vp->texture_flags = flags; + VS::get_singleton()->texture_set_flags(vp->texture_rid, flags); } void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) { @@ -122,20 +125,18 @@ Ref<Image> ViewportTexture::get_data() const { return VS::get_singleton()->texture_get_data(vp->texture_rid); } void ViewportTexture::set_flags(uint32_t p_flags) { + flags = p_flags; if (!vp) return; - vp->texture_flags = p_flags; - VS::get_singleton()->texture_set_flags(vp->texture_rid, p_flags); + vp->texture_flags = flags; + VS::get_singleton()->texture_set_flags(vp->texture_rid, flags); } uint32_t ViewportTexture::get_flags() const { - if (!vp) - return 0; - - return vp->texture_flags; + return flags; } void ViewportTexture::_bind_methods() { @@ -149,6 +150,7 @@ void ViewportTexture::_bind_methods() { ViewportTexture::ViewportTexture() { vp = NULL; + flags = 0; set_local_to_scene(true); proxy = VS::get_singleton()->texture_create(); } @@ -1345,7 +1347,7 @@ void Viewport::_gui_show_tooltip() { gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT)); gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM)); gui.tooltip_label->set_text(tooltip.strip_edges()); - Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_combined_minimum_size() + ttp->get_minimum_size()); + Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_minimum_size() + ttp->get_minimum_size()); Rect2 vr = gui.tooltip_label->get_viewport_rect(); if (r.size.x + r.position.x > vr.size.x) r.position.x = vr.size.x - r.size.x; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 363414bbad..c1ef58de69 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -58,6 +58,7 @@ class ViewportTexture : public Texture { friend class Viewport; Viewport *vp; + uint32_t flags; RID proxy; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 5ac9344f31..3ea856541e 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -544,6 +544,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("updown", "SpinBox", make_icon(spinbox_updown_png)); + //scroll container + Ref<StyleBoxEmpty> empty; + empty.instance(); + theme->set_stylebox("bg", "ScrollContainer", empty); + // WindowDialog theme->set_stylebox("panel", "WindowDialog", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6)); diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index d399c548f3..f8661638c3 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2300,7 +2300,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI if (p_node->type == Node::TYPE_OPERATOR) { OperatorNode *op = static_cast<OperatorNode *>(p_node); - if (op->type == OP_INDEX) { + if (op->op == OP_INDEX) { return _validate_assign(op->arguments[0], p_builtin_types); } } diff --git a/thirdparty/README.md b/thirdparty/README.md index 1d4e56d42e..a0b152fda2 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -218,7 +218,7 @@ Godot-made change marked with `// -- GODOT --` comments. ## libwebp - Upstream: https://chromium.googlesource.com/webm/libwebp/ -- Version: 0.6.1 +- Version: 1.0.0 - License: BSD-3-Clause Files extracted from upstream source: @@ -267,7 +267,7 @@ File extracted from upstream release tarball `mbedtls-2.8.0-apache.tgz`: ## minizip - Upstream: http://www.zlib.net -- Version: 1.2.4 (zlib contrib) +- Version: 1.2.11 (zlib contrib) - License: zlib Files extracted from the upstream source: diff --git a/thirdparty/libwebp/AUTHORS b/thirdparty/libwebp/AUTHORS index 70423cb4dd..83c7b9c5eb 100644 --- a/thirdparty/libwebp/AUTHORS +++ b/thirdparty/libwebp/AUTHORS @@ -2,25 +2,38 @@ Contributors: - Charles Munger (clm at google dot com) - Christian Duvivier (cduvivier at google dot com) - Djordje Pesut (djordje dot pesut at imgtec dot com) +- Hui Su (huisu at google dot com) - James Zern (jzern at google dot com) - Jan Engelhardt (jengelh at medozas dot de) +- Jehan (jehan at girinstud dot io) - Johann (johann dot koenig at duck dot com) - Jovan Zelincevic (jovan dot zelincevic at imgtec dot com) - Jyrki Alakuijala (jyrki at google dot com) -- levytamar82 (tamar dot levy at intel dot com) +- Lode Vandevenne (lode at google dot com) - Lou Quillio (louquillio at google dot com) - Mans Rullgard (mans at mansr dot com) +- Marcin Kowalczyk (qrczak at google dot com) - Martin Olsson (mnemo at minimum dot se) - Mikołaj Zalewski (mikolajz at google dot com) +- Mislav Bradac (mislavm at google dot com) +- Nico Weber (thakis at chromium dot org) - Noel Chromium (noel at chromium dot org) +- Owen Rodley (orodley at google dot com) +- Parag Salasakar (img dot mips1 at gmail dot com) - Pascal Massimino (pascal dot massimino at gmail dot com) - Paweł Hajdan, Jr (phajdan dot jr at chromium dot org) - Pierre Joye (pierre dot php at gmail dot com) - Sam Clegg (sbc at chromium dot org) +- Scott Hancher (seh at google dot com) - Scott LaVarnway (slavarnway at google dot com) - Scott Talbot (s at chikachow dot org) - Slobodan Prijic (slobodan dot prijic at imgtec dot com) - Somnath Banerjee (somnath dot banerjee at gmail dot com) +- Sriraman Tallam (tmsriram at google dot com) +- Tamar Levy (tamar dot levy at intel dot com) - Timothy Gu (timothygu99 at gmail dot com) - Urvang Joshi (urvang at google dot com) - Vikas Arora (vikasa at google dot com) +- Vincent Rabaud (vrabaud at google dot com) +- Vlad Tsyrklevich (vtsyrklevich at chromium dot org) +- Yang Zhang (yang dot zhang at arm dot com) diff --git a/thirdparty/libwebp/src/dec/frame_dec.c b/thirdparty/libwebp/src/dec/frame_dec.c index 517d0f5850..a9d5430d00 100644 --- a/thirdparty/libwebp/src/dec/frame_dec.c +++ b/thirdparty/libwebp/src/dec/frame_dec.c @@ -400,7 +400,9 @@ static void DitherRow(VP8Decoder* const dec) { #define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB // Finalize and transmit a complete row. Return false in case of user-abort. -static int FinishRow(VP8Decoder* const dec, VP8Io* const io) { +static int FinishRow(void* arg1, void* arg2) { + VP8Decoder* const dec = (VP8Decoder*)arg1; + VP8Io* const io = (VP8Io*)arg2; int ok = 1; const VP8ThreadContext* const ctx = &dec->thread_ctx_; const int cache_id = ctx->id_; @@ -448,10 +450,9 @@ static int FinishRow(VP8Decoder* const dec, VP8Io* const io) { if (y_end > io->crop_bottom) { y_end = io->crop_bottom; // make sure we don't overflow on last row. } + // If dec->alpha_data_ is not NULL, we have some alpha plane present. io->a = NULL; if (dec->alpha_data_ != NULL && y_start < y_end) { - // TODO(skal): testing presence of alpha with dec->alpha_data_ is not a - // good idea. io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start); if (io->a == NULL) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, @@ -558,7 +559,6 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) { if (io->bypass_filtering) { dec->filter_type_ = 0; } - // TODO(skal): filter type / strength / sharpness forcing // Define the area where we can skip in-loop filtering, in case of cropping. // @@ -569,8 +569,6 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) { // Means: there's a dependency chain that goes all the way up to the // top-left corner of the picture (MB #0). We must filter all the previous // macroblocks. - // TODO(skal): add an 'approximate_decoding' option, that won't produce - // a 1:1 bit-exactness for complex filtering? { const int extra_pixels = kFilterExtraRows[dec->filter_type_]; if (dec->filter_type_ == 2) { @@ -651,7 +649,7 @@ static int InitThreadContext(VP8Decoder* const dec) { } worker->data1 = dec; worker->data2 = (void*)&dec->thread_ctx_.io_; - worker->hook = (WebPWorkerHook)FinishRow; + worker->hook = FinishRow; dec->num_caches_ = (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; } else { diff --git a/thirdparty/libwebp/src/dec/vp8_dec.c b/thirdparty/libwebp/src/dec/vp8_dec.c index 6212efd179..c904b529f6 100644 --- a/thirdparty/libwebp/src/dec/vp8_dec.c +++ b/thirdparty/libwebp/src/dec/vp8_dec.c @@ -491,7 +491,7 @@ static int GetCoeffsAlt(VP8BitReader* const br, return 16; } -WEBP_TSAN_IGNORE_FUNCTION static void InitGetCoeffs(void) { +static WEBP_TSAN_IGNORE_FUNCTION void InitGetCoeffs(void) { if (GetCoeffs == NULL) { if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) { GetCoeffs = GetCoeffsAlt; diff --git a/thirdparty/libwebp/src/dec/vp8i_dec.h b/thirdparty/libwebp/src/dec/vp8i_dec.h index 28244d9d7a..c929933e1c 100644 --- a/thirdparty/libwebp/src/dec/vp8i_dec.h +++ b/thirdparty/libwebp/src/dec/vp8i_dec.h @@ -30,9 +30,9 @@ extern "C" { // Various defines and enums // version numbers -#define DEC_MAJ_VERSION 0 -#define DEC_MIN_VERSION 6 -#define DEC_REV_VERSION 1 +#define DEC_MAJ_VERSION 1 +#define DEC_MIN_VERSION 0 +#define DEC_REV_VERSION 0 // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // Constraints are: We need to store one 16x16 block of luma samples (y), diff --git a/thirdparty/libwebp/src/dec/vp8l_dec.c b/thirdparty/libwebp/src/dec/vp8l_dec.c index 42ea3b5e4c..0570f53a77 100644 --- a/thirdparty/libwebp/src/dec/vp8l_dec.c +++ b/thirdparty/libwebp/src/dec/vp8l_dec.c @@ -1643,17 +1643,17 @@ int VP8LDecodeImage(VP8LDecoder* const dec) { #if !defined(WEBP_REDUCE_SIZE) if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err; - - if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) { - // need the alpha-multiply functions for premultiplied output or rescaling - WebPInitAlphaProcessing(); - } #else if (io->use_scaling) { dec->status_ = VP8_STATUS_INVALID_PARAM; goto Err; } #endif + if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) { + // need the alpha-multiply functions for premultiplied output or rescaling + WebPInitAlphaProcessing(); + } + if (!WebPIsRGBMode(dec->output_->colorspace)) { WebPInitConvertARGBToYUV(); if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing(); diff --git a/thirdparty/libwebp/src/demux/demux.c b/thirdparty/libwebp/src/demux/demux.c index 79c24a5a7f..684215e3de 100644 --- a/thirdparty/libwebp/src/demux/demux.c +++ b/thirdparty/libwebp/src/demux/demux.c @@ -23,9 +23,9 @@ #include "src/webp/demux.h" #include "src/webp/format_constants.h" -#define DMUX_MAJ_VERSION 0 -#define DMUX_MIN_VERSION 3 -#define DMUX_REV_VERSION 3 +#define DMUX_MAJ_VERSION 1 +#define DMUX_MIN_VERSION 0 +#define DMUX_REV_VERSION 0 typedef struct { size_t start_; // start location of the data diff --git a/thirdparty/libwebp/src/dsp/alpha_processing.c b/thirdparty/libwebp/src/dsp/alpha_processing.c index 590e3bc312..819d1391f2 100644 --- a/thirdparty/libwebp/src/dsp/alpha_processing.c +++ b/thirdparty/libwebp/src/dsp/alpha_processing.c @@ -366,6 +366,16 @@ static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) { return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b); } +#ifdef WORDS_BIGENDIAN +static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g, + const uint8_t* b, int len, uint32_t* out) { + int i; + for (i = 0; i < len; ++i) { + out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]); + } +} +#endif + static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b, int len, int step, uint32_t* out) { int i, offset = 0; @@ -381,6 +391,10 @@ int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int); void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int); int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int); void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size); +#ifdef WORDS_BIGENDIAN +void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g, + const uint8_t* b, int, uint32_t*); +#endif void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b, int len, int step, uint32_t* out); @@ -395,16 +409,14 @@ extern void WebPInitAlphaProcessingSSE2(void); extern void WebPInitAlphaProcessingSSE41(void); extern void WebPInitAlphaProcessingNEON(void); -static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used = - (VP8CPUInfo)&alpha_processing_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) { - if (alpha_processing_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) { WebPMultARGBRow = WebPMultARGBRow_C; WebPMultRow = WebPMultRow_C; WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b_C; +#ifdef WORDS_BIGENDIAN + WebPPackARGB = PackARGB_C; +#endif WebPPackRGB = PackRGB_C; #if !WEBP_NEON_OMIT_C_CODE WebPApplyAlphaMultiply = ApplyAlphaMultiply_C; @@ -451,9 +463,10 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) { assert(WebPDispatchAlphaToGreen != NULL); assert(WebPExtractAlpha != NULL); assert(WebPExtractGreen != NULL); +#ifdef WORDS_BIGENDIAN + assert(WebPPackARGB != NULL); +#endif assert(WebPPackRGB != NULL); assert(WebPHasAlpha8b != NULL); assert(WebPHasAlpha32b != NULL); - - alpha_processing_last_cpuinfo_used = VP8GetCPUInfo; } diff --git a/thirdparty/libwebp/src/dsp/alpha_processing_mips_dsp_r2.c b/thirdparty/libwebp/src/dsp/alpha_processing_mips_dsp_r2.c index e0dc91bab9..0090e87cd1 100644 --- a/thirdparty/libwebp/src/dsp/alpha_processing_mips_dsp_r2.c +++ b/thirdparty/libwebp/src/dsp/alpha_processing_mips_dsp_r2.c @@ -125,6 +125,49 @@ static void MultARGBRow_MIPSdspR2(uint32_t* const ptr, int width, } } +#ifdef WORDS_BIGENDIAN +static void PackARGB_MIPSdspR2(const uint8_t* a, const uint8_t* r, + const uint8_t* g, const uint8_t* b, int len, + uint32_t* out) { + int temp0, temp1, temp2, temp3, offset; + const int rest = len & 1; + const uint32_t* const loop_end = out + len - rest; + const int step = 4; + __asm__ volatile ( + "xor %[offset], %[offset], %[offset] \n\t" + "beq %[loop_end], %[out], 0f \n\t" + "2: \n\t" + "lbux %[temp0], %[offset](%[a]) \n\t" + "lbux %[temp1], %[offset](%[r]) \n\t" + "lbux %[temp2], %[offset](%[g]) \n\t" + "lbux %[temp3], %[offset](%[b]) \n\t" + "ins %[temp1], %[temp0], 16, 16 \n\t" + "ins %[temp3], %[temp2], 16, 16 \n\t" + "addiu %[out], %[out], 4 \n\t" + "precr.qb.ph %[temp0], %[temp1], %[temp3] \n\t" + "sw %[temp0], -4(%[out]) \n\t" + "addu %[offset], %[offset], %[step] \n\t" + "bne %[loop_end], %[out], 2b \n\t" + "0: \n\t" + "beq %[rest], $zero, 1f \n\t" + "lbux %[temp0], %[offset](%[a]) \n\t" + "lbux %[temp1], %[offset](%[r]) \n\t" + "lbux %[temp2], %[offset](%[g]) \n\t" + "lbux %[temp3], %[offset](%[b]) \n\t" + "ins %[temp1], %[temp0], 16, 16 \n\t" + "ins %[temp3], %[temp2], 16, 16 \n\t" + "precr.qb.ph %[temp0], %[temp1], %[temp3] \n\t" + "sw %[temp0], 0(%[out]) \n\t" + "1: \n\t" + : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), + [temp3]"=&r"(temp3), [offset]"=&r"(offset), [out]"+&r"(out) + : [a]"r"(a), [r]"r"(r), [g]"r"(g), [b]"r"(b), [step]"r"(step), + [loop_end]"r"(loop_end), [rest]"r"(rest) + : "memory" + ); +} +#endif // WORDS_BIGENDIAN + static void PackRGB_MIPSdspR2(const uint8_t* r, const uint8_t* g, const uint8_t* b, int len, int step, uint32_t* out) { @@ -172,6 +215,9 @@ extern void WebPInitAlphaProcessingMIPSdspR2(void); WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingMIPSdspR2(void) { WebPDispatchAlpha = DispatchAlpha_MIPSdspR2; WebPMultARGBRow = MultARGBRow_MIPSdspR2; +#ifdef WORDS_BIGENDIAN + WebPPackARGB = PackARGB_MIPSdspR2; +#endif WebPPackRGB = PackRGB_MIPSdspR2; } diff --git a/thirdparty/libwebp/src/dsp/common_sse2.h b/thirdparty/libwebp/src/dsp/common_sse2.h index 995d7cf4ea..e9f1ebff44 100644 --- a/thirdparty/libwebp/src/dsp/common_sse2.h +++ b/thirdparty/libwebp/src/dsp/common_sse2.h @@ -128,9 +128,9 @@ static WEBP_INLINE void VP8Transpose_2_4x4_16b( // Pack the planar buffers // rrrr... rrrr... gggg... gggg... bbbb... bbbb.... // triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... -static WEBP_INLINE void VP8PlanarTo24b(__m128i* const in0, __m128i* const in1, - __m128i* const in2, __m128i* const in3, - __m128i* const in4, __m128i* const in5) { +static WEBP_INLINE void VP8PlanarTo24b_SSE2( + __m128i* const in0, __m128i* const in1, __m128i* const in2, + __m128i* const in3, __m128i* const in4, __m128i* const in5) { // The input is 6 registers of sixteen 8b but for the sake of explanation, // let's take 6 registers of four 8b values. // To pack, we will keep taking one every two 8b integer and move it @@ -159,10 +159,10 @@ static WEBP_INLINE void VP8PlanarTo24b(__m128i* const in0, __m128i* const in1, // Convert four packed four-channel buffers like argbargbargbargb... into the // split channels aaaaa ... rrrr ... gggg .... bbbbb ...... -static WEBP_INLINE void VP8L32bToPlanar(__m128i* const in0, - __m128i* const in1, - __m128i* const in2, - __m128i* const in3) { +static WEBP_INLINE void VP8L32bToPlanar_SSE2(__m128i* const in0, + __m128i* const in1, + __m128i* const in2, + __m128i* const in3) { // Column-wise transpose. const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1); const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1); diff --git a/thirdparty/libwebp/src/dsp/common_sse41.h b/thirdparty/libwebp/src/dsp/common_sse41.h new file mode 100644 index 0000000000..2f173c024a --- /dev/null +++ b/thirdparty/libwebp/src/dsp/common_sse41.h @@ -0,0 +1,132 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE4 code common to several files. +// +// Author: Vincent Rabaud (vrabaud@google.com) + +#ifndef WEBP_DSP_COMMON_SSE41_H_ +#define WEBP_DSP_COMMON_SSE41_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(WEBP_USE_SSE41) +#include <smmintrin.h> + +//------------------------------------------------------------------------------ +// Channel mixing. +// Shuffles the input buffer as A0 0 0 A1 0 0 A2 ... +#define WEBP_SSE41_SHUFF(OUT, IN0, IN1) \ + OUT##0 = _mm_shuffle_epi8(*IN0, shuff0); \ + OUT##1 = _mm_shuffle_epi8(*IN0, shuff1); \ + OUT##2 = _mm_shuffle_epi8(*IN0, shuff2); \ + OUT##3 = _mm_shuffle_epi8(*IN1, shuff0); \ + OUT##4 = _mm_shuffle_epi8(*IN1, shuff1); \ + OUT##5 = _mm_shuffle_epi8(*IN1, shuff2); + +// Pack the planar buffers +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... +static WEBP_INLINE void VP8PlanarTo24b_SSE41( + __m128i* const in0, __m128i* const in1, __m128i* const in2, + __m128i* const in3, __m128i* const in4, __m128i* const in5) { + __m128i R0, R1, R2, R3, R4, R5; + __m128i G0, G1, G2, G3, G4, G5; + __m128i B0, B1, B2, B3, B4, B5; + + // Process R. + { + const __m128i shuff0 = _mm_set_epi8( + 5, -1, -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0); + const __m128i shuff1 = _mm_set_epi8( + -1, 10, -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1); + const __m128i shuff2 = _mm_set_epi8( + -1, -1, 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1); + WEBP_SSE41_SHUFF(R, in0, in1) + } + + // Process G. + { + // Same as before, just shifted to the left by one and including the right + // padding. + const __m128i shuff0 = _mm_set_epi8( + -1, -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1); + const __m128i shuff1 = _mm_set_epi8( + 10, -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1, 5); + const __m128i shuff2 = _mm_set_epi8( + -1, 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1, -1); + WEBP_SSE41_SHUFF(G, in2, in3) + } + + // Process B. + { + const __m128i shuff0 = _mm_set_epi8( + -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1, -1); + const __m128i shuff1 = _mm_set_epi8( + -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1, 5, -1); + const __m128i shuff2 = _mm_set_epi8( + 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1, -1, 10); + WEBP_SSE41_SHUFF(B, in4, in5) + } + + // OR the different channels. + { + const __m128i RG0 = _mm_or_si128(R0, G0); + const __m128i RG1 = _mm_or_si128(R1, G1); + const __m128i RG2 = _mm_or_si128(R2, G2); + const __m128i RG3 = _mm_or_si128(R3, G3); + const __m128i RG4 = _mm_or_si128(R4, G4); + const __m128i RG5 = _mm_or_si128(R5, G5); + *in0 = _mm_or_si128(RG0, B0); + *in1 = _mm_or_si128(RG1, B1); + *in2 = _mm_or_si128(RG2, B2); + *in3 = _mm_or_si128(RG3, B3); + *in4 = _mm_or_si128(RG4, B4); + *in5 = _mm_or_si128(RG5, B5); + } +} + +#undef WEBP_SSE41_SHUFF + +// Convert four packed four-channel buffers like argbargbargbargb... into the +// split channels aaaaa ... rrrr ... gggg .... bbbbb ...... +static WEBP_INLINE void VP8L32bToPlanar_SSE41(__m128i* const in0, + __m128i* const in1, + __m128i* const in2, + __m128i* const in3) { + // aaaarrrrggggbbbb + const __m128i shuff0 = + _mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0); + const __m128i A0 = _mm_shuffle_epi8(*in0, shuff0); + const __m128i A1 = _mm_shuffle_epi8(*in1, shuff0); + const __m128i A2 = _mm_shuffle_epi8(*in2, shuff0); + const __m128i A3 = _mm_shuffle_epi8(*in3, shuff0); + // A0A1R0R1 + // G0G1B0B1 + // A2A3R2R3 + // G0G1B0B1 + const __m128i B0 = _mm_unpacklo_epi32(A0, A1); + const __m128i B1 = _mm_unpackhi_epi32(A0, A1); + const __m128i B2 = _mm_unpacklo_epi32(A2, A3); + const __m128i B3 = _mm_unpackhi_epi32(A2, A3); + *in3 = _mm_unpacklo_epi64(B0, B2); + *in2 = _mm_unpackhi_epi64(B0, B2); + *in1 = _mm_unpacklo_epi64(B1, B3); + *in0 = _mm_unpackhi_epi64(B1, B3); +} + +#endif // WEBP_USE_SSE41 + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_COMMON_SSE41_H_ diff --git a/thirdparty/libwebp/src/dsp/cost.c b/thirdparty/libwebp/src/dsp/cost.c index a732389d58..634ccc2085 100644 --- a/thirdparty/libwebp/src/dsp/cost.c +++ b/thirdparty/libwebp/src/dsp/cost.c @@ -378,12 +378,7 @@ extern void VP8EncDspCostInitMIPS32(void); extern void VP8EncDspCostInitMIPSdspR2(void); extern void VP8EncDspCostInitSSE2(void); -static volatile VP8CPUInfo cost_last_cpuinfo_used = - (VP8CPUInfo)&cost_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInit(void) { - if (cost_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) { VP8GetResidualCost = GetResidualCost_C; VP8SetResidualCoeffs = SetResidualCoeffs_C; @@ -405,8 +400,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInit(void) { } #endif } - - cost_last_cpuinfo_used = VP8GetCPUInfo; } //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/dsp/dec.c b/thirdparty/libwebp/src/dsp/dec.c index 7e82407567..1119842dd3 100644 --- a/thirdparty/libwebp/src/dsp/dec.c +++ b/thirdparty/libwebp/src/dsp/dec.c @@ -741,12 +741,7 @@ extern void VP8DspInitMIPS32(void); extern void VP8DspInitMIPSdspR2(void); extern void VP8DspInitMSA(void); -static volatile VP8CPUInfo dec_last_cpuinfo_used = - (VP8CPUInfo)&dec_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) { - if (dec_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(VP8DspInit) { VP8InitClipTables(); #if !WEBP_NEON_OMIT_C_CODE @@ -889,6 +884,4 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) { assert(VP8PredChroma8[5] != NULL); assert(VP8PredChroma8[6] != NULL); assert(VP8DitherCombine8x8 != NULL); - - dec_last_cpuinfo_used = VP8GetCPUInfo; } diff --git a/thirdparty/libwebp/src/dsp/dsp.h b/thirdparty/libwebp/src/dsp/dsp.h index 99eefe092f..4ab77a5130 100644 --- a/thirdparty/libwebp/src/dsp/dsp.h +++ b/thirdparty/libwebp/src/dsp/dsp.h @@ -141,6 +141,42 @@ extern "C" { #endif #endif +#if defined(WEBP_USE_THREAD) && !defined(_WIN32) +#include <pthread.h> // NOLINT + +#define WEBP_DSP_INIT(func) do { \ + static volatile VP8CPUInfo func ## _last_cpuinfo_used = \ + (VP8CPUInfo)&func ## _last_cpuinfo_used; \ + static pthread_mutex_t func ## _lock = PTHREAD_MUTEX_INITIALIZER; \ + if (pthread_mutex_lock(&func ## _lock)) break; \ + if (func ## _last_cpuinfo_used != VP8GetCPUInfo) func(); \ + func ## _last_cpuinfo_used = VP8GetCPUInfo; \ + (void)pthread_mutex_unlock(&func ## _lock); \ +} while (0) +#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32)) +#define WEBP_DSP_INIT(func) do { \ + static volatile VP8CPUInfo func ## _last_cpuinfo_used = \ + (VP8CPUInfo)&func ## _last_cpuinfo_used; \ + if (func ## _last_cpuinfo_used == VP8GetCPUInfo) break; \ + func(); \ + func ## _last_cpuinfo_used = VP8GetCPUInfo; \ +} while (0) +#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32) + +// Defines an Init + helper function that control multiple initialization of +// function pointers / tables. +/* Usage: + WEBP_DSP_INIT_FUNC(InitFunc) { + ...function body + } +*/ +#define WEBP_DSP_INIT_FUNC(name) \ + static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void); \ + WEBP_TSAN_IGNORE_FUNCTION void name(void) { \ + WEBP_DSP_INIT(name ## _body); \ + } \ + static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void) + #define WEBP_UBSAN_IGNORE_UNDEF #define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW #if defined(__clang__) && defined(__has_attribute) @@ -166,6 +202,13 @@ extern "C" { #define WEBP_SWAP_16BIT_CSP 0 #endif +// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__) +#if !defined(WORDS_BIGENDIAN) && \ + (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \ + (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) +#define WORDS_BIGENDIAN +#endif + typedef enum { kSSE2, kSSE3, @@ -189,7 +232,7 @@ WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; // avoiding a compiler warning. #define WEBP_DSP_INIT_STUB(func) \ extern void func(void); \ - WEBP_TSAN_IGNORE_FUNCTION void func(void) {} + void func(void) {} //------------------------------------------------------------------------------ // Encoding @@ -578,6 +621,13 @@ void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha, int width, int inverse); void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse); +#ifdef WORDS_BIGENDIAN +// ARGB packing function: a/r/g/b input is rgba or bgra order. +extern void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, + const uint8_t* g, const uint8_t* b, int len, + uint32_t* out); +#endif + // RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order. extern void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b, int len, int step, uint32_t* out); diff --git a/thirdparty/libwebp/src/dsp/enc.c b/thirdparty/libwebp/src/dsp/enc.c index 1c807f1df7..fa23b40a30 100644 --- a/thirdparty/libwebp/src/dsp/enc.c +++ b/thirdparty/libwebp/src/dsp/enc.c @@ -740,12 +740,7 @@ extern void VP8EncDspInitMIPS32(void); extern void VP8EncDspInitMIPSdspR2(void); extern void VP8EncDspInitMSA(void); -static volatile VP8CPUInfo enc_last_cpuinfo_used = - (VP8CPUInfo)&enc_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInit(void) { - if (enc_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(VP8EncDspInit) { VP8DspInit(); // common inverse transforms InitTables(); @@ -838,6 +833,4 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInit(void) { assert(VP8EncQuantizeBlockWHT != NULL); assert(VP8Copy4x4 != NULL); assert(VP8Copy16x8 != NULL); - - enc_last_cpuinfo_used = VP8GetCPUInfo; } diff --git a/thirdparty/libwebp/src/dsp/filters.c b/thirdparty/libwebp/src/dsp/filters.c index ca5f877da7..069a22eaef 100644 --- a/thirdparty/libwebp/src/dsp/filters.c +++ b/thirdparty/libwebp/src/dsp/filters.c @@ -238,12 +238,7 @@ extern void VP8FiltersInitMSA(void); extern void VP8FiltersInitNEON(void); extern void VP8FiltersInitSSE2(void); -static volatile VP8CPUInfo filters_last_cpuinfo_used = - (VP8CPUInfo)&filters_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) { - if (filters_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(VP8FiltersInit) { WebPUnfilters[WEBP_FILTER_NONE] = NULL; #if !WEBP_NEON_OMIT_C_CODE WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_C; @@ -289,6 +284,4 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) { assert(WebPFilters[WEBP_FILTER_HORIZONTAL] != NULL); assert(WebPFilters[WEBP_FILTER_VERTICAL] != NULL); assert(WebPFilters[WEBP_FILTER_GRADIENT] != NULL); - - filters_last_cpuinfo_used = VP8GetCPUInfo; } diff --git a/thirdparty/libwebp/src/dsp/lossless.c b/thirdparty/libwebp/src/dsp/lossless.c index 83f553d9ad..f9b3c182d3 100644 --- a/thirdparty/libwebp/src/dsp/lossless.c +++ b/thirdparty/libwebp/src/dsp/lossless.c @@ -577,9 +577,6 @@ extern void VP8LDspInitNEON(void); extern void VP8LDspInitMIPSdspR2(void); extern void VP8LDspInitMSA(void); -static volatile VP8CPUInfo lossless_last_cpuinfo_used = - (VP8CPUInfo)&lossless_last_cpuinfo_used; - #define COPY_PREDICTOR_ARRAY(IN, OUT) do { \ (OUT)[0] = IN##0_C; \ (OUT)[1] = IN##1_C; \ @@ -599,9 +596,7 @@ static volatile VP8CPUInfo lossless_last_cpuinfo_used = (OUT)[15] = IN##0_C; \ } while (0); -WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) { - if (lossless_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(VP8LDspInit) { COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors) COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors_C) COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd) @@ -658,8 +653,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) { assert(VP8LConvertBGRAToRGB565 != NULL); assert(VP8LMapColor32b != NULL); assert(VP8LMapColor8b != NULL); - - lossless_last_cpuinfo_used = VP8GetCPUInfo; } #undef COPY_PREDICTOR_ARRAY diff --git a/thirdparty/libwebp/src/dsp/lossless.h b/thirdparty/libwebp/src/dsp/lossless.h index a99dbda686..b2bbdfc93c 100644 --- a/thirdparty/libwebp/src/dsp/lossless.h +++ b/thirdparty/libwebp/src/dsp/lossless.h @@ -25,10 +25,6 @@ extern "C" { #endif -#ifdef WEBP_EXPERIMENTAL_FEATURES -#include "src/enc/delta_palettization_enc.h" -#endif // WEBP_EXPERIMENTAL_FEATURES - //------------------------------------------------------------------------------ // Decoding diff --git a/thirdparty/libwebp/src/dsp/lossless_enc.c b/thirdparty/libwebp/src/dsp/lossless_enc.c index 92ca3c0542..d608326fef 100644 --- a/thirdparty/libwebp/src/dsp/lossless_enc.c +++ b/thirdparty/libwebp/src/dsp/lossless_enc.c @@ -863,12 +863,7 @@ extern void VP8LEncDspInitMIPS32(void); extern void VP8LEncDspInitMIPSdspR2(void); extern void VP8LEncDspInitMSA(void); -static volatile VP8CPUInfo lossless_enc_last_cpuinfo_used = - (VP8CPUInfo)&lossless_enc_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInit(void) { - if (lossless_enc_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(VP8LEncDspInit) { VP8LDspInit(); #if !WEBP_NEON_OMIT_C_CODE @@ -1011,8 +1006,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInit(void) { assert(VP8LPredictorsSub_C[13] != NULL); assert(VP8LPredictorsSub_C[14] != NULL); assert(VP8LPredictorsSub_C[15] != NULL); - - lossless_enc_last_cpuinfo_used = VP8GetCPUInfo; } //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c index 1eaf35ca8e..f84a9909e1 100644 --- a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c +++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c @@ -46,16 +46,14 @@ static void SubtractGreenFromBlueAndRed_SSE2(uint32_t* argb_data, //------------------------------------------------------------------------------ // Color Transform +#define MK_CST_16(HI, LO) \ + _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) + static void TransformColor_SSE2(const VP8LMultipliers* const m, uint32_t* argb_data, int num_pixels) { - const __m128i mults_rb = _mm_set_epi16( - CST_5b(m->green_to_red_), CST_5b(m->green_to_blue_), - CST_5b(m->green_to_red_), CST_5b(m->green_to_blue_), - CST_5b(m->green_to_red_), CST_5b(m->green_to_blue_), - CST_5b(m->green_to_red_), CST_5b(m->green_to_blue_)); - const __m128i mults_b2 = _mm_set_epi16( - CST_5b(m->red_to_blue_), 0, CST_5b(m->red_to_blue_), 0, - CST_5b(m->red_to_blue_), 0, CST_5b(m->red_to_blue_), 0); + const __m128i mults_rb = MK_CST_16(CST_5b(m->green_to_red_), + CST_5b(m->green_to_blue_)); + const __m128i mults_b2 = MK_CST_16(CST_5b(m->red_to_blue_), 0); const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks const __m128i mask_rb = _mm_set1_epi32(0x00ff00ff); // red-blue masks int i; @@ -85,12 +83,8 @@ static void CollectColorBlueTransforms_SSE2(const uint32_t* argb, int stride, int tile_width, int tile_height, int green_to_blue, int red_to_blue, int histo[]) { - const __m128i mults_r = _mm_set_epi16( - CST_5b(red_to_blue), 0, CST_5b(red_to_blue), 0, - CST_5b(red_to_blue), 0, CST_5b(red_to_blue), 0); - const __m128i mults_g = _mm_set_epi16( - 0, CST_5b(green_to_blue), 0, CST_5b(green_to_blue), - 0, CST_5b(green_to_blue), 0, CST_5b(green_to_blue)); + const __m128i mults_r = MK_CST_16(CST_5b(red_to_blue), 0); + const __m128i mults_g = MK_CST_16(0, CST_5b(green_to_blue)); const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask const __m128i mask_b = _mm_set1_epi32(0x0000ff); // blue mask int y; @@ -135,9 +129,7 @@ static void CollectColorBlueTransforms_SSE2(const uint32_t* argb, int stride, static void CollectColorRedTransforms_SSE2(const uint32_t* argb, int stride, int tile_width, int tile_height, int green_to_red, int histo[]) { - const __m128i mults_g = _mm_set_epi16( - 0, CST_5b(green_to_red), 0, CST_5b(green_to_red), - 0, CST_5b(green_to_red), 0, CST_5b(green_to_red)); + const __m128i mults_g = MK_CST_16(0, CST_5b(green_to_red)); const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask const __m128i mask = _mm_set1_epi32(0xff); @@ -174,6 +166,7 @@ static void CollectColorRedTransforms_SSE2(const uint32_t* argb, int stride, } } #undef SPAN +#undef MK_CST_16 //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse41.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse41.c index 3526a342d3..2e12a712eb 100644 --- a/thirdparty/libwebp/src/dsp/lossless_enc_sse41.c +++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse41.c @@ -18,6 +18,9 @@ #include <smmintrin.h> #include "src/dsp/lossless.h" +// For sign-extended multiplying constants, pre-shifted by 5: +#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5) + //------------------------------------------------------------------------------ // Subtract-Green Transform @@ -39,12 +42,103 @@ static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data, } //------------------------------------------------------------------------------ +// Color Transform + +#define SPAN 8 +static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_blue, int red_to_blue, + int histo[]) { + const __m128i mults_r = _mm_set1_epi16(CST_5b(red_to_blue)); + const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_blue)); + const __m128i mask_g = _mm_set1_epi16(0xff00); // green mask + const __m128i mask_gb = _mm_set1_epi32(0xffff); // green/blue mask + const __m128i mask_b = _mm_set1_epi16(0x00ff); // blue mask + const __m128i shuffler_lo = _mm_setr_epi8(-1, 2, -1, 6, -1, 10, -1, 14, -1, + -1, -1, -1, -1, -1, -1, -1); + const __m128i shuffler_hi = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, + 2, -1, 6, -1, 10, -1, 14); + int y; + for (y = 0; y < tile_height; ++y) { + const uint32_t* const src = argb + y * stride; + int i, x; + for (x = 0; x + SPAN <= tile_width; x += SPAN) { + uint16_t values[SPAN]; + const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]); + const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]); + const __m128i r0 = _mm_shuffle_epi8(in0, shuffler_lo); + const __m128i r1 = _mm_shuffle_epi8(in1, shuffler_hi); + const __m128i r = _mm_or_si128(r0, r1); // r 0 + const __m128i gb0 = _mm_and_si128(in0, mask_gb); + const __m128i gb1 = _mm_and_si128(in1, mask_gb); + const __m128i gb = _mm_packus_epi32(gb0, gb1); // g b + const __m128i g = _mm_and_si128(gb, mask_g); // g 0 + const __m128i A = _mm_mulhi_epi16(r, mults_r); // x dbr + const __m128i B = _mm_mulhi_epi16(g, mults_g); // x dbg + const __m128i C = _mm_sub_epi8(gb, B); // x b' + const __m128i D = _mm_sub_epi8(C, A); // x b'' + const __m128i E = _mm_and_si128(D, mask_b); // 0 b'' + _mm_storeu_si128((__m128i*)values, E); + for (i = 0; i < SPAN; ++i) ++histo[values[i]]; + } + } + { + const int left_over = tile_width & (SPAN - 1); + if (left_over > 0) { + VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride, + left_over, tile_height, + green_to_blue, red_to_blue, histo); + } + } +} + +static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride, + int tile_width, int tile_height, + int green_to_red, int histo[]) { + const __m128i mults_g = _mm_set1_epi16(CST_5b(green_to_red)); + const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask + const __m128i mask = _mm_set1_epi16(0xff); + + int y; + for (y = 0; y < tile_height; ++y) { + const uint32_t* const src = argb + y * stride; + int i, x; + for (x = 0; x + SPAN <= tile_width; x += SPAN) { + uint16_t values[SPAN]; + const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]); + const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]); + const __m128i g0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0 + const __m128i g1 = _mm_and_si128(in1, mask_g); + const __m128i g = _mm_packus_epi32(g0, g1); // g 0 + const __m128i A0 = _mm_srli_epi32(in0, 16); // 0 0 | x r + const __m128i A1 = _mm_srli_epi32(in1, 16); + const __m128i A = _mm_packus_epi32(A0, A1); // x r + const __m128i B = _mm_mulhi_epi16(g, mults_g); // x dr + const __m128i C = _mm_sub_epi8(A, B); // x r' + const __m128i D = _mm_and_si128(C, mask); // 0 r' + _mm_storeu_si128((__m128i*)values, D); + for (i = 0; i < SPAN; ++i) ++histo[values[i]]; + } + } + { + const int left_over = tile_width & (SPAN - 1); + if (left_over > 0) { + VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride, + left_over, tile_height, green_to_red, + histo); + } + } +} + +//------------------------------------------------------------------------------ // Entry point extern void VP8LEncDspInitSSE41(void); WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE41(void) { VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_SSE41; + VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE41; + VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE41; } #else // !WEBP_USE_SSE41 diff --git a/thirdparty/libwebp/src/dsp/lossless_sse2.c b/thirdparty/libwebp/src/dsp/lossless_sse2.c index 653b466cd6..17d7576419 100644 --- a/thirdparty/libwebp/src/dsp/lossless_sse2.c +++ b/thirdparty/libwebp/src/dsp/lossless_sse2.c @@ -453,14 +453,11 @@ static void TransformColorInverse_SSE2(const VP8LMultipliers* const m, int num_pixels, uint32_t* dst) { // sign-extended multiplying constants, pre-shifted by 5. #define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend - const __m128i mults_rb = _mm_set_epi16( - CST(green_to_red_), CST(green_to_blue_), - CST(green_to_red_), CST(green_to_blue_), - CST(green_to_red_), CST(green_to_blue_), - CST(green_to_red_), CST(green_to_blue_)); - const __m128i mults_b2 = _mm_set_epi16( - CST(red_to_blue_), 0, CST(red_to_blue_), 0, - CST(red_to_blue_), 0, CST(red_to_blue_), 0); +#define MK_CST_16(HI, LO) \ + _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) + const __m128i mults_rb = MK_CST_16(CST(green_to_red_), CST(green_to_blue_)); + const __m128i mults_b2 = MK_CST_16(CST(red_to_blue_), 0); +#undef MK_CST_16 #undef CST const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks int i; @@ -503,11 +500,11 @@ static void ConvertBGRAToRGB_SSE2(const uint32_t* src, int num_pixels, __m128i in5 = _mm_loadu_si128(in + 5); __m128i in6 = _mm_loadu_si128(in + 6); __m128i in7 = _mm_loadu_si128(in + 7); - VP8L32bToPlanar(&in0, &in1, &in2, &in3); - VP8L32bToPlanar(&in4, &in5, &in6, &in7); + VP8L32bToPlanar_SSE2(&in0, &in1, &in2, &in3); + VP8L32bToPlanar_SSE2(&in4, &in5, &in6, &in7); // At this points, in1/in5 contains red only, in2/in6 green only ... // Pack the colors in 24b RGB. - VP8PlanarTo24b(&in1, &in5, &in2, &in6, &in3, &in7); + VP8PlanarTo24b_SSE2(&in1, &in5, &in2, &in6, &in3, &in7); _mm_storeu_si128(out + 0, in1); _mm_storeu_si128(out + 1, in5); _mm_storeu_si128(out + 2, in2); diff --git a/thirdparty/libwebp/src/dsp/rescaler.c b/thirdparty/libwebp/src/dsp/rescaler.c index 4b6b7834e5..f307d35056 100644 --- a/thirdparty/libwebp/src/dsp/rescaler.c +++ b/thirdparty/libwebp/src/dsp/rescaler.c @@ -204,11 +204,7 @@ extern void WebPRescalerDspInitMIPSdspR2(void); extern void WebPRescalerDspInitMSA(void); extern void WebPRescalerDspInitNEON(void); -static volatile VP8CPUInfo rescaler_last_cpuinfo_used = - (VP8CPUInfo)&rescaler_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) { - if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return; +WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) { #if !defined(WEBP_REDUCE_SIZE) #if !WEBP_NEON_OMIT_C_CODE WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C; @@ -253,5 +249,4 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) { assert(WebPRescalerImportRowExpand != NULL); assert(WebPRescalerImportRowShrink != NULL); #endif // WEBP_REDUCE_SIZE - rescaler_last_cpuinfo_used = VP8GetCPUInfo; } diff --git a/thirdparty/libwebp/src/dsp/rescaler_sse2.c b/thirdparty/libwebp/src/dsp/rescaler_sse2.c index f93b204fe1..64c50deab5 100644 --- a/thirdparty/libwebp/src/dsp/rescaler_sse2.c +++ b/thirdparty/libwebp/src/dsp/rescaler_sse2.c @@ -36,7 +36,7 @@ static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) { } // input: 8 bytes ABCDEFGH -> output: A0B0C0D0E0F0G0H0 -static void LoadHeightPixels_SSE2(const uint8_t* const src, __m128i* out) { +static void LoadEightPixels_SSE2(const uint8_t* const src, __m128i* out) { const __m128i zero = _mm_setzero_si128(); const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH *out = _mm_unpacklo_epi8(A, zero); @@ -50,13 +50,15 @@ static void RescalerImportRowExpand_SSE2(WebPRescaler* const wrk, int accum = x_add; __m128i cur_pixels; + // SSE2 implementation only works with 16b signed arithmetic at max. + if (wrk->src_width < 8 || accum >= (1 << 15)) { + WebPRescalerImportRowExpand_C(wrk, src); + return; + } + assert(!WebPRescalerInputDone(wrk)); assert(wrk->x_expand); if (wrk->num_channels == 4) { - if (wrk->src_width < 2) { - WebPRescalerImportRowExpand_C(wrk, src); - return; - } LoadTwoPixels_SSE2(src, &cur_pixels); src += 4; while (1) { @@ -75,11 +77,7 @@ static void RescalerImportRowExpand_SSE2(WebPRescaler* const wrk, } else { int left; const uint8_t* const src_limit = src + wrk->src_width - 8; - if (wrk->src_width < 8) { - WebPRescalerImportRowExpand_C(wrk, src); - return; - } - LoadHeightPixels_SSE2(src, &cur_pixels); + LoadEightPixels_SSE2(src, &cur_pixels); src += 7; left = 7; while (1) { @@ -94,7 +92,7 @@ static void RescalerImportRowExpand_SSE2(WebPRescaler* const wrk, if (--left) { cur_pixels = _mm_srli_si128(cur_pixels, 2); } else if (src <= src_limit) { - LoadHeightPixels_SSE2(src, &cur_pixels); + LoadEightPixels_SSE2(src, &cur_pixels); src += 7; left = 7; } else { // tail diff --git a/thirdparty/libwebp/src/dsp/ssim.c b/thirdparty/libwebp/src/dsp/ssim.c index dc1b518a33..989ce8254c 100644 --- a/thirdparty/libwebp/src/dsp/ssim.c +++ b/thirdparty/libwebp/src/dsp/ssim.c @@ -139,12 +139,7 @@ VP8AccumulateSSEFunc VP8AccumulateSSE; extern void VP8SSIMDspInitSSE2(void); -static volatile VP8CPUInfo ssim_last_cpuinfo_used = - (VP8CPUInfo)&ssim_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void VP8SSIMDspInit(void) { - if (ssim_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(VP8SSIMDspInit) { #if !defined(WEBP_REDUCE_SIZE) VP8SSIMGetClipped = SSIMGetClipped_C; VP8SSIMGet = SSIMGet_C; @@ -161,6 +156,4 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8SSIMDspInit(void) { } #endif } - - ssim_last_cpuinfo_used = VP8GetCPUInfo; } diff --git a/thirdparty/libwebp/src/dsp/upsampling.c b/thirdparty/libwebp/src/dsp/upsampling.c index e72626a82a..9b60da5bbb 100644 --- a/thirdparty/libwebp/src/dsp/upsampling.c +++ b/thirdparty/libwebp/src/dsp/upsampling.c @@ -217,13 +217,9 @@ WebPYUV444Converter WebPYUV444Converters[MODE_LAST]; extern void WebPInitYUV444ConvertersMIPSdspR2(void); extern void WebPInitYUV444ConvertersSSE2(void); +extern void WebPInitYUV444ConvertersSSE41(void); -static volatile VP8CPUInfo upsampling_last_cpuinfo_used1 = - (VP8CPUInfo)&upsampling_last_cpuinfo_used1; - -WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void) { - if (upsampling_last_cpuinfo_used1 == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(WebPInitYUV444Converters) { WebPYUV444Converters[MODE_RGBA] = WebPYuv444ToRgba_C; WebPYUV444Converters[MODE_BGRA] = WebPYuv444ToBgra_C; WebPYUV444Converters[MODE_RGB] = WebPYuv444ToRgb_C; @@ -242,29 +238,29 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void) { WebPInitYUV444ConvertersSSE2(); } #endif +#if defined(WEBP_USE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitYUV444ConvertersSSE41(); + } +#endif #if defined(WEBP_USE_MIPS_DSP_R2) if (VP8GetCPUInfo(kMIPSdspR2)) { WebPInitYUV444ConvertersMIPSdspR2(); } #endif } - upsampling_last_cpuinfo_used1 = VP8GetCPUInfo; } //------------------------------------------------------------------------------ // Main calls extern void WebPInitUpsamplersSSE2(void); +extern void WebPInitUpsamplersSSE41(void); extern void WebPInitUpsamplersNEON(void); extern void WebPInitUpsamplersMIPSdspR2(void); extern void WebPInitUpsamplersMSA(void); -static volatile VP8CPUInfo upsampling_last_cpuinfo_used2 = - (VP8CPUInfo)&upsampling_last_cpuinfo_used2; - -WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) { - if (upsampling_last_cpuinfo_used2 == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) { #ifdef FANCY_UPSAMPLING #if !WEBP_NEON_OMIT_C_CODE WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_C; @@ -287,6 +283,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) { WebPInitUpsamplersSSE2(); } #endif +#if defined(WEBP_USE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitUpsamplersSSE41(); + } +#endif #if defined(WEBP_USE_MIPS_DSP_R2) if (VP8GetCPUInfo(kMIPSdspR2)) { WebPInitUpsamplersMIPSdspR2(); @@ -310,6 +311,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) { assert(WebPUpsamplers[MODE_BGRA] != NULL); assert(WebPUpsamplers[MODE_rgbA] != NULL); assert(WebPUpsamplers[MODE_bgrA] != NULL); +#if !defined(WEBP_REDUCE_CSP) || !WEBP_NEON_OMIT_C_CODE assert(WebPUpsamplers[MODE_RGB] != NULL); assert(WebPUpsamplers[MODE_BGR] != NULL); assert(WebPUpsamplers[MODE_ARGB] != NULL); @@ -317,9 +319,9 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) { assert(WebPUpsamplers[MODE_RGB_565] != NULL); assert(WebPUpsamplers[MODE_Argb] != NULL); assert(WebPUpsamplers[MODE_rgbA_4444] != NULL); +#endif #endif // FANCY_UPSAMPLING - upsampling_last_cpuinfo_used2 = VP8GetCPUInfo; } //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/dsp/upsampling_msa.c b/thirdparty/libwebp/src/dsp/upsampling_msa.c index 535ffb772c..99eea70e7d 100644 --- a/thirdparty/libwebp/src/dsp/upsampling_msa.c +++ b/thirdparty/libwebp/src/dsp/upsampling_msa.c @@ -264,6 +264,7 @@ static void YuvToBgr(int y, int u, int v, uint8_t* const bgr) { bgr[2] = Clip8(r1 >> 6); } +#if !defined(WEBP_REDUCE_CSP) static void YuvToRgb565(int y, int u, int v, uint8_t* const rgb) { const int y1 = MultHi(y, 19077); const int r1 = y1 + MultHi(v, 26149) - 14234; @@ -306,6 +307,7 @@ static void YuvToArgb(uint8_t y, uint8_t u, uint8_t v, uint8_t* const argb) { argb[0] = 0xff; YuvToRgb(y, u, v, argb + 1); } +#endif // WEBP_REDUCE_CSP static void YuvToBgra(uint8_t y, uint8_t u, uint8_t v, uint8_t* const bgra) { YuvToBgr(y, u, v, bgra); @@ -317,6 +319,7 @@ static void YuvToRgba(uint8_t y, uint8_t u, uint8_t v, uint8_t* const rgba) { rgba[3] = 0xff; } +#if !defined(WEBP_REDUCE_CSP) static void YuvToRgbLine(const uint8_t* y, const uint8_t* u, const uint8_t* v, uint8_t* dst, int length) { v16u8 R, G, B; @@ -370,6 +373,7 @@ static void YuvToBgrLine(const uint8_t* y, const uint8_t* u, memcpy(dst, temp, length * 3 * sizeof(*dst)); } } +#endif // WEBP_REDUCE_CSP static void YuvToRgbaLine(const uint8_t* y, const uint8_t* u, const uint8_t* v, uint8_t* dst, int length) { @@ -427,6 +431,7 @@ static void YuvToBgraLine(const uint8_t* y, const uint8_t* u, } } +#if !defined(WEBP_REDUCE_CSP) static void YuvToArgbLine(const uint8_t* y, const uint8_t* u, const uint8_t* v, uint8_t* dst, int length) { v16u8 R, G, B; @@ -526,6 +531,7 @@ static void YuvToRgb565Line(const uint8_t* y, const uint8_t* u, memcpy(dst, temp, length * 2 * sizeof(*dst)); } } +#endif // WEBP_REDUCE_CSP #define UPSAMPLE_32PIXELS(a, b, c, d) do { \ v16u8 s = __msa_aver_u_b(a, d); \ diff --git a/thirdparty/libwebp/src/dsp/upsampling_sse2.c b/thirdparty/libwebp/src/dsp/upsampling_sse2.c index fd5d303982..340f1e2ac2 100644 --- a/thirdparty/libwebp/src/dsp/upsampling_sse2.c +++ b/thirdparty/libwebp/src/dsp/upsampling_sse2.c @@ -104,21 +104,6 @@ static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[], Upsample32Pixels_SSE2(r1, r2, out); \ } -#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, \ - top_dst, bottom_dst, cur_x, num_pixels) { \ - int n; \ - for (n = 0; n < (num_pixels); ++n) { \ - FUNC((top_y)[(cur_x) + n], r_u[n], r_v[n], \ - (top_dst) + ((cur_x) + n) * (XSTEP)); \ - } \ - if ((bottom_y) != NULL) { \ - for (n = 0; n < (num_pixels); ++n) { \ - FUNC((bottom_y)[(cur_x) + n], r_u[64 + n], r_v[64 + n], \ - (bottom_dst) + ((cur_x) + n) * (XSTEP)); \ - } \ - } \ -} - #define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \ top_dst, bottom_dst, cur_x) do { \ FUNC##32_SSE2((top_y) + (cur_x), r_u, r_v, (top_dst) + (cur_x) * (XSTEP)); \ @@ -135,7 +120,7 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ int uv_pos, pos; \ /* 16byte-aligned array to cache reconstructed u and v */ \ - uint8_t uv_buf[4 * 32 + 15]; \ + uint8_t uv_buf[14 * 32 + 15] = { 0 }; \ uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ uint8_t* const r_v = r_u + 32; \ \ @@ -160,11 +145,22 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ } \ if (len > 1) { \ const int left_over = ((len + 1) >> 1) - (pos >> 1); \ + uint8_t* const tmp_top_dst = r_u + 4 * 32; \ + uint8_t* const tmp_bottom_dst = tmp_top_dst + 4 * 32; \ + uint8_t* const tmp_top = tmp_bottom_dst + 4 * 32; \ + uint8_t* const tmp_bottom = (bottom_y == NULL) ? NULL : tmp_top + 32; \ assert(left_over > 0); \ UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \ UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \ - CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, \ - pos, len - pos); \ + memcpy(tmp_top, top_y + pos, len - pos); \ + if (bottom_y != NULL) memcpy(tmp_bottom, bottom_y + pos, len - pos); \ + CONVERT2RGB_32(FUNC, XSTEP, tmp_top, tmp_bottom, tmp_top_dst, \ + tmp_bottom_dst, 0); \ + memcpy(top_dst + pos * (XSTEP), tmp_top_dst, (len - pos) * (XSTEP)); \ + if (bottom_y != NULL) { \ + memcpy(bottom_dst + pos * (XSTEP), tmp_bottom_dst, \ + (len - pos) * (XSTEP)); \ + } \ } \ } diff --git a/thirdparty/libwebp/src/dsp/upsampling_sse41.c b/thirdparty/libwebp/src/dsp/upsampling_sse41.c new file mode 100644 index 0000000000..648d456027 --- /dev/null +++ b/thirdparty/libwebp/src/dsp/upsampling_sse41.c @@ -0,0 +1,239 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// SSE41 version of YUV to RGB upsampling functions. +// +// Author: somnath@google.com (Somnath Banerjee) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_SSE41) + +#include <assert.h> +#include <smmintrin.h> +#include <string.h> +#include "src/dsp/yuv.h" + +#ifdef FANCY_UPSAMPLING + +#if !defined(WEBP_REDUCE_CSP) + +// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows +// u = (9*a + 3*b + 3*c + d + 8) / 16 +// = (a + (a + 3*b + 3*c + d) / 8 + 1) / 2 +// = (a + m + 1) / 2 +// where m = (a + 3*b + 3*c + d) / 8 +// = ((a + b + c + d) / 2 + b + c) / 4 +// +// Let's say k = (a + b + c + d) / 4. +// We can compute k as +// k = (s + t + 1) / 2 - ((a^d) | (b^c) | (s^t)) & 1 +// where s = (a + d + 1) / 2 and t = (b + c + 1) / 2 +// +// Then m can be written as +// m = (k + t + 1) / 2 - (((b^c) & (s^t)) | (k^t)) & 1 + +// Computes out = (k + in + 1) / 2 - ((ij & (s^t)) | (k^in)) & 1 +#define GET_M(ij, in, out) do { \ + const __m128i tmp0 = _mm_avg_epu8(k, (in)); /* (k + in + 1) / 2 */ \ + const __m128i tmp1 = _mm_and_si128((ij), st); /* (ij) & (s^t) */ \ + const __m128i tmp2 = _mm_xor_si128(k, (in)); /* (k^in) */ \ + const __m128i tmp3 = _mm_or_si128(tmp1, tmp2); /* ((ij) & (s^t)) | (k^in) */\ + const __m128i tmp4 = _mm_and_si128(tmp3, one); /* & 1 -> lsb_correction */ \ + (out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \ +} while (0) + +// pack and store two alternating pixel rows +#define PACK_AND_STORE(a, b, da, db, out) do { \ + const __m128i t_a = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \ + const __m128i t_b = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \ + const __m128i t_1 = _mm_unpacklo_epi8(t_a, t_b); \ + const __m128i t_2 = _mm_unpackhi_epi8(t_a, t_b); \ + _mm_store_si128(((__m128i*)(out)) + 0, t_1); \ + _mm_store_si128(((__m128i*)(out)) + 1, t_2); \ +} while (0) + +// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels. +#define UPSAMPLE_32PIXELS(r1, r2, out) { \ + const __m128i one = _mm_set1_epi8(1); \ + const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \ + const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \ + const __m128i c = _mm_loadu_si128((const __m128i*)&(r2)[0]); \ + const __m128i d = _mm_loadu_si128((const __m128i*)&(r2)[1]); \ + \ + const __m128i s = _mm_avg_epu8(a, d); /* s = (a + d + 1) / 2 */ \ + const __m128i t = _mm_avg_epu8(b, c); /* t = (b + c + 1) / 2 */ \ + const __m128i st = _mm_xor_si128(s, t); /* st = s^t */ \ + \ + const __m128i ad = _mm_xor_si128(a, d); /* ad = a^d */ \ + const __m128i bc = _mm_xor_si128(b, c); /* bc = b^c */ \ + \ + const __m128i t1 = _mm_or_si128(ad, bc); /* (a^d) | (b^c) */ \ + const __m128i t2 = _mm_or_si128(t1, st); /* (a^d) | (b^c) | (s^t) */ \ + const __m128i t3 = _mm_and_si128(t2, one); /* (a^d) | (b^c) | (s^t) & 1 */ \ + const __m128i t4 = _mm_avg_epu8(s, t); \ + const __m128i k = _mm_sub_epi8(t4, t3); /* k = (a + b + c + d) / 4 */ \ + __m128i diag1, diag2; \ + \ + GET_M(bc, t, diag1); /* diag1 = (a + 3b + 3c + d) / 8 */ \ + GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \ + \ + /* pack the alternate pixels */ \ + PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \ + PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \ +} + +// Turn the macro into a function for reducing code-size when non-critical +static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[], + uint8_t* const out) { + UPSAMPLE_32PIXELS(r1, r2, out); +} + +#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \ + uint8_t r1[17], r2[17]; \ + memcpy(r1, (tb), (num_pixels)); \ + memcpy(r2, (bb), (num_pixels)); \ + /* replicate last byte */ \ + memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \ + memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \ + /* using the shared function instead of the macro saves ~3k code size */ \ + Upsample32Pixels_SSE41(r1, r2, out); \ +} + +#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \ + top_dst, bottom_dst, cur_x) do { \ + FUNC##32_SSE41((top_y) + (cur_x), r_u, r_v, (top_dst) + (cur_x) * (XSTEP)); \ + if ((bottom_y) != NULL) { \ + FUNC##32_SSE41((bottom_y) + (cur_x), r_u + 64, r_v + 64, \ + (bottom_dst) + (cur_x) * (XSTEP)); \ + } \ +} while (0) + +#define SSE4_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ + int uv_pos, pos; \ + /* 16byte-aligned array to cache reconstructed u and v */ \ + uint8_t uv_buf[14 * 32 + 15] = { 0 }; \ + uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ + uint8_t* const r_v = r_u + 32; \ + \ + assert(top_y != NULL); \ + { /* Treat the first pixel in regular way */ \ + const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \ + const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \ + const int u0_t = (top_u[0] + u_diag) >> 1; \ + const int v0_t = (top_v[0] + v_diag) >> 1; \ + FUNC(top_y[0], u0_t, v0_t, top_dst); \ + if (bottom_y != NULL) { \ + const int u0_b = (cur_u[0] + u_diag) >> 1; \ + const int v0_b = (cur_v[0] + v_diag) >> 1; \ + FUNC(bottom_y[0], u0_b, v0_b, bottom_dst); \ + } \ + } \ + /* For UPSAMPLE_32PIXELS, 17 u/v values must be read-able for each block */ \ + for (pos = 1, uv_pos = 0; pos + 32 + 1 <= len; pos += 32, uv_pos += 16) { \ + UPSAMPLE_32PIXELS(top_u + uv_pos, cur_u + uv_pos, r_u); \ + UPSAMPLE_32PIXELS(top_v + uv_pos, cur_v + uv_pos, r_v); \ + CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, pos); \ + } \ + if (len > 1) { \ + const int left_over = ((len + 1) >> 1) - (pos >> 1); \ + uint8_t* const tmp_top_dst = r_u + 4 * 32; \ + uint8_t* const tmp_bottom_dst = tmp_top_dst + 4 * 32; \ + uint8_t* const tmp_top = tmp_bottom_dst + 4 * 32; \ + uint8_t* const tmp_bottom = (bottom_y == NULL) ? NULL : tmp_top + 32; \ + assert(left_over > 0); \ + UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \ + UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \ + memcpy(tmp_top, top_y + pos, len - pos); \ + if (bottom_y != NULL) memcpy(tmp_bottom, bottom_y + pos, len - pos); \ + CONVERT2RGB_32(FUNC, XSTEP, tmp_top, tmp_bottom, tmp_top_dst, \ + tmp_bottom_dst, 0); \ + memcpy(top_dst + pos * (XSTEP), tmp_top_dst, (len - pos) * (XSTEP)); \ + if (bottom_y != NULL) { \ + memcpy(bottom_dst + pos * (XSTEP), tmp_bottom_dst, \ + (len - pos) * (XSTEP)); \ + } \ + } \ +} + +// SSE4 variants of the fancy upsampler. +SSE4_UPSAMPLE_FUNC(UpsampleRgbLinePair_SSE41, VP8YuvToRgb, 3) +SSE4_UPSAMPLE_FUNC(UpsampleBgrLinePair_SSE41, VP8YuvToBgr, 3) + +#undef GET_M +#undef PACK_AND_STORE +#undef UPSAMPLE_32PIXELS +#undef UPSAMPLE_LAST_BLOCK +#undef CONVERT2RGB +#undef CONVERT2RGB_32 +#undef SSE4_UPSAMPLE_FUNC + +#endif // WEBP_REDUCE_CSP + +//------------------------------------------------------------------------------ +// Entry point + +extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; + +extern void WebPInitUpsamplersSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE41(void) { +#if !defined(WEBP_REDUCE_CSP) + WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_SSE41; + WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_SSE41; +#endif // WEBP_REDUCE_CSP +} + +#endif // FANCY_UPSAMPLING + +//------------------------------------------------------------------------------ + +extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; +extern void WebPInitYUV444ConvertersSSE41(void); + +#define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \ +extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len); \ +static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ + uint8_t* dst, int len) { \ + int i; \ + const int max_len = len & ~31; \ + for (i = 0; i < max_len; i += 32) { \ + CALL(y + i, u + i, v + i, dst + i * (XSTEP)); \ + } \ + if (i < len) { /* C-fallback */ \ + CALL_C(y + i, u + i, v + i, dst + i * (XSTEP), len - i); \ + } \ +} + +#if !defined(WEBP_REDUCE_CSP) +YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3); +YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3); +#endif // WEBP_REDUCE_CSP + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE41(void) { +#if !defined(WEBP_REDUCE_CSP) + WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb_SSE41; + WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr_SSE41; +#endif // WEBP_REDUCE_CSP +} + +#else + +WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersSSE41) + +#endif // WEBP_USE_SSE41 + +#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_SSE41)) +WEBP_DSP_INIT_STUB(WebPInitUpsamplersSSE41) +#endif diff --git a/thirdparty/libwebp/src/dsp/yuv.c b/thirdparty/libwebp/src/dsp/yuv.c index bddf81fe09..14e67fc28e 100644 --- a/thirdparty/libwebp/src/dsp/yuv.c +++ b/thirdparty/libwebp/src/dsp/yuv.c @@ -71,15 +71,11 @@ void WebPSamplerProcessPlane(const uint8_t* y, int y_stride, WebPSamplerRowFunc WebPSamplers[MODE_LAST]; extern void WebPInitSamplersSSE2(void); +extern void WebPInitSamplersSSE41(void); extern void WebPInitSamplersMIPS32(void); extern void WebPInitSamplersMIPSdspR2(void); -static volatile VP8CPUInfo yuv_last_cpuinfo_used = - (VP8CPUInfo)&yuv_last_cpuinfo_used; - -WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) { - if (yuv_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(WebPInitSamplers) { WebPSamplers[MODE_RGB] = YuvToRgbRow; WebPSamplers[MODE_RGBA] = YuvToRgbaRow; WebPSamplers[MODE_BGR] = YuvToBgrRow; @@ -99,6 +95,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) { WebPInitSamplersSSE2(); } #endif // WEBP_USE_SSE2 +#if defined(WEBP_USE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitSamplersSSE41(); + } +#endif // WEBP_USE_SSE41 #if defined(WEBP_USE_MIPS32) if (VP8GetCPUInfo(kMIPS32)) { WebPInitSamplersMIPS32(); @@ -110,7 +111,6 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) { } #endif // WEBP_USE_MIPS_DSP_R2 } - yuv_last_cpuinfo_used = VP8GetCPUInfo; } //----------------------------------------------------------------------------- @@ -254,17 +254,13 @@ void (*WebPSharpYUVUpdateRGB)(const int16_t* ref, const int16_t* src, void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len, const uint16_t* best_y, uint16_t* out); -static volatile VP8CPUInfo rgba_to_yuv_last_cpuinfo_used = - (VP8CPUInfo)&rgba_to_yuv_last_cpuinfo_used; - extern void WebPInitConvertARGBToYUVSSE2(void); +extern void WebPInitConvertARGBToYUVSSE41(void); extern void WebPInitConvertARGBToYUVNEON(void); extern void WebPInitSharpYUVSSE2(void); extern void WebPInitSharpYUVNEON(void); -WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) { - if (rgba_to_yuv_last_cpuinfo_used == VP8GetCPUInfo) return; - +WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) { WebPConvertARGBToY = ConvertARGBToY_C; WebPConvertARGBToUV = WebPConvertARGBToUV_C; @@ -286,6 +282,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) { WebPInitSharpYUVSSE2(); } #endif // WEBP_USE_SSE2 +#if defined(WEBP_USE_SSE41) + if (VP8GetCPUInfo(kSSE4_1)) { + WebPInitConvertARGBToYUVSSE41(); + } +#endif // WEBP_USE_SSE41 } #if defined(WEBP_USE_NEON) @@ -304,6 +305,4 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) { assert(WebPSharpYUVUpdateY != NULL); assert(WebPSharpYUVUpdateRGB != NULL); assert(WebPSharpYUVFilterRow != NULL); - - rgba_to_yuv_last_cpuinfo_used = VP8GetCPUInfo; } diff --git a/thirdparty/libwebp/src/dsp/yuv.h b/thirdparty/libwebp/src/dsp/yuv.h index c8a55832d4..eb787270d2 100644 --- a/thirdparty/libwebp/src/dsp/yuv.h +++ b/thirdparty/libwebp/src/dsp/yuv.h @@ -166,6 +166,19 @@ void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, #endif // WEBP_USE_SSE2 +//----------------------------------------------------------------------------- +// SSE41 extra functions (mostly for upsampling_sse41.c) + +#if defined(WEBP_USE_SSE41) + +// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst. +void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); +void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst); + +#endif // WEBP_USE_SSE41 + //------------------------------------------------------------------------------ // RGB -> YUV conversion diff --git a/thirdparty/libwebp/src/dsp/yuv_sse2.c b/thirdparty/libwebp/src/dsp/yuv_sse2.c index 6810bf8d15..baa48d5371 100644 --- a/thirdparty/libwebp/src/dsp/yuv_sse2.c +++ b/thirdparty/libwebp/src/dsp/yuv_sse2.c @@ -180,7 +180,7 @@ static WEBP_INLINE void PlanarTo24b_SSE2(__m128i* const in0, __m128i* const in1, // Repeat the same permutations twice more: // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7 // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7 - VP8PlanarTo24b(in0, in1, in2, in3, in4, in5); + VP8PlanarTo24b_SSE2(in0, in1, in2, in3, in4, in5); _mm_storeu_si128((__m128i*)(rgb + 0), *in0); _mm_storeu_si128((__m128i*)(rgb + 16), *in1); @@ -492,7 +492,7 @@ static WEBP_INLINE void RGB32PackedToPlanar_SSE2(const uint32_t* const argb, __m128i a1 = LOAD_16(argb + 4); __m128i a2 = LOAD_16(argb + 8); __m128i a3 = LOAD_16(argb + 12); - VP8L32bToPlanar(&a0, &a1, &a2, &a3); + VP8L32bToPlanar_SSE2(&a0, &a1, &a2, &a3); rgb[0] = _mm_unpacklo_epi8(a1, zero); rgb[1] = _mm_unpackhi_epi8(a1, zero); rgb[2] = _mm_unpacklo_epi8(a2, zero); diff --git a/thirdparty/libwebp/src/dsp/yuv_sse41.c b/thirdparty/libwebp/src/dsp/yuv_sse41.c new file mode 100644 index 0000000000..579d1f7402 --- /dev/null +++ b/thirdparty/libwebp/src/dsp/yuv_sse41.c @@ -0,0 +1,613 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// YUV->RGB conversion functions +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "src/dsp/yuv.h" + +#if defined(WEBP_USE_SSE41) + +#include "src/dsp/common_sse41.h" +#include <stdlib.h> +#include <smmintrin.h> + +//----------------------------------------------------------------------------- +// Convert spans of 32 pixels to various RGB formats for the fancy upsampler. + +// These constants are 14b fixed-point version of ITU-R BT.601 constants. +// R = (19077 * y + 26149 * v - 14234) >> 6 +// G = (19077 * y - 6419 * u - 13320 * v + 8708) >> 6 +// B = (19077 * y + 33050 * u - 17685) >> 6 +static void ConvertYUV444ToRGB_SSE41(const __m128i* const Y0, + const __m128i* const U0, + const __m128i* const V0, + __m128i* const R, + __m128i* const G, + __m128i* const B) { + const __m128i k19077 = _mm_set1_epi16(19077); + const __m128i k26149 = _mm_set1_epi16(26149); + const __m128i k14234 = _mm_set1_epi16(14234); + // 33050 doesn't fit in a signed short: only use this with unsigned arithmetic + const __m128i k33050 = _mm_set1_epi16((short)33050); + const __m128i k17685 = _mm_set1_epi16(17685); + const __m128i k6419 = _mm_set1_epi16(6419); + const __m128i k13320 = _mm_set1_epi16(13320); + const __m128i k8708 = _mm_set1_epi16(8708); + + const __m128i Y1 = _mm_mulhi_epu16(*Y0, k19077); + + const __m128i R0 = _mm_mulhi_epu16(*V0, k26149); + const __m128i R1 = _mm_sub_epi16(Y1, k14234); + const __m128i R2 = _mm_add_epi16(R1, R0); + + const __m128i G0 = _mm_mulhi_epu16(*U0, k6419); + const __m128i G1 = _mm_mulhi_epu16(*V0, k13320); + const __m128i G2 = _mm_add_epi16(Y1, k8708); + const __m128i G3 = _mm_add_epi16(G0, G1); + const __m128i G4 = _mm_sub_epi16(G2, G3); + + // be careful with the saturated *unsigned* arithmetic here! + const __m128i B0 = _mm_mulhi_epu16(*U0, k33050); + const __m128i B1 = _mm_adds_epu16(B0, Y1); + const __m128i B2 = _mm_subs_epu16(B1, k17685); + + // use logical shift for B2, which can be larger than 32767 + *R = _mm_srai_epi16(R2, 6); // range: [-14234, 30815] + *G = _mm_srai_epi16(G4, 6); // range: [-10953, 27710] + *B = _mm_srli_epi16(B2, 6); // range: [0, 34238] +} + +// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically. +static WEBP_INLINE __m128i Load_HI_16_SSE41(const uint8_t* src) { + const __m128i zero = _mm_setzero_si128(); + return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src)); +} + +// Load and replicate the U/V samples +static WEBP_INLINE __m128i Load_UV_HI_8_SSE41(const uint8_t* src) { + const __m128i zero = _mm_setzero_si128(); + const __m128i tmp0 = _mm_cvtsi32_si128(*(const uint32_t*)src); + const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0); + return _mm_unpacklo_epi16(tmp1, tmp1); // replicate samples +} + +// Convert 32 samples of YUV444 to R/G/B +static void YUV444ToRGB_SSE41(const uint8_t* const y, + const uint8_t* const u, + const uint8_t* const v, + __m128i* const R, __m128i* const G, + __m128i* const B) { + const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_HI_16_SSE41(u), + V0 = Load_HI_16_SSE41(v); + ConvertYUV444ToRGB_SSE41(&Y0, &U0, &V0, R, G, B); +} + +// Convert 32 samples of YUV420 to R/G/B +static void YUV420ToRGB_SSE41(const uint8_t* const y, + const uint8_t* const u, + const uint8_t* const v, + __m128i* const R, __m128i* const G, + __m128i* const B) { + const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_UV_HI_8_SSE41(u), + V0 = Load_UV_HI_8_SSE41(v); + ConvertYUV444ToRGB_SSE41(&Y0, &U0, &V0, R, G, B); +} + +// Pack the planar buffers +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ... +static WEBP_INLINE void PlanarTo24b_SSE41( + __m128i* const in0, __m128i* const in1, __m128i* const in2, + __m128i* const in3, __m128i* const in4, __m128i* const in5, + uint8_t* const rgb) { + // The input is 6 registers of sixteen 8b but for the sake of explanation, + // let's take 6 registers of four 8b values. + // To pack, we will keep taking one every two 8b integer and move it + // around as follows: + // Input: + // r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7 + // Split the 6 registers in two sets of 3 registers: the first set as the even + // 8b bytes, the second the odd ones: + // r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7 + // Repeat the same permutations twice more: + // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7 + // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7 + VP8PlanarTo24b_SSE41(in0, in1, in2, in3, in4, in5); + + _mm_storeu_si128((__m128i*)(rgb + 0), *in0); + _mm_storeu_si128((__m128i*)(rgb + 16), *in1); + _mm_storeu_si128((__m128i*)(rgb + 32), *in2); + _mm_storeu_si128((__m128i*)(rgb + 48), *in3); + _mm_storeu_si128((__m128i*)(rgb + 64), *in4); + _mm_storeu_si128((__m128i*)(rgb + 80), *in5); +} + +void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; + + YUV444ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV444ToRGB_SSE41(y + 8, u + 8, v + 8, &R1, &G1, &B1); + YUV444ToRGB_SSE41(y + 16, u + 16, v + 16, &R2, &G2, &B2); + YUV444ToRGB_SSE41(y + 24, u + 24, v + 24, &R3, &G3, &B3); + + // Cast to 8b and store as RRRRGGGGBBBB. + rgb0 = _mm_packus_epi16(R0, R1); + rgb1 = _mm_packus_epi16(R2, R3); + rgb2 = _mm_packus_epi16(G0, G1); + rgb3 = _mm_packus_epi16(G2, G3); + rgb4 = _mm_packus_epi16(B0, B1); + rgb5 = _mm_packus_epi16(B2, B3); + + // Pack as RGBRGBRGBRGB. + PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); +} + +void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, + uint8_t* dst) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; + + YUV444ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV444ToRGB_SSE41(y + 8, u + 8, v + 8, &R1, &G1, &B1); + YUV444ToRGB_SSE41(y + 16, u + 16, v + 16, &R2, &G2, &B2); + YUV444ToRGB_SSE41(y + 24, u + 24, v + 24, &R3, &G3, &B3); + + // Cast to 8b and store as BBBBGGGGRRRR. + bgr0 = _mm_packus_epi16(B0, B1); + bgr1 = _mm_packus_epi16(B2, B3); + bgr2 = _mm_packus_epi16(G0, G1); + bgr3 = _mm_packus_epi16(G2, G3); + bgr4 = _mm_packus_epi16(R0, R1); + bgr5= _mm_packus_epi16(R2, R3); + + // Pack as BGRBGRBGRBGR. + PlanarTo24b_SSE41(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst); +} + +//----------------------------------------------------------------------------- +// Arbitrary-length row conversion functions + +static void YuvToRgbRow_SSE41(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + int n; + for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; + + YUV420ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV420ToRGB_SSE41(y + 8, u + 4, v + 4, &R1, &G1, &B1); + YUV420ToRGB_SSE41(y + 16, u + 8, v + 8, &R2, &G2, &B2); + YUV420ToRGB_SSE41(y + 24, u + 12, v + 12, &R3, &G3, &B3); + + // Cast to 8b and store as RRRRGGGGBBBB. + rgb0 = _mm_packus_epi16(R0, R1); + rgb1 = _mm_packus_epi16(R2, R3); + rgb2 = _mm_packus_epi16(G0, G1); + rgb3 = _mm_packus_epi16(G2, G3); + rgb4 = _mm_packus_epi16(B0, B1); + rgb5 = _mm_packus_epi16(B2, B3); + + // Pack as RGBRGBRGBRGB. + PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); + + y += 32; + u += 16; + v += 16; + } + for (; n < len; ++n) { // Finish off + VP8YuvToRgb(y[0], u[0], v[0], dst); + dst += 3; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +static void YuvToBgrRow_SSE41(const uint8_t* y, + const uint8_t* u, const uint8_t* v, + uint8_t* dst, int len) { + int n; + for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { + __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; + __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; + + YUV420ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0); + YUV420ToRGB_SSE41(y + 8, u + 4, v + 4, &R1, &G1, &B1); + YUV420ToRGB_SSE41(y + 16, u + 8, v + 8, &R2, &G2, &B2); + YUV420ToRGB_SSE41(y + 24, u + 12, v + 12, &R3, &G3, &B3); + + // Cast to 8b and store as BBBBGGGGRRRR. + bgr0 = _mm_packus_epi16(B0, B1); + bgr1 = _mm_packus_epi16(B2, B3); + bgr2 = _mm_packus_epi16(G0, G1); + bgr3 = _mm_packus_epi16(G2, G3); + bgr4 = _mm_packus_epi16(R0, R1); + bgr5 = _mm_packus_epi16(R2, R3); + + // Pack as BGRBGRBGRBGR. + PlanarTo24b_SSE41(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst); + + y += 32; + u += 16; + v += 16; + } + for (; n < len; ++n) { // Finish off + VP8YuvToBgr(y[0], u[0], v[0], dst); + dst += 3; + y += 1; + u += (n & 1); + v += (n & 1); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void WebPInitSamplersSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE41(void) { + WebPSamplers[MODE_RGB] = YuvToRgbRow_SSE41; + WebPSamplers[MODE_BGR] = YuvToBgrRow_SSE41; +} + +//------------------------------------------------------------------------------ +// RGB24/32 -> YUV converters + +// Load eight 16b-words from *src. +#define LOAD_16(src) _mm_loadu_si128((const __m128i*)(src)) +// Store either 16b-words into *dst +#define STORE_16(V, dst) _mm_storeu_si128((__m128i*)(dst), (V)) + +#define WEBP_SSE41_SHUFF(OUT) do { \ + const __m128i tmp0 = _mm_shuffle_epi8(A0, shuff0); \ + const __m128i tmp1 = _mm_shuffle_epi8(A1, shuff1); \ + const __m128i tmp2 = _mm_shuffle_epi8(A2, shuff2); \ + const __m128i tmp3 = _mm_shuffle_epi8(A3, shuff0); \ + const __m128i tmp4 = _mm_shuffle_epi8(A4, shuff1); \ + const __m128i tmp5 = _mm_shuffle_epi8(A5, shuff2); \ + \ + /* OR everything to get one channel */ \ + const __m128i tmp6 = _mm_or_si128(tmp0, tmp1); \ + const __m128i tmp7 = _mm_or_si128(tmp3, tmp4); \ + out[OUT + 0] = _mm_or_si128(tmp6, tmp2); \ + out[OUT + 1] = _mm_or_si128(tmp7, tmp5); \ +} while (0); + +// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers: +// rrrr... rrrr... gggg... gggg... bbbb... bbbb.... +// Similar to PlanarTo24bHelper(), but in reverse order. +static WEBP_INLINE void RGB24PackedToPlanar_SSE41( + const uint8_t* const rgb, __m128i* const out /*out[6]*/) { + const __m128i A0 = _mm_loadu_si128((const __m128i*)(rgb + 0)); + const __m128i A1 = _mm_loadu_si128((const __m128i*)(rgb + 16)); + const __m128i A2 = _mm_loadu_si128((const __m128i*)(rgb + 32)); + const __m128i A3 = _mm_loadu_si128((const __m128i*)(rgb + 48)); + const __m128i A4 = _mm_loadu_si128((const __m128i*)(rgb + 64)); + const __m128i A5 = _mm_loadu_si128((const __m128i*)(rgb + 80)); + + // Compute RR. + { + const __m128i shuff0 = _mm_set_epi8( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 12, 9, 6, 3, 0); + const __m128i shuff1 = _mm_set_epi8( + -1, -1, -1, -1, -1, 14, 11, 8, 5, 2, -1, -1, -1, -1, -1, -1); + const __m128i shuff2 = _mm_set_epi8( + 13, 10, 7, 4, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + WEBP_SSE41_SHUFF(0) + } + // Compute GG. + { + const __m128i shuff0 = _mm_set_epi8( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 10, 7, 4, 1); + const __m128i shuff1 = _mm_set_epi8( + -1, -1, -1, -1, -1, 15, 12, 9, 6, 3, 0, -1, -1, -1, -1, -1); + const __m128i shuff2 = _mm_set_epi8( + 14, 11, 8, 5, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + WEBP_SSE41_SHUFF(2) + } + // Compute BB. + { + const __m128i shuff0 = _mm_set_epi8( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, 11, 8, 5, 2); + const __m128i shuff1 = _mm_set_epi8( + -1, -1, -1, -1, -1, -1, 13, 10, 7, 4, 1, -1, -1, -1, -1, -1); + const __m128i shuff2 = _mm_set_epi8( + 15, 12, 9, 6, 3, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + WEBP_SSE41_SHUFF(4) + } +} + +#undef WEBP_SSE41_SHUFF + +// Convert 8 packed ARGB to r[], g[], b[] +static WEBP_INLINE void RGB32PackedToPlanar_SSE41( + const uint32_t* const argb, __m128i* const rgb /*in[6]*/) { + const __m128i zero = _mm_setzero_si128(); + __m128i a0 = LOAD_16(argb + 0); + __m128i a1 = LOAD_16(argb + 4); + __m128i a2 = LOAD_16(argb + 8); + __m128i a3 = LOAD_16(argb + 12); + VP8L32bToPlanar_SSE41(&a0, &a1, &a2, &a3); + rgb[0] = _mm_unpacklo_epi8(a1, zero); + rgb[1] = _mm_unpackhi_epi8(a1, zero); + rgb[2] = _mm_unpacklo_epi8(a2, zero); + rgb[3] = _mm_unpackhi_epi8(a2, zero); + rgb[4] = _mm_unpacklo_epi8(a3, zero); + rgb[5] = _mm_unpackhi_epi8(a3, zero); +} + +// This macro computes (RG * MULT_RG + GB * MULT_GB + ROUNDER) >> DESCALE_FIX +// It's a macro and not a function because we need to use immediate values with +// srai_epi32, e.g. +#define TRANSFORM(RG_LO, RG_HI, GB_LO, GB_HI, MULT_RG, MULT_GB, \ + ROUNDER, DESCALE_FIX, OUT) do { \ + const __m128i V0_lo = _mm_madd_epi16(RG_LO, MULT_RG); \ + const __m128i V0_hi = _mm_madd_epi16(RG_HI, MULT_RG); \ + const __m128i V1_lo = _mm_madd_epi16(GB_LO, MULT_GB); \ + const __m128i V1_hi = _mm_madd_epi16(GB_HI, MULT_GB); \ + const __m128i V2_lo = _mm_add_epi32(V0_lo, V1_lo); \ + const __m128i V2_hi = _mm_add_epi32(V0_hi, V1_hi); \ + const __m128i V3_lo = _mm_add_epi32(V2_lo, ROUNDER); \ + const __m128i V3_hi = _mm_add_epi32(V2_hi, ROUNDER); \ + const __m128i V5_lo = _mm_srai_epi32(V3_lo, DESCALE_FIX); \ + const __m128i V5_hi = _mm_srai_epi32(V3_hi, DESCALE_FIX); \ + (OUT) = _mm_packs_epi32(V5_lo, V5_hi); \ +} while (0) + +#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A)) +static WEBP_INLINE void ConvertRGBToY_SSE41(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + __m128i* const Y) { + const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384); + const __m128i kGB_y = MK_CST_16(16384, 6420); + const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF); + + const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G); + const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G); + const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B); + const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y); +} + +static WEBP_INLINE void ConvertRGBToUV_SSE41(const __m128i* const R, + const __m128i* const G, + const __m128i* const B, + __m128i* const U, + __m128i* const V) { + const __m128i kRG_u = MK_CST_16(-9719, -19081); + const __m128i kGB_u = MK_CST_16(0, 28800); + const __m128i kRG_v = MK_CST_16(28800, 0); + const __m128i kGB_v = MK_CST_16(-24116, -4684); + const __m128i kHALF_UV = _mm_set1_epi32(((128 << YUV_FIX) + YUV_HALF) << 2); + + const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G); + const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G); + const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B); + const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_u, kGB_u, + kHALF_UV, YUV_FIX + 2, *U); + TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_v, kGB_v, + kHALF_UV, YUV_FIX + 2, *V); +} + +#undef MK_CST_16 +#undef TRANSFORM + +static void ConvertRGB24ToY_SSE41(const uint8_t* rgb, uint8_t* y, int width) { + const int max_width = width & ~31; + int i; + for (i = 0; i < max_width; rgb += 3 * 16 * 2) { + __m128i rgb_plane[6]; + int j; + + RGB24PackedToPlanar_SSE41(rgb, rgb_plane); + + for (j = 0; j < 2; ++j, i += 16) { + const __m128i zero = _mm_setzero_si128(); + __m128i r, g, b, Y0, Y1; + + // Convert to 16-bit Y. + r = _mm_unpacklo_epi8(rgb_plane[0 + j], zero); + g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero); + b = _mm_unpacklo_epi8(rgb_plane[4 + j], zero); + ConvertRGBToY_SSE41(&r, &g, &b, &Y0); + + // Convert to 16-bit Y. + r = _mm_unpackhi_epi8(rgb_plane[0 + j], zero); + g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero); + b = _mm_unpackhi_epi8(rgb_plane[4 + j], zero); + ConvertRGBToY_SSE41(&r, &g, &b, &Y1); + + // Cast to 8-bit and store. + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + } + for (; i < width; ++i, rgb += 3) { // left-over + y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF); + } +} + +static void ConvertBGR24ToY_SSE41(const uint8_t* bgr, uint8_t* y, int width) { + const int max_width = width & ~31; + int i; + for (i = 0; i < max_width; bgr += 3 * 16 * 2) { + __m128i bgr_plane[6]; + int j; + + RGB24PackedToPlanar_SSE41(bgr, bgr_plane); + + for (j = 0; j < 2; ++j, i += 16) { + const __m128i zero = _mm_setzero_si128(); + __m128i r, g, b, Y0, Y1; + + // Convert to 16-bit Y. + b = _mm_unpacklo_epi8(bgr_plane[0 + j], zero); + g = _mm_unpacklo_epi8(bgr_plane[2 + j], zero); + r = _mm_unpacklo_epi8(bgr_plane[4 + j], zero); + ConvertRGBToY_SSE41(&r, &g, &b, &Y0); + + // Convert to 16-bit Y. + b = _mm_unpackhi_epi8(bgr_plane[0 + j], zero); + g = _mm_unpackhi_epi8(bgr_plane[2 + j], zero); + r = _mm_unpackhi_epi8(bgr_plane[4 + j], zero); + ConvertRGBToY_SSE41(&r, &g, &b, &Y1); + + // Cast to 8-bit and store. + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + } + for (; i < width; ++i, bgr += 3) { // left-over + y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF); + } +} + +static void ConvertARGBToY_SSE41(const uint32_t* argb, uint8_t* y, int width) { + const int max_width = width & ~15; + int i; + for (i = 0; i < max_width; i += 16) { + __m128i Y0, Y1, rgb[6]; + RGB32PackedToPlanar_SSE41(&argb[i], rgb); + ConvertRGBToY_SSE41(&rgb[0], &rgb[2], &rgb[4], &Y0); + ConvertRGBToY_SSE41(&rgb[1], &rgb[3], &rgb[5], &Y1); + STORE_16(_mm_packus_epi16(Y0, Y1), y + i); + } + for (; i < width; ++i) { // left-over + const uint32_t p = argb[i]; + y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff, + YUV_HALF); + } +} + +// Horizontal add (doubled) of two 16b values, result is 16b. +// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ... +static void HorizontalAddPack_SSE41(const __m128i* const A, + const __m128i* const B, + __m128i* const out) { + const __m128i k2 = _mm_set1_epi16(2); + const __m128i C = _mm_madd_epi16(*A, k2); + const __m128i D = _mm_madd_epi16(*B, k2); + *out = _mm_packs_epi32(C, D); +} + +static void ConvertARGBToUV_SSE41(const uint32_t* argb, + uint8_t* u, uint8_t* v, + int src_width, int do_store) { + const int max_width = src_width & ~31; + int i; + for (i = 0; i < max_width; i += 32, u += 16, v += 16) { + __m128i rgb[6], U0, V0, U1, V1; + RGB32PackedToPlanar_SSE41(&argb[i], rgb); + HorizontalAddPack_SSE41(&rgb[0], &rgb[1], &rgb[0]); + HorizontalAddPack_SSE41(&rgb[2], &rgb[3], &rgb[2]); + HorizontalAddPack_SSE41(&rgb[4], &rgb[5], &rgb[4]); + ConvertRGBToUV_SSE41(&rgb[0], &rgb[2], &rgb[4], &U0, &V0); + + RGB32PackedToPlanar_SSE41(&argb[i + 16], rgb); + HorizontalAddPack_SSE41(&rgb[0], &rgb[1], &rgb[0]); + HorizontalAddPack_SSE41(&rgb[2], &rgb[3], &rgb[2]); + HorizontalAddPack_SSE41(&rgb[4], &rgb[5], &rgb[4]); + ConvertRGBToUV_SSE41(&rgb[0], &rgb[2], &rgb[4], &U1, &V1); + + U0 = _mm_packus_epi16(U0, U1); + V0 = _mm_packus_epi16(V0, V1); + if (!do_store) { + const __m128i prev_u = LOAD_16(u); + const __m128i prev_v = LOAD_16(v); + U0 = _mm_avg_epu8(U0, prev_u); + V0 = _mm_avg_epu8(V0, prev_v); + } + STORE_16(U0, u); + STORE_16(V0, v); + } + if (i < src_width) { // left-over + WebPConvertARGBToUV_C(argb + i, u, v, src_width - i, do_store); + } +} + +// Convert 16 packed ARGB 16b-values to r[], g[], b[] +static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE41( + const uint16_t* const rgbx, + __m128i* const r, __m128i* const g, __m128i* const b) { + const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x + const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x + const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ... + const __m128i in3 = LOAD_16(rgbx + 24); // r6 | ... + // aarrggbb as 16-bit. + const __m128i shuff0 = + _mm_set_epi8(-1, -1, -1, -1, 13, 12, 5, 4, 11, 10, 3, 2, 9, 8, 1, 0); + const __m128i shuff1 = + _mm_set_epi8(13, 12, 5, 4, -1, -1, -1, -1, 11, 10, 3, 2, 9, 8, 1, 0); + const __m128i A0 = _mm_shuffle_epi8(in0, shuff0); + const __m128i A1 = _mm_shuffle_epi8(in1, shuff1); + const __m128i A2 = _mm_shuffle_epi8(in2, shuff0); + const __m128i A3 = _mm_shuffle_epi8(in3, shuff1); + // R0R1G0G1 + // B0B1**** + // R2R3G2G3 + // B2B3**** + // (OR is used to free port 5 for the unpack) + const __m128i B0 = _mm_unpacklo_epi32(A0, A1); + const __m128i B1 = _mm_or_si128(A0, A1); + const __m128i B2 = _mm_unpacklo_epi32(A2, A3); + const __m128i B3 = _mm_or_si128(A2, A3); + // Gather the channels. + *r = _mm_unpacklo_epi64(B0, B2); + *g = _mm_unpackhi_epi64(B0, B2); + *b = _mm_unpackhi_epi64(B1, B3); +} + +static void ConvertRGBA32ToUV_SSE41(const uint16_t* rgb, + uint8_t* u, uint8_t* v, int width) { + const int max_width = width & ~15; + const uint16_t* const last_rgb = rgb + 4 * max_width; + while (rgb < last_rgb) { + __m128i r, g, b, U0, V0, U1, V1; + RGBA32PackedToPlanar_16b_SSE41(rgb + 0, &r, &g, &b); + ConvertRGBToUV_SSE41(&r, &g, &b, &U0, &V0); + RGBA32PackedToPlanar_16b_SSE41(rgb + 32, &r, &g, &b); + ConvertRGBToUV_SSE41(&r, &g, &b, &U1, &V1); + STORE_16(_mm_packus_epi16(U0, U1), u); + STORE_16(_mm_packus_epi16(V0, V1), v); + u += 16; + v += 16; + rgb += 2 * 32; + } + if (max_width < width) { // left-over + WebPConvertRGBA32ToUV_C(rgb, u, v, width - max_width); + } +} + +//------------------------------------------------------------------------------ + +extern void WebPInitConvertARGBToYUVSSE41(void); + +WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE41(void) { + WebPConvertARGBToY = ConvertARGBToY_SSE41; + WebPConvertARGBToUV = ConvertARGBToUV_SSE41; + + WebPConvertRGB24ToY = ConvertRGB24ToY_SSE41; + WebPConvertBGR24ToY = ConvertBGR24ToY_SSE41; + + WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE41; +} + +//------------------------------------------------------------------------------ + +#else // !WEBP_USE_SSE41 + +WEBP_DSP_INIT_STUB(WebPInitSamplersSSE41) +WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE41) + +#endif // WEBP_USE_SSE41 diff --git a/thirdparty/libwebp/src/enc/alpha_enc.c b/thirdparty/libwebp/src/enc/alpha_enc.c index 7e8d87f22e..dce9ca957d 100644 --- a/thirdparty/libwebp/src/enc/alpha_enc.c +++ b/thirdparty/libwebp/src/enc/alpha_enc.c @@ -361,7 +361,8 @@ static int EncodeAlpha(VP8Encoder* const enc, //------------------------------------------------------------------------------ // Main calls -static int CompressAlphaJob(VP8Encoder* const enc, void* dummy) { +static int CompressAlphaJob(void* arg1, void* dummy) { + VP8Encoder* const enc = (VP8Encoder*)arg1; const WebPConfig* config = enc->config_; uint8_t* alpha_data = NULL; size_t alpha_size = 0; @@ -394,7 +395,7 @@ void VP8EncInitAlpha(VP8Encoder* const enc) { WebPGetWorkerInterface()->Init(worker); worker->data1 = enc; worker->data2 = NULL; - worker->hook = (WebPWorkerHook)CompressAlphaJob; + worker->hook = CompressAlphaJob; } } diff --git a/thirdparty/libwebp/src/enc/analysis_enc.c b/thirdparty/libwebp/src/enc/analysis_enc.c index 08f471f5f8..a47ff7d4e8 100644 --- a/thirdparty/libwebp/src/enc/analysis_enc.c +++ b/thirdparty/libwebp/src/enc/analysis_enc.c @@ -434,7 +434,9 @@ typedef struct { } SegmentJob; // main work call -static int DoSegmentsJob(SegmentJob* const job, VP8EncIterator* const it) { +static int DoSegmentsJob(void* arg1, void* arg2) { + SegmentJob* const job = (SegmentJob*)arg1; + VP8EncIterator* const it = (VP8EncIterator*)arg2; int ok = 1; if (!VP8IteratorIsDone(it)) { uint8_t tmp[32 + WEBP_ALIGN_CST]; @@ -462,7 +464,7 @@ static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job, WebPGetWorkerInterface()->Init(&job->worker); job->worker.data1 = job; job->worker.data2 = &job->it; - job->worker.hook = (WebPWorkerHook)DoSegmentsJob; + job->worker.hook = DoSegmentsJob; VP8IteratorInit(enc, &job->it); VP8IteratorSetRow(&job->it, start_row); VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_); diff --git a/thirdparty/libwebp/src/enc/frame_enc.c b/thirdparty/libwebp/src/enc/frame_enc.c index 2b0dc66410..1aec376e44 100644 --- a/thirdparty/libwebp/src/enc/frame_enc.c +++ b/thirdparty/libwebp/src/enc/frame_enc.c @@ -198,7 +198,7 @@ static void SetSegmentProbas(VP8Encoder* const enc) { for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { const VP8MBInfo* const mb = &enc->mb_info_[n]; - p[mb->segment_]++; + ++p[mb->segment_]; } #if !defined(WEBP_DISABLE_STATS) if (enc->pic_->stats != NULL) { @@ -520,6 +520,14 @@ static void StoreSideInfo(const VP8EncIterator* const it) { #endif } +static void ResetSideInfo(const VP8EncIterator* const it) { + VP8Encoder* const enc = it->enc_; + WebPPicture* const pic = enc->pic_; + if (pic->stats != NULL) { + memset(enc->block_count_, 0, sizeof(enc->block_count_)); + } + ResetSSE(enc); +} #else // defined(WEBP_DISABLE_STATS) static void ResetSSE(VP8Encoder* const enc) { (void)enc; @@ -528,10 +536,16 @@ static void StoreSideInfo(const VP8EncIterator* const it) { VP8Encoder* const enc = it->enc_; WebPPicture* const pic = enc->pic_; if (pic->extra_info != NULL) { - memset(pic->extra_info, 0, - enc->mb_w_ * enc->mb_h_ * sizeof(*pic->extra_info)); + if (it->x_ == 0 && it->y_ == 0) { // only do it once, at start + memset(pic->extra_info, 0, + enc->mb_w_ * enc->mb_h_ * sizeof(*pic->extra_info)); + } } } + +static void ResetSideInfo(const VP8EncIterator* const it) { + (void)it; +} #endif // !defined(WEBP_DISABLE_STATS) static double GetPSNR(uint64_t mse, uint64_t size) { @@ -570,7 +584,7 @@ static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt, VP8IteratorImport(&it, NULL); if (VP8Decimate(&it, &info, rd_opt)) { // Just record the number of skips and act like skip_proba is not used. - enc->proba_.nb_skip_++; + ++enc->proba_.nb_skip_; } RecordResiduals(&it, &info); size += info.R + info.H; @@ -841,6 +855,9 @@ int VP8EncTokenLoop(VP8Encoder* const enc) { if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { ++num_pass_left; enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation... + if (is_last_pass) { + ResetSideInfo(&it); + } continue; // ...and start over } if (is_last_pass) { @@ -871,4 +888,3 @@ int VP8EncTokenLoop(VP8Encoder* const enc) { #endif // DISABLE_TOKEN_BUFFER //------------------------------------------------------------------------------ - diff --git a/thirdparty/libwebp/src/enc/histogram_enc.c b/thirdparty/libwebp/src/enc/histogram_enc.c index 056a972dda..9fdbc627a1 100644 --- a/thirdparty/libwebp/src/enc/histogram_enc.c +++ b/thirdparty/libwebp/src/enc/histogram_enc.c @@ -200,14 +200,9 @@ static WEBP_INLINE double BitsEntropyRefine(const VP8LBitEntropy* entropy) { } } -double VP8LBitsEntropy(const uint32_t* const array, int n, - uint32_t* const trivial_symbol) { +double VP8LBitsEntropy(const uint32_t* const array, int n) { VP8LBitEntropy entropy; VP8LBitsEntropyUnrefined(array, n, &entropy); - if (trivial_symbol != NULL) { - *trivial_symbol = - (entropy.nonzeros == 1) ? entropy.nonzero_code : VP8L_NON_TRIVIAL_SYM; - } return BitsEntropyRefine(&entropy); } @@ -605,7 +600,7 @@ static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo, } // Implement a Lehmer random number generator with a multiplicative constant of -// 48271 and a modulo constant of 2^31 − 1. +// 48271 and a modulo constant of 2^31 - 1. static uint32_t MyRand(uint32_t* const seed) { *seed = (uint32_t)(((uint64_t)(*seed) * 48271u) % 2147483647u); assert(*seed > 0); @@ -1031,7 +1026,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, } } - // TODO(vikasa): Optimize HistogramRemap for low-effort compression mode also. + // TODO(vrabaud): Optimize HistogramRemap for low-effort compression mode. // Find the optimal map from original histograms to the final ones. HistogramRemap(orig_histo, image_histo, histogram_symbols); diff --git a/thirdparty/libwebp/src/enc/histogram_enc.h b/thirdparty/libwebp/src/enc/histogram_enc.h index 15b1fbda34..e8c4c83f6f 100644 --- a/thirdparty/libwebp/src/enc/histogram_enc.h +++ b/thirdparty/libwebp/src/enc/histogram_enc.h @@ -109,10 +109,7 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, uint16_t* const histogram_symbols); // Returns the entropy for the symbols in the input array. -// Also sets trivial_symbol to the code value, if the array has only one code -// value. Otherwise, set it to VP8L_NON_TRIVIAL_SYM. -double VP8LBitsEntropy(const uint32_t* const array, int n, - uint32_t* const trivial_symbol); +double VP8LBitsEntropy(const uint32_t* const array, int n); // Estimate how many bits the combined entropy of literals and distance // approximately maps to. diff --git a/thirdparty/libwebp/src/enc/iterator_enc.c b/thirdparty/libwebp/src/enc/iterator_enc.c index cfacfd2401..7c47d51272 100644 --- a/thirdparty/libwebp/src/enc/iterator_enc.c +++ b/thirdparty/libwebp/src/enc/iterator_enc.c @@ -26,6 +26,9 @@ static void InitLeft(VP8EncIterator* const it) { memset(it->u_left_, 129, 8); memset(it->v_left_, 129, 8); it->left_nz_[8] = 0; + if (it->top_derr_ != NULL) { + memset(&it->left_derr_, 0, sizeof(it->left_derr_)); + } } static void InitTop(VP8EncIterator* const it) { @@ -33,6 +36,9 @@ static void InitTop(VP8EncIterator* const it) { const size_t top_size = enc->mb_w_ * 16; memset(enc->y_top_, 127, 2 * top_size); memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_)); + if (enc->top_derr_ != NULL) { + memset(enc->top_derr_, 0, enc->mb_w_ * sizeof(*enc->top_derr_)); + } } void VP8IteratorSetRow(VP8EncIterator* const it, int y) { @@ -76,6 +82,7 @@ void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) { it->y_left_ = (uint8_t*)WEBP_ALIGN(it->yuv_left_mem_ + 1); it->u_left_ = it->y_left_ + 16 + 16; it->v_left_ = it->u_left_ + 16; + it->top_derr_ = enc->top_derr_; VP8IteratorReset(it); } @@ -450,4 +457,3 @@ int VP8IteratorRotateI4(VP8EncIterator* const it, } //------------------------------------------------------------------------------ - diff --git a/thirdparty/libwebp/src/enc/near_lossless_enc.c b/thirdparty/libwebp/src/enc/near_lossless_enc.c index cadd14c664..5517a7e271 100644 --- a/thirdparty/libwebp/src/enc/near_lossless_enc.c +++ b/thirdparty/libwebp/src/enc/near_lossless_enc.c @@ -146,6 +146,6 @@ int VP8ApplyNearLossless(const WebPPicture* const picture, int quality, // Define a stub to suppress compiler warnings. extern void VP8LNearLosslessStub(void); -WEBP_TSAN_IGNORE_FUNCTION void VP8LNearLosslessStub(void) {} +void VP8LNearLosslessStub(void) {} #endif // (WEBP_NEAR_LOSSLESS == 1) diff --git a/thirdparty/libwebp/src/enc/picture_csp_enc.c b/thirdparty/libwebp/src/enc/picture_csp_enc.c index d531dd0282..02d9df76d5 100644 --- a/thirdparty/libwebp/src/enc/picture_csp_enc.c +++ b/thirdparty/libwebp/src/enc/picture_csp_enc.c @@ -28,11 +28,11 @@ // If defined, use table to compute x / alpha. #define USE_INVERSE_ALPHA_TABLE -static const union { - uint32_t argb; - uint8_t bytes[4]; -} test_endian = { 0xff000000u }; -#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff) +#ifdef WORDS_BIGENDIAN +#define ALPHA_OFFSET 0 // uint32_t 0xff000000 is 0xff,00,00,00 in memory +#else +#define ALPHA_OFFSET 3 // uint32_t 0xff000000 is 0x00,00,00,ff in memory +#endif //------------------------------------------------------------------------------ // Detection of non-trivial transparency @@ -61,7 +61,7 @@ int WebPPictureHasTransparency(const WebPPicture* picture) { return CheckNonOpaque(picture->a, picture->width, picture->height, 1, picture->a_stride); } else { - const int alpha_offset = ALPHA_IS_LAST ? 3 : 0; + const int alpha_offset = ALPHA_OFFSET; return CheckNonOpaque((const uint8_t*)picture->argb + alpha_offset, picture->width, picture->height, 4, picture->argb_stride * sizeof(*picture->argb)); @@ -126,7 +126,7 @@ static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { #else -static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {} +static void InitGammaTables(void) {} static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; } static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { return (int)(base_value << shift); @@ -170,29 +170,33 @@ typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W #if defined(USE_GAMMA_COMPRESSION) -// float variant of gamma-correction // We use tables of different size and precision for the Rec709 / BT2020 // transfer function. #define kGammaF (1./0.45) -static float kGammaToLinearTabF[MAX_Y_T + 1]; // size scales with Y_FIX -static float kLinearToGammaTabF[kGammaTabSize + 2]; -static volatile int kGammaTablesFOk = 0; - -static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) { - if (!kGammaTablesFOk) { +static uint32_t kLinearToGammaTabS[kGammaTabSize + 2]; +#define GAMMA_TO_LINEAR_BITS 14 +static uint32_t kGammaToLinearTabS[MAX_Y_T + 1]; // size scales with Y_FIX +static volatile int kGammaTablesSOk = 0; + +static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesS(void) { + assert(2 * GAMMA_TO_LINEAR_BITS < 32); // we use uint32_t intermediate values + if (!kGammaTablesSOk) { int v; const double norm = 1. / MAX_Y_T; const double scale = 1. / kGammaTabSize; const double a = 0.09929682680944; const double thresh = 0.018053968510807; + const double final_scale = 1 << GAMMA_TO_LINEAR_BITS; for (v = 0; v <= MAX_Y_T; ++v) { const double g = norm * v; + double value; if (g <= thresh * 4.5) { - kGammaToLinearTabF[v] = (float)(g / 4.5); + value = g / 4.5; } else { const double a_rec = 1. / (1. + a); - kGammaToLinearTabF[v] = (float)pow(a_rec * (g + a), kGammaF); + value = pow(a_rec * (g + a), kGammaF); } + kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5); } for (v = 0; v <= kGammaTabSize; ++v) { const double g = scale * v; @@ -202,37 +206,44 @@ static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) { } else { value = (1. + a) * pow(g, 1. / kGammaF) - a; } - kLinearToGammaTabF[v] = (float)(MAX_Y_T * value); + // we already incorporate the 1/2 rounding constant here + kLinearToGammaTabS[v] = + (uint32_t)(MAX_Y_T * value) + (1 << GAMMA_TO_LINEAR_BITS >> 1); } // to prevent small rounding errors to cause read-overflow: - kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize]; - kGammaTablesFOk = 1; + kLinearToGammaTabS[kGammaTabSize + 1] = kLinearToGammaTabS[kGammaTabSize]; + kGammaTablesSOk = 1; } } -static WEBP_INLINE float GammaToLinearF(int v) { - return kGammaToLinearTabF[v]; +// return value has a fixed-point precision of GAMMA_TO_LINEAR_BITS +static WEBP_INLINE uint32_t GammaToLinearS(int v) { + return kGammaToLinearTabS[v]; } -static WEBP_INLINE int LinearToGammaF(float value) { - const float v = value * kGammaTabSize; - const int tab_pos = (int)v; - const float x = v - (float)tab_pos; // fractional part - const float v0 = kLinearToGammaTabF[tab_pos + 0]; - const float v1 = kLinearToGammaTabF[tab_pos + 1]; - const float y = v1 * x + v0 * (1.f - x); // interpolate - return (int)(y + .5); +static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) { + // 'value' is in GAMMA_TO_LINEAR_BITS fractional precision + const uint32_t v = value * kGammaTabSize; + const uint32_t tab_pos = v >> GAMMA_TO_LINEAR_BITS; + // fractional part, in GAMMA_TO_LINEAR_BITS fixed-point precision + const uint32_t x = v - (tab_pos << GAMMA_TO_LINEAR_BITS); // fractional part + // v0 / v1 are in GAMMA_TO_LINEAR_BITS fixed-point precision (range [0..1]) + const uint32_t v0 = kLinearToGammaTabS[tab_pos + 0]; + const uint32_t v1 = kLinearToGammaTabS[tab_pos + 1]; + // Final interpolation. Note that rounding is already included. + const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0. + const uint32_t result = v0 + (v2 >> GAMMA_TO_LINEAR_BITS); + return result; } #else -static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {} -static WEBP_INLINE float GammaToLinearF(int v) { - const float norm = 1.f / MAX_Y_T; - return norm * v; +static void InitGammaTablesS(void) {} +static WEBP_INLINE uint32_t GammaToLinearS(int v) { + return (v << GAMMA_TO_LINEAR_BITS) / MAX_Y_T; } -static WEBP_INLINE int LinearToGammaF(float value) { - return (int)(MAX_Y_T * value + .5); +static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) { + return (MAX_Y_T * value) >> GAMMA_TO_LINEAR_BITS; } #endif // USE_GAMMA_COMPRESSION @@ -254,26 +265,22 @@ static int RGBToGray(int r, int g, int b) { return (luma >> YUV_FIX); } -static float RGBToGrayF(float r, float g, float b) { - return (float)(0.2126 * r + 0.7152 * g + 0.0722 * b); -} - -static int ScaleDown(int a, int b, int c, int d) { - const float A = GammaToLinearF(a); - const float B = GammaToLinearF(b); - const float C = GammaToLinearF(c); - const float D = GammaToLinearF(d); - return LinearToGammaF(0.25f * (A + B + C + D)); +static uint32_t ScaleDown(int a, int b, int c, int d) { + const uint32_t A = GammaToLinearS(a); + const uint32_t B = GammaToLinearS(b); + const uint32_t C = GammaToLinearS(c); + const uint32_t D = GammaToLinearS(d); + return LinearToGammaS((A + B + C + D + 2) >> 2); } static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) { int i; for (i = 0; i < w; ++i) { - const float R = GammaToLinearF(src[0 * w + i]); - const float G = GammaToLinearF(src[1 * w + i]); - const float B = GammaToLinearF(src[2 * w + i]); - const float Y = RGBToGrayF(R, G, B); - dst[i] = (fixed_y_t)LinearToGammaF(Y); + const uint32_t R = GammaToLinearS(src[0 * w + i]); + const uint32_t G = GammaToLinearS(src[1 * w + i]); + const uint32_t B = GammaToLinearS(src[2 * w + i]); + const uint32_t Y = RGBToGray(R, G, B); + dst[i] = (fixed_y_t)LinearToGammaS(Y); } } @@ -863,7 +870,7 @@ static int ImportYUVAFromRGBA(const uint8_t* r_ptr, } if (use_iterative_conversion) { - InitGammaTablesF(); + InitGammaTablesS(); if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) { return 0; } @@ -990,10 +997,10 @@ static int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace, return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); } else { const uint8_t* const argb = (const uint8_t*)picture->argb; - const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1; - const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2; - const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3; - const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0; + const uint8_t* const a = argb + (0 ^ ALPHA_OFFSET); + const uint8_t* const r = argb + (1 ^ ALPHA_OFFSET); + const uint8_t* const g = argb + (2 ^ ALPHA_OFFSET); + const uint8_t* const b = argb + (3 ^ ALPHA_OFFSET); picture->colorspace = WEBP_YUV420; return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride, @@ -1044,7 +1051,8 @@ int WebPPictureYUVAToARGB(WebPPicture* picture) { const int argb_stride = 4 * picture->argb_stride; uint8_t* dst = (uint8_t*)picture->argb; const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y; - WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST); + WebPUpsampleLinePairFunc upsample = + WebPGetLinePairConverter(ALPHA_OFFSET > 0); // First row, with replicated top samples. upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width); @@ -1087,6 +1095,7 @@ static int Import(WebPPicture* const picture, const uint8_t* rgb, int rgb_stride, int step, int swap_rb, int import_alpha) { int y; + // swap_rb -> b,g,r,a , !swap_rb -> r,g,b,a const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0); const uint8_t* g_ptr = rgb + 1; const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2); @@ -1104,19 +1113,32 @@ static int Import(WebPPicture* const picture, WebPInitAlphaProcessing(); if (import_alpha) { + // dst[] byte order is {a,r,g,b} for big-endian, {b,g,r,a} for little endian uint32_t* dst = picture->argb; - const int do_copy = - (!swap_rb && !ALPHA_IS_LAST) || (swap_rb && ALPHA_IS_LAST); + const int do_copy = (ALPHA_OFFSET == 3) && swap_rb; assert(step == 4); - for (y = 0; y < height; ++y) { - if (do_copy) { + if (do_copy) { + for (y = 0; y < height; ++y) { memcpy(dst, rgb, width * 4); - } else { + rgb += rgb_stride; + dst += picture->argb_stride; + } + } else { + for (y = 0; y < height; ++y) { +#ifdef WORDS_BIGENDIAN + // BGRA or RGBA input order. + const uint8_t* a_ptr = rgb + 3; + WebPPackARGB(a_ptr, r_ptr, g_ptr, b_ptr, width, dst); + r_ptr += rgb_stride; + g_ptr += rgb_stride; + b_ptr += rgb_stride; +#else // RGBA input order. Need to swap R and B. VP8LConvertBGRAToRGBA((const uint32_t*)rgb, width, (uint8_t*)dst); +#endif + rgb += rgb_stride; + dst += picture->argb_stride; } - rgb += rgb_stride; - dst += picture->argb_stride; } } else { uint32_t* dst = picture->argb; diff --git a/thirdparty/libwebp/src/enc/picture_psnr_enc.c b/thirdparty/libwebp/src/enc/picture_psnr_enc.c index 362a7c79be..1a2f0bef3e 100644 --- a/thirdparty/libwebp/src/enc/picture_psnr_enc.c +++ b/thirdparty/libwebp/src/enc/picture_psnr_enc.c @@ -18,6 +18,7 @@ #include <math.h> #include <stdlib.h> +#include "src/dsp/dsp.h" #include "src/enc/vp8i_enc.h" #include "src/utils/utils.h" @@ -169,6 +170,12 @@ int WebPPlaneDistortion(const uint8_t* src, size_t src_stride, return 1; } +#ifdef WORDS_BIGENDIAN +#define BLUE_OFFSET 3 // uint32_t 0x000000ff is 0x00,00,00,ff in memory +#else +#define BLUE_OFFSET 0 // uint32_t 0x000000ff is 0xff,00,00,00 in memory +#endif + int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, int type, float results[5]) { int w, h, c; @@ -195,8 +202,10 @@ int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, float distortion; const size_t stride0 = 4 * (size_t)p0.argb_stride; const size_t stride1 = 4 * (size_t)p1.argb_stride; - if (!WebPPlaneDistortion((const uint8_t*)p0.argb + c, stride0, - (const uint8_t*)p1.argb + c, stride1, + // results are reported as BGRA + const int offset = c ^ BLUE_OFFSET; + if (!WebPPlaneDistortion((const uint8_t*)p0.argb + offset, stride0, + (const uint8_t*)p1.argb + offset, stride1, w, h, 4, type, &distortion, results + c)) { goto Error; } @@ -214,6 +223,8 @@ int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, return ok; } +#undef BLUE_OFFSET + #else // defined(WEBP_DISABLE_STATS) int WebPPlaneDistortion(const uint8_t* src, size_t src_stride, const uint8_t* ref, size_t ref_stride, diff --git a/thirdparty/libwebp/src/enc/quant_enc.c b/thirdparty/libwebp/src/enc/quant_enc.c index 3b1a3129b5..35bfaf21ef 100644 --- a/thirdparty/libwebp/src/enc/quant_enc.c +++ b/thirdparty/libwebp/src/enc/quant_enc.c @@ -826,6 +826,85 @@ static int ReconstructIntra4(VP8EncIterator* const it, return nz; } +//------------------------------------------------------------------------------ +// DC-error diffusion + +// Diffusion weights. We under-correct a bit (15/16th of the error is actually +// diffused) to avoid 'rainbow' chessboard pattern of blocks at q~=0. +#define C1 7 // fraction of error sent to the 4x4 block below +#define C2 8 // fraction of error sent to the 4x4 block on the right +#define DSHIFT 4 +#define DSCALE 1 // storage descaling, needed to make the error fit int8_t + +// Quantize as usual, but also compute and return the quantization error. +// Error is already divided by DSHIFT. +static int QuantizeSingle(int16_t* const v, const VP8Matrix* const mtx) { + int V = *v; + const int sign = (V < 0); + if (sign) V = -V; + if (V > (int)mtx->zthresh_[0]) { + const int qV = QUANTDIV(V, mtx->iq_[0], mtx->bias_[0]) * mtx->q_[0]; + const int err = (V - qV); + *v = sign ? -qV : qV; + return (sign ? -err : err) >> DSCALE; + } + *v = 0; + return (sign ? -V : V) >> DSCALE; +} + +static void CorrectDCValues(const VP8EncIterator* const it, + const VP8Matrix* const mtx, + int16_t tmp[][16], VP8ModeScore* const rd) { + // | top[0] | top[1] + // --------+--------+--------- + // left[0] | tmp[0] tmp[1] <-> err0 err1 + // left[1] | tmp[2] tmp[3] err2 err3 + // + // Final errors {err1,err2,err3} are preserved and later restored + // as top[]/left[] on the next block. + int ch; + for (ch = 0; ch <= 1; ++ch) { + const int8_t* const top = it->top_derr_[it->x_][ch]; + const int8_t* const left = it->left_derr_[ch]; + int16_t (* const c)[16] = &tmp[ch * 4]; + int err0, err1, err2, err3; + c[0][0] += (C1 * top[0] + C2 * left[0]) >> (DSHIFT - DSCALE); + err0 = QuantizeSingle(&c[0][0], mtx); + c[1][0] += (C1 * top[1] + C2 * err0) >> (DSHIFT - DSCALE); + err1 = QuantizeSingle(&c[1][0], mtx); + c[2][0] += (C1 * err0 + C2 * left[1]) >> (DSHIFT - DSCALE); + err2 = QuantizeSingle(&c[2][0], mtx); + c[3][0] += (C1 * err1 + C2 * err2) >> (DSHIFT - DSCALE); + err3 = QuantizeSingle(&c[3][0], mtx); + // error 'err' is bounded by mtx->q_[0] which is 132 at max. Hence + // err >> DSCALE will fit in an int8_t type if DSCALE>=1. + assert(abs(err1) <= 127 && abs(err2) <= 127 && abs(err3) <= 127); + rd->derr[ch][0] = (int8_t)err1; + rd->derr[ch][1] = (int8_t)err2; + rd->derr[ch][2] = (int8_t)err3; + } +} + +static void StoreDiffusionErrors(VP8EncIterator* const it, + const VP8ModeScore* const rd) { + int ch; + for (ch = 0; ch <= 1; ++ch) { + int8_t* const top = it->top_derr_[it->x_][ch]; + int8_t* const left = it->left_derr_[ch]; + left[0] = rd->derr[ch][0]; // restore err1 + left[1] = 3 * rd->derr[ch][2] >> 2; // ... 3/4th of err3 + top[0] = rd->derr[ch][1]; // ... err2 + top[1] = rd->derr[ch][2] - left[1]; // ... 1/4th of err3. + } +} + +#undef C1 +#undef C2 +#undef DSHIFT +#undef DSCALE + +//------------------------------------------------------------------------------ + static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd, uint8_t* const yuv_out, int mode) { const VP8Encoder* const enc = it->enc_; @@ -839,6 +918,8 @@ static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd, for (n = 0; n < 8; n += 2) { VP8FTransform2(src + VP8ScanUV[n], ref + VP8ScanUV[n], tmp[n]); } + if (it->top_derr_ != NULL) CorrectDCValues(it, &dqm->uv_, tmp, rd); + if (DO_TRELLIS_UV && it->do_trellis_) { int ch, x, y; for (ch = 0, n = 0; ch <= 2; ch += 2) { @@ -1101,6 +1182,9 @@ static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) { CopyScore(&rd_best, &rd_uv); rd->mode_uv = mode; memcpy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels)); + if (it->top_derr_ != NULL) { + memcpy(rd->derr, rd_uv.derr, sizeof(rd_uv.derr)); + } SwapPtr(&dst, &tmp_dst); } } @@ -1109,6 +1193,9 @@ static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) { if (dst != dst0) { // copy 16x8 block if needed VP8Copy16x8(dst, dst0); } + if (it->top_derr_ != NULL) { // store diffusion errors for next block + StoreDiffusionErrors(it, rd); + } } //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/enc/vp8i_enc.h b/thirdparty/libwebp/src/enc/vp8i_enc.h index 3463491e9d..624e8f8e66 100644 --- a/thirdparty/libwebp/src/enc/vp8i_enc.h +++ b/thirdparty/libwebp/src/enc/vp8i_enc.h @@ -30,9 +30,9 @@ extern "C" { // Various defines and enums // version numbers -#define ENC_MAJ_VERSION 0 -#define ENC_MIN_VERSION 6 -#define ENC_REV_VERSION 1 +#define ENC_MAJ_VERSION 1 +#define ENC_MIN_VERSION 0 +#define ENC_REV_VERSION 0 enum { MAX_LF_LEVELS = 64, // Maximum loop filter level MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost @@ -120,6 +120,9 @@ static WEBP_INLINE int QUANTDIV(uint32_t n, uint32_t iQ, uint32_t B) { // Uncomment the following to remove token-buffer code: // #define DISABLE_TOKEN_BUFFER +// quality below which error-diffusion is enabled +#define ERROR_DIFFUSION_QUALITY 98 + //------------------------------------------------------------------------------ // Headers @@ -201,6 +204,8 @@ typedef struct { score_t i4_penalty_; // penalty for using Intra4 } VP8SegmentInfo; +typedef int8_t DError[2 /* u/v */][2 /* top or left */]; + // Handy transient struct to accumulate score and info during RD-optimization // and mode evaluation. typedef struct { @@ -213,6 +218,7 @@ typedef struct { uint8_t modes_i4[16]; // mode numbers for intra4 predictions int mode_uv; // mode number of chroma prediction uint32_t nz; // non-zero blocks + int8_t derr[2][3]; // DC diffusion errors for U/V for blocks #1/2/3 } VP8ModeScore; // Iterator structure to iterate through macroblocks, pointing to the @@ -242,6 +248,9 @@ typedef struct { int count_down0_; // starting counter value (for progress) int percent0_; // saved initial progress percent + DError left_derr_; // left error diffusion (u/v) + DError *top_derr_; // top diffusion error - NULL if disabled + uint8_t* y_left_; // left luma samples (addressable from index -1 to 15). uint8_t* u_left_; // left u samples (addressable from index -1 to 7) uint8_t* v_left_; // left v samples (addressable from index -1 to 7) @@ -401,6 +410,7 @@ struct VP8Encoder { uint8_t* uv_top_; // top u/v samples. // U and V are packed into 16 bytes (8 U + 8 V) LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off) + DError* top_derr_; // diffusion error (NULL if disabled) }; //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/enc/vp8l_enc.c b/thirdparty/libwebp/src/enc/vp8l_enc.c index 312e521906..a89184eb08 100644 --- a/thirdparty/libwebp/src/enc/vp8l_enc.c +++ b/thirdparty/libwebp/src/enc/vp8l_enc.c @@ -26,8 +26,6 @@ #include "src/utils/utils.h" #include "src/webp/format_constants.h" -#include "src/enc/delta_palettization_enc.h" - // Maximum number of histogram images (sub-blocks). #define MAX_HUFF_IMAGE_SIZE 2600 @@ -259,7 +257,7 @@ static int AnalyzeEntropy(const uint32_t* argb, ++histo[kHistoAlphaPred * 256]; for (j = 0; j < kHistoTotal; ++j) { - entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256, NULL); + entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256); } entropy[kDirect] = entropy_comp[kHistoAlpha] + entropy_comp[kHistoRed] + @@ -384,8 +382,7 @@ static int EncoderAnalyze(VP8LEncoder* const enc, AnalyzeAndCreatePalette(pic, low_effort, enc->palette_, &enc->palette_size_); - // TODO(jyrki): replace the decision to be based on an actual estimate - // of entropy, or even spatial variance of entropy. + // Empirical bit sizes. enc->histo_bits_ = GetHistoBits(method, use_palette, pic->width, pic->height); enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_); @@ -756,7 +753,6 @@ static WebPEncodingError StoreImageToBitMask( // Don't write the distance with the extra bits code since // the distance can be up to 18 bits of extra bits, and the prefix // 15 bits, totaling to 33, and our PutBits only supports up to 32 bits. - // TODO(jyrki): optimize this further. VP8LPrefixEncode(distance, &code, &n_bits, &bits); WriteHuffmanCode(bw, codes + 4, code); VP8LPutBits(bw, bits, n_bits); @@ -1464,49 +1460,6 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort, 20 /* quality */, low_effort); } -#ifdef WEBP_EXPERIMENTAL_FEATURES - -static WebPEncodingError EncodeDeltaPalettePredictorImage( - VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality, - int low_effort) { - const WebPPicture* const pic = enc->pic_; - const int width = pic->width; - const int height = pic->height; - - const int pred_bits = 5; - const int transform_width = VP8LSubSampleSize(width, pred_bits); - const int transform_height = VP8LSubSampleSize(height, pred_bits); - const int pred = 7; // default is Predictor7 (Top/Left Average) - const int tiles_per_row = VP8LSubSampleSize(width, pred_bits); - const int tiles_per_col = VP8LSubSampleSize(height, pred_bits); - uint32_t* predictors; - int tile_x, tile_y; - WebPEncodingError err = VP8_ENC_OK; - - predictors = (uint32_t*)WebPSafeMalloc(tiles_per_col * tiles_per_row, - sizeof(*predictors)); - if (predictors == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; - - for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) { - for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) { - predictors[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8); - } - } - - VP8LPutBits(bw, TRANSFORM_PRESENT, 1); - VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); - VP8LPutBits(bw, pred_bits - 2, 3); - err = EncodeImageNoHuffman( - bw, predictors, &enc->hash_chain_, - (VP8LBackwardRefs*)&enc->refs_[0], // cast const away - (VP8LBackwardRefs*)&enc->refs_[1], - transform_width, transform_height, quality, low_effort); - WebPSafeFree(predictors); - return err; -} - -#endif // WEBP_EXPERIMENTAL_FEATURES - // ----------------------------------------------------------------------------- // VP8LEncoder @@ -1568,7 +1521,7 @@ static int EncodeStreamHook(void* input, void* data2) { WebPEncodingError err = VP8_ENC_OK; const int quality = (int)config->quality; const int low_effort = (config->method == 0); -#if (WEBP_NEAR_LOSSLESS == 1) || defined(WEBP_EXPERIMENTAL_FEATURES) +#if (WEBP_NEAR_LOSSLESS == 1) const int width = picture->width; #endif const int height = picture->height; @@ -1627,29 +1580,6 @@ static int EncodeStreamHook(void* input, void* data2) { enc->argb_content_ = kEncoderNone; #endif -#ifdef WEBP_EXPERIMENTAL_FEATURES - if (config->use_delta_palette) { - enc->use_predict_ = 1; - enc->use_cross_color_ = 0; - enc->use_subtract_green_ = 0; - enc->use_palette_ = 1; - if (enc->argb_content_ != kEncoderNearLossless && - enc->argb_content_ != kEncoderPalette) { - err = MakeInputImageCopy(enc); - if (err != VP8_ENC_OK) goto Error; - } - err = WebPSearchOptimalDeltaPalette(enc); - if (err != VP8_ENC_OK) goto Error; - if (enc->use_palette_) { - err = AllocateTransformBuffer(enc, width, height); - if (err != VP8_ENC_OK) goto Error; - err = EncodeDeltaPalettePredictorImage(bw, enc, quality, low_effort); - if (err != VP8_ENC_OK) goto Error; - use_delta_palette = 1; - } - } -#endif // WEBP_EXPERIMENTAL_FEATURES - // Encode palette if (enc->use_palette_) { err = EncodePalette(bw, low_effort, enc); @@ -1822,7 +1752,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, worker_interface->Init(worker); worker->data1 = param; worker->data2 = NULL; - worker->hook = (WebPWorkerHook)EncodeStreamHook; + worker->hook = EncodeStreamHook; } } @@ -1944,7 +1874,6 @@ int VP8LEncodeImage(const WebPConfig* const config, err = VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/); if (err != VP8_ENC_OK) goto Error; - // TODO(skal): have a fine-grained progress report in VP8LEncodeStream(). if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort; // Finish the RIFF chunk. diff --git a/thirdparty/libwebp/src/enc/webp_enc.c b/thirdparty/libwebp/src/enc/webp_enc.c index 283cda8e7b..9f4b10c26c 100644 --- a/thirdparty/libwebp/src/enc/webp_enc.c +++ b/thirdparty/libwebp/src/enc/webp_enc.c @@ -159,12 +159,16 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config, + WEBP_ALIGN_CST; // align all const size_t lf_stats_size = config->autofilter ? sizeof(*enc->lf_stats_) + WEBP_ALIGN_CST : 0; + const size_t top_derr_size = + (config->quality <= ERROR_DIFFUSION_QUALITY || config->pass > 1) ? + mb_w * sizeof(*enc->top_derr_) : 0; uint8_t* mem; const uint64_t size = (uint64_t)sizeof(*enc) // main struct + WEBP_ALIGN_CST // cache alignment + info_size // modes info + preds_size // prediction modes + samples_size // top/left samples + + top_derr_size // top diffusion error + nz_size // coeff context bits + lf_stats_size; // autofilter stats @@ -175,11 +179,12 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config, " info: %ld\n" " preds: %ld\n" " top samples: %ld\n" + " top diffusion: %ld\n" " non-zero: %ld\n" " lf-stats: %ld\n" " total: %ld\n", sizeof(*enc) + WEBP_ALIGN_CST, info_size, - preds_size, samples_size, nz_size, lf_stats_size, size); + preds_size, samples_size, top_derr_size, nz_size, lf_stats_size, size); printf("Transient object sizes:\n" " VP8EncIterator: %ld\n" " VP8ModeScore: %ld\n" @@ -219,6 +224,8 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config, enc->y_top_ = mem; enc->uv_top_ = enc->y_top_ + top_stride; mem += 2 * top_stride; + enc->top_derr_ = top_derr_size ? (DError*)mem : NULL; + mem += top_derr_size; assert(mem <= (uint8_t*)enc + size); enc->config_ = config; diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h index b73e3fbd7a..6b57eea30f 100644 --- a/thirdparty/libwebp/src/mux/muxi.h +++ b/thirdparty/libwebp/src/mux/muxi.h @@ -26,9 +26,9 @@ extern "C" { //------------------------------------------------------------------------------ // Defines and constants. -#define MUX_MAJ_VERSION 0 -#define MUX_MIN_VERSION 4 -#define MUX_REV_VERSION 1 +#define MUX_MAJ_VERSION 1 +#define MUX_MIN_VERSION 0 +#define MUX_REV_VERSION 0 // Chunk object. typedef struct WebPChunk WebPChunk; diff --git a/thirdparty/libwebp/src/utils/endian_inl_utils.h b/thirdparty/libwebp/src/utils/endian_inl_utils.h index 4b2f91dfb8..3630a293bf 100644 --- a/thirdparty/libwebp/src/utils/endian_inl_utils.h +++ b/thirdparty/libwebp/src/utils/endian_inl_utils.h @@ -19,13 +19,6 @@ #include "src/dsp/dsp.h" #include "src/webp/types.h" -// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__) -#if !defined(WORDS_BIGENDIAN) && \ - (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \ - (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) -#define WORDS_BIGENDIAN -#endif - #if defined(WORDS_BIGENDIAN) #define HToLE32 BSwap32 #define HToLE16 BSwap16 diff --git a/thirdparty/minizip/crypt.h b/thirdparty/minizip/crypt.h index a01d08d932..1e9e8200b2 100644 --- a/thirdparty/minizip/crypt.h +++ b/thirdparty/minizip/crypt.h @@ -32,7 +32,7 @@ /*********************************************************************** * Return the next byte in the pseudo-random sequence */ -static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem @@ -45,7 +45,7 @@ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) /*********************************************************************** * Update the encryption keys with the next byte of plain text */ -static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; @@ -62,7 +62,7 @@ static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int * Initialize the encryption keys and the random header according to * the given password. */ -static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; @@ -91,7 +91,7 @@ static int crypthead(const char* passwd, /* password string */ unsigned char* buf, /* where to write header */ int bufSize, unsigned long* pkeys, - const unsigned long* pcrc_32_tab, + const z_crc_t* pcrc_32_tab, unsigned long crcForCrypting) { int n; /* index in random header */ diff --git a/thirdparty/minizip/godot-zlib-1.2.4-minizip-seek.patch b/thirdparty/minizip/godot-zlib-1.2.4-minizip-seek.patch index 8e66416a43..2162bafbbc 100644 --- a/thirdparty/minizip/godot-zlib-1.2.4-minizip-seek.patch +++ b/thirdparty/minizip/godot-zlib-1.2.4-minizip-seek.patch @@ -96,8 +96,8 @@ index 7617f41f1..32e27bd65 100644 +/* GODOT end */ + /* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), @@ -1018,10 +1034,20 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file, if (lSeek!=0) @@ -237,7 +237,7 @@ index 3183968b7..54e65ad8a 100644 --- a/thirdparty/minizip/unzip.h +++ b/thirdparty/minizip/unzip.h @@ -202,6 +202,10 @@ extern int ZEXPORT unzClose OF((unzFile file)); - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ +/* GODOT start */ diff --git a/thirdparty/minizip/ioapi.c b/thirdparty/minizip/ioapi.c index 2b42df4abd..9cb27c16db 100644 --- a/thirdparty/minizip/ioapi.c +++ b/thirdparty/minizip/ioapi.c @@ -10,10 +10,22 @@ */ -#if (defined(_WIN32)) +#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) #define _CRT_SECURE_NO_WARNINGS #endif +#if defined(__APPLE__) || defined(IOAPI_NO_64) +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + #include "ioapi.h" voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) @@ -47,7 +59,7 @@ ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream else { uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); - if ((tell_uLong) == ((uLong)-1)) + if ((tell_uLong) == MAXU32) return (ZPOS64_T)-1; else return tell_uLong; @@ -119,7 +131,7 @@ static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) - file = fopen64((const char*)filename, mode_fopen); + file = FOPEN_FUNC((const char*)filename, mode_fopen); return file; } @@ -149,7 +161,7 @@ static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) { ZPOS64_T ret; - ret = ftello64((FILE *)stream); + ret = FTELLO_FUNC((FILE *)stream); return ret; } @@ -195,7 +207,7 @@ static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T } ret = 0; - if(fseeko64((FILE *)stream, offset, fseek_origin) != 0) + if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) ret = -1; return ret; diff --git a/thirdparty/minizip/ioapi.h b/thirdparty/minizip/ioapi.h index 6043d34cea..4011e9cabb 100644 --- a/thirdparty/minizip/ioapi.h +++ b/thirdparty/minizip/ioapi.h @@ -21,7 +21,7 @@ #ifndef _ZLIBIOAPI64_H #define _ZLIBIOAPI64_H -#if (!defined(_WIN32)) && (!defined(WIN32)) +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) // Linux needs this to support file operation on files larger then 4+GB // But might need better if/def to select just the platforms that needs them. @@ -38,6 +38,7 @@ #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif + #endif #include <stdio.h> @@ -65,6 +66,11 @@ #define ftello64 ftell #define fseeko64 fseek #else +#ifdef __FreeBSD__ +#define fopen64 fopen +#define ftello64 ftello +#define fseeko64 fseeko +#endif #ifdef _MSC_VER #define fopen64 fopen #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) @@ -101,6 +107,8 @@ typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; typedef uint64_t ZPOS64_T; #else +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#define MAXU32 0xffffffff #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ZPOS64_T; diff --git a/thirdparty/minizip/unzip.c b/thirdparty/minizip/unzip.c index 32e27bd657..31f8a5ff47 100644 --- a/thirdparty/minizip/unzip.c +++ b/thirdparty/minizip/unzip.c @@ -191,7 +191,7 @@ typedef struct # ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; + const z_crc_t* pcrc_32_tab; # endif } unz64_s; @@ -203,7 +203,7 @@ typedef struct /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. - IN assertion: the stream s has been sucessfully opened for reading. + IN assertion: the stream s has been successfully opened for reading. */ @@ -817,9 +817,9 @@ extern void* unzGetOpaque(unzFile file) { /* GODOT end */ /* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzClose (unzFile file) { @@ -1066,26 +1066,26 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file, { uLong uL; - if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) + if(file_info.uncompressed_size == MAXU32) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; } - if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) + if(file_info.compressed_size == MAXU32) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; } - if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) + if(file_info_internal.offset_curfile == MAXU32) { /* Relative Header offset */ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; } - if(file_info.disk_num_start == (unsigned long)-1) + if(file_info.disk_num_start == MAXU32) { /* Disk Start Number */ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) @@ -1171,7 +1171,7 @@ extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); - if (err==UNZ_OK) + if ((err==UNZ_OK) && (pfile_info != NULL)) { pfile_info->version = file_info64.version; pfile_info->version_needed = file_info64.version_needed; @@ -1249,7 +1249,7 @@ extern int ZEXPORT unzGoToNextFile (unzFile file) /* Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzipStringFileNameCompare + For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. @@ -1806,7 +1806,7 @@ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) return UNZ_PARAMERROR; - if ((pfile_in_zip_read_info->read_buffer == NULL)) + if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; @@ -2108,7 +2108,7 @@ extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) } /* - Close the file in zip opened with unzipOpenCurrentFile + Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile (unzFile file) diff --git a/thirdparty/minizip/unzip.h b/thirdparty/minizip/unzip.h index 54e65ad8ab..bab1cb939f 100644 --- a/thirdparty/minizip/unzip.h +++ b/thirdparty/minizip/unzip.h @@ -197,9 +197,9 @@ extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, extern int ZEXPORT unzClose OF((unzFile file)); /* - Close a ZipFile opened with unzipOpen. + Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ /* GODOT start */ diff --git a/thirdparty/minizip/zip.c b/thirdparty/minizip/zip.c index d7093e7457..2936e2b5d9 100644 --- a/thirdparty/minizip/zip.c +++ b/thirdparty/minizip/zip.c @@ -15,7 +15,7 @@ Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data It is used when recreting zip archive with RAW when deleting items from a zip. - ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. + ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed. Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer @@ -116,7 +116,7 @@ typedef struct linkedlist_datablock_internal_s struct linkedlist_datablock_internal_s* next_datablock; uLong avail_in_this_block; uLong filled_in_this_block; - uLong unused; /* for future use and alignement */ + uLong unused; /* for future use and alignment */ unsigned char data[SIZEDATA_INDATABLOCK]; } linkedlist_datablock_internal; @@ -157,7 +157,7 @@ typedef struct ZPOS64_T totalUncompressedData; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; + const z_crc_t* pcrc_32_tab; int crypt_header_size; #endif } curfile64_info; @@ -171,7 +171,7 @@ typedef struct curfile64_info ci; /* info on the file curretly writing */ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ - ZPOS64_T add_position_when_writting_offset; + ZPOS64_T add_position_when_writing_offset; ZPOS64_T number_entry; #ifndef NO_ADDFILEINEXISTINGZIP @@ -807,7 +807,7 @@ int LoadCentralDirectoryRecord(zip64_internal* pziinit) } byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); - pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + pziinit->add_position_when_writing_offset = byte_before_the_zipfile; { ZPOS64_T size_central_dir_to_read = size_central_dir; @@ -877,7 +877,7 @@ extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* gl ziinit.in_opened_file_inzip = 0; ziinit.ci.stream_initialised = 0; ziinit.number_entry = 0; - ziinit.add_position_when_writting_offset = 0; + ziinit.add_position_when_writing_offset = 0; init_linkedlist(&(ziinit.central_dir)); @@ -1069,6 +1069,7 @@ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, int err = ZIP_OK; # ifdef NOCRYPT + (crcForCrypting); if (password != NULL) return ZIP_PARAMERROR; # endif @@ -1116,9 +1117,9 @@ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, zi->ci.flag = flagBase; if ((level==8) || (level==9)) zi->ci.flag |= 2; - if ((level==2)) + if (level==2) zi->ci.flag |= 4; - if ((level==1)) + if (level==1) zi->ci.flag |= 6; if (password != NULL) zi->ci.flag |= 1; @@ -1165,7 +1166,7 @@ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, if(zi->ci.pos_local_header >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); else - zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writing_offset,4); for (i=0;i<size_filename;i++) *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i); @@ -1714,7 +1715,7 @@ extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_s if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ - if(uncompressed_size >= 0xffffffff) + if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff ) { if(zi->ci.pos_zip64extrainfo > 0) { @@ -1728,6 +1729,8 @@ extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_s if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); } + else + err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal } else { @@ -1756,7 +1759,7 @@ extern int ZEXPORT zipCloseFileInZip (zipFile file) int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) { int err = ZIP_OK; - ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); @@ -1809,7 +1812,7 @@ int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centra if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { - ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); } return err; @@ -1850,13 +1853,13 @@ int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { - ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; if(pos >= 0xffffffff) { err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); } else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4); } return err; @@ -1922,8 +1925,8 @@ extern int ZEXPORT zipClose (zipFile file, const char* global_comment) } free_linkedlist(&(zi->central_dir)); - pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; - if(pos >= 0xffffffff) + pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; + if(pos >= 0xffffffff || zi->number_entry > 0xFFFF) { ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); |