diff options
117 files changed, 1596 insertions, 557 deletions
diff --git a/.travis.yml b/.travis.yml index acab89e516..2c4eda9105 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,9 +30,9 @@ matrix: - env: GODOT_TARGET=android TOOLS=no CACHE_NAME=${GODOT_TARGET}-gcc os: linux compiler: gcc - - env: GODOT_TARGET=osx TOOLS=yes CACHE_NAME=${GODOT_TARGET}-clang-tools - os: osx - compiler: clang + #- env: GODOT_TARGET=osx TOOLS=yes CACHE_NAME=${GODOT_TARGET}-clang-tools + # os: osx + # compiler: clang #- env: GODOT_TARGET=iphone TOOLS=no CACHE_NAME=${GODOT_TARGET}-clang # os: osx # compiler: clang diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 999befaf67..f6011c3976 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -2694,12 +2694,12 @@ Variant JSONParseResult::get_result() const { } void _JSON::_bind_methods() { - ClassDB::bind_method(D_METHOD("print", "value"), &_JSON::print); + ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys"), &_JSON::print, DEFVAL(String()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("parse", "json"), &_JSON::parse); } -String _JSON::print(const Variant &p_value) { - return JSON::print(p_value); +String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys) { + return JSON::print(p_value, p_indent, p_sort_keys); } Ref<JSONParseResult> _JSON::parse(const String &p_json) { diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 8163b08d76..b642a907fb 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -719,7 +719,7 @@ protected: public: static _JSON *get_singleton() { return singleton; } - String print(const Variant &p_value); + String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false); Ref<JSONParseResult> parse(const String &p_json); _JSON(); diff --git a/core/dictionary.cpp b/core/dictionary.cpp index 48e65c734f..44fce2474f 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -204,7 +204,9 @@ const Variant *Dictionary::next(const Variant *p_key) const { if (p_key == NULL) { // caller wants to get the first element - return &_p->variant_map.front().key(); + if (_p->variant_map.front()) + return &_p->variant_map.front().key(); + return NULL; } OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.find(*p_key); diff --git a/core/error_list.h b/core/error_list.h index 50d248b3d0..9a36b27aab 100644 --- a/core/error_list.h +++ b/core/error_list.h @@ -87,8 +87,6 @@ enum Error { ERR_HELP, ///< user requested help!! ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior. ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames - ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though - ERR_WTF = ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above }; #endif diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 48101c8cf1..fb432b85db 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -491,7 +491,6 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(ERR_BUSY); BIND_GLOBAL_ENUM_CONSTANT(ERR_HELP); ///< user requested help!! BIND_GLOBAL_ENUM_CONSTANT(ERR_BUG); ///< a bug in the software certainly happened ), due to a double check failing or unexpected behavior. - BIND_GLOBAL_ENUM_CONSTANT(ERR_WTF); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_NONE); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_RANGE); diff --git a/core/io/json.cpp b/core/io/json.cpp index 2e9170bc34..ddfc792cc7 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -43,7 +43,25 @@ const char *JSON::tk_name[TK_MAX] = { "EOF", }; -String JSON::_print_var(const Variant &p_var) { +static String _make_indent(const String& p_indent, int p_size) { + + String indent_text = ""; + if (!p_indent.empty()) { + for (int i = 0; i < p_size; i++) + indent_text += p_indent; + } + return indent_text; +} + +String JSON::_print_var(const Variant &p_var, const String& p_indent, int p_cur_indent, bool p_sort_keys) { + + String colon = ":"; + String end_statement = ""; + + if (!p_indent.empty()) { + colon += " "; + end_statement += "\n"; + } switch (p_var.get_type()) { @@ -57,41 +75,50 @@ String JSON::_print_var(const Variant &p_var) { case Variant::ARRAY: { String s = "["; + s += end_statement; Array a = p_var; for (int i = 0; i < a.size(); i++) { - if (i > 0) - s += ", "; - s += _print_var(a[i]); + if (i > 0) { + s += ","; + s += end_statement; + } + s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys); } - s += "]"; + s += end_statement + _make_indent(p_indent, p_cur_indent) + "]"; return s; }; case Variant::DICTIONARY: { String s = "{"; + s += end_statement; Dictionary d = p_var; List<Variant> keys; d.get_key_list(&keys); + if (p_sort_keys) + keys.sort(); + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - if (E != keys.front()) - s += ", "; - s += _print_var(String(E->get())); - s += ":"; - s += _print_var(d[E->get()]); + if (E != keys.front()) { + s += ","; + s += end_statement; + } + s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys); + s += colon; + s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys); } - s += "}"; + s += end_statement + _make_indent(p_indent, p_cur_indent) + "}"; return s; }; default: return "\"" + String(p_var).json_escape() + "\""; } } -String JSON::print(const Variant &p_var) { +String JSON::print(const Variant &p_var, const String& p_indent, bool p_sort_keys) { - return _print_var(p_var); + return _print_var(p_var, p_indent, 0, p_sort_keys); } Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) { diff --git a/core/io/json.h b/core/io/json.h index 893a88e264..5e1a89f069 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -64,7 +64,7 @@ class JSON { static const char *tk_name[TK_MAX]; - static String _print_var(const Variant &p_var); + static String _print_var(const Variant &p_var, const String& p_indent, int p_cur_indent, bool p_sort_keys); static Error _get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str); static Error _parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str); @@ -72,7 +72,7 @@ class JSON { static Error _parse_object(Dictionary &object, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str); public: - static String print(const Variant &p_var); + static String print(const Variant &p_var, const String& p_indent = "", bool p_sort_keys = true); static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); }; diff --git a/core/object.h b/core/object.h index 3ac699f978..0a0c781649 100644 --- a/core/object.h +++ b/core/object.h @@ -1,4 +1,4 @@ -/*************************************************************************/ +/*************************************************************************/ /* object.h */ /*************************************************************************/ /* This file is part of: */ @@ -109,10 +109,11 @@ enum PropertyUsageFlags { PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 17, PROPERTY_USAGE_CLASS_IS_ENUM = 1 << 18, PROPERTY_USAGE_NIL_IS_VARIANT = 1 << 19, + PROPERTY_USAGE_INTERNAL = 1 << 20, PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK, PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED, - PROPERTY_USAGE_NOEDITOR = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK, + PROPERTY_USAGE_NOEDITOR = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNAL, }; #define ADD_SIGNAL(m_signal) ClassDB::add_signal(get_class_static(), m_signal) diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index 6d4b46f4da..e19c8e8ea5 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -333,6 +333,9 @@ Error DirAccess::copy(String p_from, String p_to, int chmod_flags) { if (err == OK && chmod_flags != -1) { fdst->close(); err = fdst->_chmod(p_to, chmod_flags); + // If running on a platform with no chmod support (i.e., Windows), don't fail + if (err == ERR_UNAVAILABLE) + err = OK; } memdelete(fsrc); diff --git a/core/os/file_access.h b/core/os/file_access.h index 455dd1ea99..6fda3d9668 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -141,7 +141,7 @@ public: virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType - virtual Error _chmod(const String &p_path, int p_mod) { return FAILED; } + virtual Error _chmod(const String &p_path, int p_mod) { return ERR_UNAVAILABLE; } static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files. static FileAccess *create_for_path(const String &p_path); diff --git a/core/resource.cpp b/core/resource.cpp index 78e20bada4..d339eb78ad 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -184,6 +184,35 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Res return Ref<Resource>(r); } +void Resource::configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource> > &remap_cache) { + + print_line("configure for local: " + get_class()); + List<PropertyInfo> plist; + get_property_list(&plist); + + local_scene = p_for_scene; + + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) + continue; + Variant p = get(E->get().name); + if (p.get_type() == Variant::OBJECT) { + + RES sr = p; + if (sr.is_valid()) { + + if (sr->is_local_to_scene()) { + if (!remap_cache.has(sr)) { + sr->configure_for_local_scene(p_for_scene, remap_cache); + remap_cache[sr] = sr; + } + } + } + } + } +} + Ref<Resource> Resource::duplicate(bool p_subresources) const { List<PropertyInfo> plist; diff --git a/core/resource.h b/core/resource.h index 7dc3b67291..19714a68d1 100644 --- a/core/resource.h +++ b/core/resource.h @@ -108,6 +108,7 @@ public: virtual Ref<Resource> duplicate(bool p_subresources = false) const; Ref<Resource> duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource> > &remap_cache); + void configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource> > &remap_cache); void set_local_to_scene(bool p_enable); bool is_local_to_scene() const; diff --git a/core/ustring.cpp b/core/ustring.cpp index a86fb46c8a..3a0708851e 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -3380,8 +3380,6 @@ bool String::is_valid_float() const { from++; } - //this was pulled out of my ass, i wonder if it's correct... - bool exponent_found = false; bool period_found = false; bool sign_found = false; diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 5655578459..deddaffdc6 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1190,9 +1190,6 @@ <constant name="ERR_BUG" value="47" enum="Error"> Bug error </constant> - <constant name="ERR_WTF" value="49" enum="Error"> - WTF error (something probably went really wrong) - </constant> <constant name="PROPERTY_HINT_NONE" value="0" enum="PropertyHint"> No hint for edited property. </constant> diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index ac547d20b7..c3933443a0 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -157,6 +157,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns [code]true[/code] if the track at [code]idx[/code] wraps the interpolation loop. Default value: [code]true[/code]. </description> </method> <method name="track_get_interpolation_type" qualifiers="const"> @@ -311,6 +312,7 @@ <argument index="1" name="interpolation" type="bool"> </argument> <description> + If [code]true[/code] the track at [code]idx[/code] wraps the interpolation loop. </description> </method> <method name="track_set_interpolation_type"> diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index e724f24498..09ace05bfb 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -19,7 +19,7 @@ <argument index="1" name="animation" type="Animation"> </argument> <description> - Add an animation resource to the player, which will be later referenced by the "name" argument. + Adds [code]animation[/code] to the player accessible with the key [code]name[/code]. </description> </method> <method name="advance"> @@ -28,7 +28,7 @@ <argument index="0" name="delta" type="float"> </argument> <description> - Used to skip ahead or skip back in an animation. Delta is the time in seconds to skip. + Shifts position in the animation timeline. Delta is the time in seconds to shift. </description> </method> <method name="animation_get_next" qualifiers="const"> @@ -37,7 +37,7 @@ <argument index="0" name="anim_from" type="String"> </argument> <description> - Return the name of the next animation in the queue. + Returns the name of the next animation in the queue. </description> </method> <method name="animation_set_next"> @@ -48,21 +48,21 @@ <argument index="1" name="anim_to" type="String"> </argument> <description> - Set the name of an animation that will be played after. + Triggers the [code]anim_to[/code] animation when the [code]anim_from[/code] animation completes. </description> </method> <method name="clear_caches"> <return type="void"> </return> <description> - The animation player creates caches for faster access to the nodes it will animate. However, if a specific node is removed, it may not notice it, so clear_caches will force the player to search for the nodes again. + [code]AnimationPlayer[/code] caches animated nodes. It may not notice if a node disappears, so clear_caches forces it to update the cache again. </description> </method> <method name="clear_queue"> <return type="void"> </return> <description> - If animations are queued to play, clear them. + Clears all queued, unplayed animations. </description> </method> <method name="find_animation" qualifiers="const"> @@ -71,7 +71,7 @@ <argument index="0" name="animation" type="Animation"> </argument> <description> - Find an animation name by resource. + Returns the name of [code]animation[/code] or empty string if not found. </description> </method> <method name="get_animation" qualifiers="const"> @@ -80,21 +80,21 @@ <argument index="0" name="name" type="String"> </argument> <description> - Get an [Animation] resource by requesting a name. + Returns the [Animation] with key [code]name[/code] or [code]null[/code] if not found. </description> </method> <method name="get_animation_list" qualifiers="const"> <return type="PoolStringArray"> </return> <description> - Get the list of names of the animations stored in the player. + Returns the list of stored animation names. </description> </method> <method name="get_autoplay" qualifiers="const"> <return type="String"> </return> <description> - Return the name of the animation that will be automatically played when the scene is loaded. + Returns the name of the animation played when the scene loads. </description> </method> <method name="get_blend_time" qualifiers="const"> @@ -105,35 +105,28 @@ <argument index="1" name="anim_to" type="String"> </argument> <description> - Get the blend time between two animations, referenced by their names. + Get the blend time (in seconds) between two animations, referenced by their names. </description> </method> <method name="get_current_animation" qualifiers="const"> <return type="String"> </return> <description> - Return the name of the animation being played. + Returns the name of the currently playing animation. </description> </method> - <method name="get_current_animation_length" qualifiers="const"> + <method name="get_anim_length" qualifiers="const"> <return type="float"> </return> <description> - Get the length (in seconds) of the currently being played animation. + Get the length (in seconds) of the currently playing animation. </description> </method> - <method name="get_current_animation_position" qualifiers="const"> + <method name="get_anim_position" qualifiers="const"> <return type="float"> </return> <description> - Get the position (in seconds) of the currently being played animation. - </description> - </method> - <method name="get_position" qualifiers="const"> - <return type="float"> - </return> - <description> - Return the playback position (in seconds) in an animation channel (or channel 0 if none is provided). + Get the position (in seconds) of the currently playing animation. </description> </method> <method name="get_speed_scale" qualifiers="const"> @@ -149,21 +142,21 @@ <argument index="0" name="name" type="String"> </argument> <description> - Request whether an [Animation] name exist within the player. + Returns [code]true[/code] if the [code]AnimationPlayer[/code] stores an [Animation] with key [code]name[/code]. </description> </method> <method name="is_active" qualifiers="const"> <return type="bool"> </return> <description> - Return true if the player is active. + Returns true if the player is active. </description> </method> <method name="is_playing" qualifiers="const"> <return type="bool"> </return> <description> - Return whether an animation is playing. + Returns [code]true[/code] if playing an animation. </description> </method> <method name="play"> @@ -178,7 +171,7 @@ <argument index="3" name="from_end" type="bool" default="false"> </argument> <description> - Play a given animation by the animation name. Custom speed and blend times can be set. If custom speed is negative (-1), 'from_end' being true can play the animation backwards. + Play the animation with key [code]name[/code]. Custom speed and blend times can be set. If custom speed is negative (-1), 'from_end' being true can play the animation backwards. </description> </method> <method name="play_backwards"> @@ -189,7 +182,7 @@ <argument index="1" name="custom_blend" type="float" default="-1"> </argument> <description> - Play a given animation by the animation name in reverse. + Play the animation with key [code]name[/code] in reverse. </description> </method> <method name="queue"> @@ -207,7 +200,7 @@ <argument index="0" name="name" type="String"> </argument> <description> - Remove an animation from the player (by supplying the same name used to add it). + Remove the animation with key [code]name[/code]. </description> </method> <method name="rename_animation"> @@ -218,7 +211,7 @@ <argument index="1" name="newname" type="String"> </argument> <description> - Rename an existing animation. + Rename an existing animation with key [code]name[/code] to [code]newname[/code]. </description> </method> <method name="seek"> @@ -229,7 +222,7 @@ <argument index="1" name="update" type="bool" default="false"> </argument> <description> - Seek the animation to a given position in time (in seconds). If 'update' is true, the animation will be updated too, otherwise it will be updated at process time. + Seek the animation to the [code]seconds[/code] point in time (in seconds). If 'update' is true, the animation updates too, otherwise it updates at process time. </description> </method> <method name="set_active"> @@ -287,7 +280,7 @@ <argument index="0" name="reset" type="bool" default="true"> </argument> <description> - Stop the currently playing animation. + Stop the currently playing animation. If [code]reset[/code] is [code]true[/code], the anim position is reset to [code]0[/code]. </description> </method> <method name="stop_all"> @@ -300,10 +293,25 @@ </methods> <members> <member name="playback_default_blend_time" type="float" setter="set_default_blend_time" getter="get_default_blend_time"> + The default time in which to blend animations. Ranges from 0 to 4096 with 0.01 precision. Default value: [code]0[/code]. </member> <member name="playback_process_mode" type="int" setter="set_animation_process_mode" getter="get_animation_process_mode" enum="AnimationPlayer.AnimationProcessMode"> + The process notification in which to update animations. Default value: [enum ANIMATION_PROCESS_IDLE]. </member> <member name="root_node" type="NodePath" setter="set_root" getter="get_root"> + The node from which node path references will travel. Default value: [code]".."[/code]. + </member> + <member name="autoplay" type="String" setter="set_autoplay" getter="get_autoplay"> + The name of the animation to play when the scene loads. Default value: [code]""[/code]. + </member> + <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale"> + The speed scaling ratio in a given animation channel (or channel 0 if none is provided). Default value: [code]1[/code]. + </member> + <member name="active" type="bool" setter="set_active" getter="is_active"> + If [code]true[/code] updates animations in response to process-related notifications. Default value: [code]true[/code]. + </member> + <member name="current_anim" type="String" setter="set_current_anim" getter="get_current_anim"> + The name of the current animation. If already playing, restarts the animation. Ensure [member active] is [code]true[/code] to simulate [method play]. Default value: [code]""[/code]. </member> </members> <signals> @@ -313,21 +321,21 @@ <argument index="1" name="new_name" type="String"> </argument> <description> - If the currently being played animation changes, this signal will notify of such change. + Emitted when the [Animation] with key [member current_anim] is modified. </description> </signal> <signal name="animation_finished"> <argument index="0" name="name" type="String"> </argument> <description> - Notifies when an animation finished playing. + Emitted when an animation finishes. </description> </signal> <signal name="animation_started"> <argument index="0" name="name" type="String"> </argument> <description> - Notifies when an animation starts playing. + Emitted when an animation starts. </description> </signal> </signals> diff --git a/doc/classes/Area.xml b/doc/classes/Area.xml index f58aa3cc0a..b74e767fd2 100644 --- a/doc/classes/Area.xml +++ b/doc/classes/Area.xml @@ -17,7 +17,7 @@ <argument index="0" name="bit" type="int"> </argument> <description> - Return an individual bit on the layer mask. + Returns an individual bit on the layer mask. </description> </method> <method name="get_collision_mask_bit" qualifiers="const"> @@ -26,7 +26,7 @@ <argument index="0" name="bit" type="int"> </argument> <description> - Return an individual bit on the collision mask. + Returns an individual bit on the collision mask. </description> </method> <method name="get_overlapping_areas" qualifiers="const"> @@ -69,7 +69,7 @@ <argument index="1" name="value" type="bool"> </argument> <description> - Set/clear individual bits on the layer mask. This makes getting an area in/out of only one layer easier. + Set/clear individual bits on the layer mask. This simplifies editing this [code]Area[code]'s layers. </description> </method> <method name="set_collision_mask_bit"> @@ -80,7 +80,7 @@ <argument index="1" name="value" type="bool"> </argument> <description> - Set/clear individual bits on the collision mask. This makes selecting the areas scanned easier. + Set/clear individual bits on the collision mask. This simplifies editing which [code]Area[/code] layers this [code]Area[/code] scans. </description> </method> </methods> @@ -125,12 +125,16 @@ The area's priority. Higher priority areas are processed first. Default value: 0. </member> <member name="reverb_bus_amount" type="float" setter="set_reverb_amount" getter="get_reverb_amount"> + The degree to which this area applies reverb to its associated audio. Ranges from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision. </member> <member name="reverb_bus_enable" type="bool" setter="set_use_reverb_bus" getter="is_using_reverb_bus"> + If [code]true[/code] the area applies reverb to its associated audio. </member> <member name="reverb_bus_name" type="String" setter="set_reverb_bus" getter="get_reverb_bus"> + The reverb bus name to use for this area's associated audio. </member> <member name="reverb_bus_uniformity" type="float" setter="set_reverb_uniformity" getter="get_reverb_uniformity"> + The degree to which this area's reverb is a uniform effect. Ranges from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision. </member> <member name="space_override" type="int" setter="set_space_override_mode" getter="get_space_override_mode" enum="Area.SpaceOverride"> Override mode for gravity and damping calculations within this area. See the SPACE_OVERRIDE_* constants for values. diff --git a/doc/classes/CenterContainer.xml b/doc/classes/CenterContainer.xml index 0db18aed53..6235a3fec4 100644 --- a/doc/classes/CenterContainer.xml +++ b/doc/classes/CenterContainer.xml @@ -14,6 +14,7 @@ </methods> <members> <member name="use_top_left" type="bool" setter="set_use_top_left" getter="is_using_top_left"> + If [code]true[/code] centers children relative to the [code]CenterContainer[/code]'s top left corner. Default value: [code]false[/code]. </member> </members> <constants> diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index c538f66779..ee34b2bcd1 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -15,13 +15,23 @@ <return type="ColorPicker"> </return> <description> + Returns the [code]ColorPicker[/code] that this [code]ColorPickerButton[/code] toggles. + </description> + </method> + <method name="get_popup"> + <return type="PopupPanel"> + </return> + <description> + Returns the control's [PopupPanel] which allows you to connect to Popup Signals. This allows you to handle events when the ColorPicker is shown or hidden. </description> </method> </methods> <members> <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color"> + The currently selected color. </member> <member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha"> + If [code]true[/code] the alpha channel in the displayed [ColorPicker] will be visible. Default value: [code]true[/code]. </member> </members> <signals> @@ -29,7 +39,7 @@ <argument index="0" name="color" type="Color"> </argument> <description> - Emitted when the color is changed. + Emitted when the color changes. </description> </signal> </signals> diff --git a/doc/classes/CurveTexture.xml b/doc/classes/CurveTexture.xml index 73126de4aa..f62da8a135 100644 --- a/doc/classes/CurveTexture.xml +++ b/doc/classes/CurveTexture.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CurveTexture" inherits="Texture" category="Core" version="3.0-beta"> <brief_description> + A texture that shows a curve. </brief_description> <description> + Renders a given [Curve] provided to it. Simplifies the task of drawing curves and/or saving them as image files. </description> <tutorials> </tutorials> @@ -12,8 +14,10 @@ </methods> <members> <member name="curve" type="Curve" setter="set_curve" getter="get_curve"> + The [code]curve[/code] rendered onto the texture. </member> <member name="width" type="int" setter="set_width" getter="get_width"> + The width of the texture. </member> </members> <constants> diff --git a/doc/classes/EditorFileDialog.xml b/doc/classes/EditorFileDialog.xml index e893d92840..4529a473c6 100644 --- a/doc/classes/EditorFileDialog.xml +++ b/doc/classes/EditorFileDialog.xml @@ -15,12 +15,15 @@ <argument index="0" name="filter" type="String"> </argument> <description> + Adds a comma-delimited file extension filter option to the [code]EditorFileDialog[/code] with an optional semi-colon-delimited label. + Example: "*.tscn, *.scn; Scenes", results in filter text "Scenes (*.tscn, *.scn)". </description> </method> <method name="clear_filters"> <return type="void"> </return> <description> + Removes all filters except for "All Files (*)". </description> </method> <method name="get_access" qualifiers="const"> @@ -63,12 +66,14 @@ <return type="VBoxContainer"> </return> <description> + Returns the [code]VBoxContainer[/code] used to display the file system. </description> </method> <method name="invalidate"> <return type="void"> </return> <description> + Notify the [code]EditorFileDialog[/code] that its view of the data is no longer accurate. Updates the view contents on next view update. </description> </method> <method name="is_overwrite_warning_disabled" qualifiers="const"> @@ -148,46 +153,85 @@ </description> </method> </methods> + <members> + <member name="access" type="int" enum="EditorFileDialog.Access" setter="set_access" getter="get_access"> + The location from which the user may select a file, including [code]res://[/code], [code]user://[/code], and the local file system. + </member> + <member name="display_mode" type="int" enum="EditorFileDialog.DisplayMode" setter="set_display_mode" getter="get_display_mode"> + The view format in which the [code]EditorFileDialog[/code] displays resources to the user. + </member> + <member name="mode" type="int" enum="EditorFileDialog.Mode" setter="set_mode" getter="get_mode"> + The purpose of the [code]EditorFileDialog[/code]. Changes allowed behaviors. + </member> + <member name="current_dir" type="String" setter="set_current_dir" getter="get_current_dir"> + The currently occupied directory. + </member> + <member name="current_file" type="String" setter="set_current_file" getter="get_current_file"> + The currently selected file. + </member> + <member name="current_path" type="String" setter="set_current_path" getter="get_current_path"> + The file system path in the address bar. + </member> + <member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files"> + If [code]true[/code] hidden files and directories will be visible in the [code]EditorFileDialog[/code]. + </member> + <member name="disable_overwrite_warning" type="bool" setter="set_disable_overwrite_warning" getter="is_overwrite_warning_disabled"> + If [code]true[/code] the [code]EditorFileDialog[/code] will not warn the user before overwriting files. + </member> + </members> <signals> <signal name="dir_selected"> <argument index="0" name="dir" type="String"> </argument> <description> + Emitted when a directory is selected. </description> </signal> <signal name="file_selected"> <argument index="0" name="path" type="String"> </argument> <description> + Emitted when a file is selected. </description> </signal> <signal name="files_selected"> <argument index="0" name="paths" type="PoolStringArray"> </argument> <description> + Emitted when multiple files are selected. </description> </signal> </signals> <constants> <constant name="MODE_OPEN_FILE" value="0" enum="Mode"> + The [code]EditorFileDialog[/code] can select only one file. Accepting the window will open the file. </constant> <constant name="MODE_OPEN_FILES" value="1" enum="Mode"> + The [code]EditorFileDialog[/code] can select multiple files. Accepting the window will open all files. </constant> <constant name="MODE_OPEN_DIR" value="2" enum="Mode"> + The [code]EditorFileDialog[/code] can select only one directory. Accepting the window will open the directory. </constant> <constant name="MODE_OPEN_ANY" value="3" enum="Mode"> + The [code]EditorFileDialog[/code] can select a file or directory. Accepting the window will open it. </constant> <constant name="MODE_SAVE_FILE" value="4" enum="Mode"> + The [code]EditorFileDialog[/code] can select only one file. Accepting the window will save the file. </constant> <constant name="ACCESS_RESOURCES" value="0" enum="Access"> + The [code]EditorFileDialog[/code] can only view [code]res://[/code] directory contents. </constant> <constant name="ACCESS_USERDATA" value="1" enum="Access"> + The [code]EditorFileDialog[/code] can only view [code]user://[/code] directory contents. </constant> <constant name="ACCESS_FILESYSTEM" value="2" enum="Access"> + The [code]EditorFileDialog[/code] can view the entire local file system. </constant> <constant name="DISPLAY_THUMBNAILS" value="0" enum="DisplayMode"> + The [code]EditorFileDialog[/code] displays resources as thumbnails. </constant> <constant name="DISPLAY_LIST" value="1" enum="DisplayMode"> + The [code]EditorFileDialog[/code] displays resources as a list of filenames. </constant> </constants> </class> diff --git a/doc/classes/NetworkedMultiplayerPeer.xml b/doc/classes/NetworkedMultiplayerPeer.xml index 33ffce9cf9..a7350b3863 100644 --- a/doc/classes/NetworkedMultiplayerPeer.xml +++ b/doc/classes/NetworkedMultiplayerPeer.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="NetworkedMultiplayerPeer" inherits="PacketPeer" category="Core" version="3.0-beta"> <brief_description> + A high-level network interface to simplify multiplayer interactions. </brief_description> <description> + Manages the connection to network peers. Assigns unique IDs to each client connected to the server. </description> <tutorials> </tutorials> @@ -13,31 +15,35 @@ <return type="int" enum="NetworkedMultiplayerPeer.ConnectionStatus"> </return> <description> + Returns the current state of the connection. See [enum ConnectionStatus]. </description> </method> <method name="get_packet_peer" qualifiers="const"> <return type="int"> </return> <description> + Returns the ID of the [code]NetworkedMultiplayerPeer[/code] who sent the most recent packet. </description> </method> <method name="get_unique_id" qualifiers="const"> <return type="int"> </return> <description> + Returns the ID of this [code]NetworkedMultiplayerPeer[/code]. </description> </method> <method name="is_refusing_new_connections" qualifiers="const"> <return type="bool"> </return> <description> - Return whether this [code]NetworkedMultiplayerPeer[/code] is refusing new connections. + Returns [code]true[/code] if this [code]NetworkedMultiplayerPeer[/code] refuses new connections. Default value: [code]false[/code]. </description> </method> <method name="poll"> <return type="void"> </return> <description> + Waits up to 1 second to receive a new network event. </description> </method> <method name="set_refuse_new_connections"> @@ -46,7 +52,7 @@ <argument index="0" name="enable" type="bool"> </argument> <description> - If [code]endable[/code] is true, this [code]NetworkedMultiplayerPeer[/code] will refuse new connections. + If [code]true[/code] this [code]NetworkedMultiplayerPeer[/code] refuses new connections. Default value: [code]false[/code]. </description> </method> <method name="set_target_peer"> @@ -55,6 +61,7 @@ <argument index="0" name="id" type="int"> </argument> <description> + The peer to which packets will be sent. Default value: [code]0[/code]. </description> </method> <method name="set_transfer_mode"> @@ -63,56 +70,65 @@ <argument index="0" name="mode" type="int" enum="NetworkedMultiplayerPeer.TransferMode"> </argument> <description> + The manner in which to send packets to the [code]target_peer[/code]. See [enum TransferMode]. </description> </method> </methods> <signals> <signal name="connection_failed"> <description> - Emitted when failed to connect to server. + Emitted when a connection attempt fails. </description> </signal> <signal name="connection_succeeded"> <description> - Emitted when successfully connected to server. + Emitted when a connection attempt succeeds. </description> </signal> <signal name="peer_connected"> <argument index="0" name="id" type="int"> </argument> <description> - Emitted by the server when a client is connected. + Emitted by the server when a client connects. </description> </signal> <signal name="peer_disconnected"> <argument index="0" name="id" type="int"> </argument> <description> - Emitted by the server when a client is disconnected. + Emitted by the server when a client disconnects. </description> </signal> <signal name="server_disconnected"> <description> - Emitted by clients when server is disconnected. + Emitted by clients when the server disconnects. </description> </signal> </signals> <constants> <constant name="TRANSFER_MODE_UNRELIABLE" value="0" enum="TransferMode"> + Packets are sent via unordered UDP packets. </constant> <constant name="TRANSFER_MODE_UNRELIABLE_ORDERED" value="1" enum="TransferMode"> + Packets are sent via ordered UDP packets. </constant> <constant name="TRANSFER_MODE_RELIABLE" value="2" enum="TransferMode"> + Packets are sent via TCP packets. </constant> <constant name="CONNECTION_DISCONNECTED" value="0" enum="ConnectionStatus"> + The ongoing connection disconnected. </constant> <constant name="CONNECTION_CONNECTING" value="1" enum="ConnectionStatus"> + A connection attempt is ongoing. </constant> <constant name="CONNECTION_CONNECTED" value="2" enum="ConnectionStatus"> + The connection attempt succeeded. </constant> <constant name="TARGET_PEER_BROADCAST" value="0"> + Packets are sent to the server and then redistributed to other peers. </constant> <constant name="TARGET_PEER_SERVER" value="1"> + Packets are sent to the server alone. </constant> </constants> </class> diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml index 3940995936..80ef3afdb1 100644 --- a/doc/classes/PackedScene.xml +++ b/doc/classes/PackedScene.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="PackedScene" inherits="Resource" category="Core" version="3.0-beta"> <brief_description> + An abstraction of a serialized scene. </brief_description> <description> + A simplified interface to a scene file. Provides access to operations and checks that can be performed on the scene resource itself. TODO: explain ownership, and that node does not need to own itself </description> <tutorials> @@ -14,12 +16,14 @@ <return type="bool"> </return> <description> + Returns [code]true[/code] if the scene file has nodes. </description> </method> <method name="get_state"> <return type="SceneState"> </return> <description> + Returns the [code]SceneState[/code] representing the scene file contents. </description> </method> <method name="instance" qualifiers="const"> @@ -28,6 +32,7 @@ <argument index="0" name="edit_state" type="int" enum="PackedScene.GenEditState" default="0"> </argument> <description> + Instantiates the scene's node hierarchy. Triggers child scene instantiation(s). Triggers the [enum Object.NOTIFICATION_INSTANCED] notification on the root node. </description> </method> <method name="pack"> @@ -42,14 +47,19 @@ </methods> <members> <member name="_bundled" type="Dictionary" setter="_set_bundled_scene" getter="_get_bundled_scene"> + A dictionary representation of the scene contents. + Available keys include "rnames" and "variants" for resources, "node_count", "nodes", "node_paths" for nodes, "editable_instances" for base scene children overrides, "conn_count" and "conns" for signal connections, and "version" for the format style of the PackedScene. </member> </members> <constants> <constant name="GEN_EDIT_STATE_DISABLED" value="0" enum="GenEditState"> + If passed to [method instance], blocks edits to the scene state. </constant> <constant name="GEN_EDIT_STATE_INSTANCE" value="1" enum="GenEditState"> + If passed to [method instance], provides local scene resources to the local scene. Requires tools compiled. </constant> <constant name="GEN_EDIT_STATE_MAIN" value="2" enum="GenEditState"> + If passed to [method instance], provides local scene resources to the local scene. Only the main scene should receive the main edit state. Requires tools compiled. </constant> </constants> </class> diff --git a/doc/classes/SceneState.xml b/doc/classes/SceneState.xml index 20ca43b71a..4fcaaa23dc 100644 --- a/doc/classes/SceneState.xml +++ b/doc/classes/SceneState.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="SceneState" inherits="Reference" category="Core" version="3.0-beta"> <brief_description> + A script interface to a scene file's data. </brief_description> <description> + Maintains a list of resources, nodes, exported and overridden properties, and built-in scripts associated with a scene. </description> <tutorials> </tutorials> @@ -15,12 +17,14 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the list of bound parameters for the signal at [code]idx[/code]. </description> </method> <method name="get_connection_count" qualifiers="const"> <return type="int"> </return> <description> + Returns the number of signal connections in the scene. </description> </method> <method name="get_connection_flags" qualifiers="const"> @@ -29,6 +33,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the flags for the signal at [code]idx[/code]. See [Object]'s [code]CONNECT_*[/code] flags. </description> </method> <method name="get_connection_method" qualifiers="const"> @@ -37,6 +42,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the method connected to the signal at [code]idx[/code]. </description> </method> <method name="get_connection_signal" qualifiers="const"> @@ -45,6 +51,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the name of the signal at [code]idx[/code]. </description> </method> <method name="get_connection_source" qualifiers="const"> @@ -53,6 +60,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the path to the node that owns the signal at [code]idx[/code], relative to the root node. </description> </method> <method name="get_connection_target" qualifiers="const"> @@ -61,12 +69,14 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the path to the node that owns the method connected to the signal at [code]idx[/code], relative to the root node. </description> </method> <method name="get_node_count" qualifiers="const"> <return type="int"> </return> <description> + Returns the number of nodes in the scene. </description> </method> <method name="get_node_groups" qualifiers="const"> @@ -75,6 +85,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the list of group names associated with the node at [code]idx[/code]. </description> </method> <method name="get_node_instance" qualifiers="const"> @@ -83,6 +94,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the scene for the node at [code]idx[/code] or [code]null[/code] if the node is not an instance. </description> </method> <method name="get_node_instance_placeholder" qualifiers="const"> @@ -91,6 +103,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the path to the represented scene file if the node at [code]idx[/code] is an [InstancePlaceholder]. </description> </method> <method name="get_node_name" qualifiers="const"> @@ -99,6 +112,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the name of the node at [code]idx[/code]. </description> </method> <method name="get_node_owner_path" qualifiers="const"> @@ -107,6 +121,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the path to the owner of the node at [code]idx[/code], relative to the root node. </description> </method> <method name="get_node_path" qualifiers="const"> @@ -117,6 +132,7 @@ <argument index="1" name="for_parent" type="bool" default="false"> </argument> <description> + Returns the path to the node at [code]idx[/code]. </description> </method> <method name="get_node_property_count" qualifiers="const"> @@ -125,6 +141,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the number of exported or overridden properties for the node at [code]idx[/code]. </description> </method> <method name="get_node_property_name" qualifiers="const"> @@ -135,6 +152,7 @@ <argument index="1" name="prop_idx" type="int"> </argument> <description> + Returns the name of the property at [code]prop_idx[/code] for the node at [code]idx[/code]. </description> </method> <method name="get_node_property_value" qualifiers="const"> @@ -145,6 +163,7 @@ <argument index="1" name="prop_idx" type="int"> </argument> <description> + Returns the value of the property at [code]prop_idx[/code] for the node at [code]idx[/code]. </description> </method> <method name="get_node_type" qualifiers="const"> @@ -153,6 +172,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the type of the node at [code]idx[/code]. </description> </method> <method name="is_node_instance_placeholder" qualifiers="const"> @@ -161,15 +181,19 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns [code]true[/code] if the node at [code]idx[/code] is an [InstancePlaceholder]. </description> </method> </methods> <constants> <constant name="GEN_EDIT_STATE_DISABLED" value="0" enum="GenEditState"> + If passed to [method PackedScene.instance], blocks edits to the scene state. </constant> <constant name="GEN_EDIT_STATE_INSTANCE" value="1" enum="GenEditState"> + If passed to [method PackedScene.instance], provides inherited scene resources to the local scene. Requires tools compiled. </constant> <constant name="GEN_EDIT_STATE_MAIN" value="2" enum="GenEditState"> + If passed to [method PackedScene.instance], provides local scene resources to the local scene. Only the main scene should receive the main edit state. Requires tools compiled. </constant> </constants> </class> diff --git a/doc/classes/WindowDialog.xml b/doc/classes/WindowDialog.xml index 41aa71b782..5bdcfe238d 100644 --- a/doc/classes/WindowDialog.xml +++ b/doc/classes/WindowDialog.xml @@ -21,8 +21,10 @@ </methods> <members> <member name="resizable" type="bool" setter="set_resizable" getter="get_resizable"> + If [code]true[/code] the user can resize the window. Default value: [code]false[/code]. </member> <member name="window_title" type="String" setter="set_title" getter="get_title"> + The text displayed in the window's title bar. Default value: "Save a File". </member> </members> <constants> diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 5b3e43fc43..0839f930c9 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -208,6 +208,8 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasGLES3::_bind_canvas_texture(con } else { + texture = texture->get_ptr(); + if (texture->render_target) texture->render_target->used_in_frame = true; @@ -243,6 +245,7 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasGLES3::_bind_canvas_texture(con } else { + normal_map = normal_map->get_ptr(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); state.current_normal = p_normal_map; @@ -1115,6 +1118,8 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons continue; } + t = t->get_ptr(); + if (storage->config.srgb_decode_supported && t->using_srgb) { //no srgb in 2D glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _SKIP_DECODE_EXT); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 0f8f98b021..3031b70f70 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1235,6 +1235,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m } else { + t = t->get_ptr(); //resolve for proxies #ifdef TOOLS_ENABLED if (t->detect_3d) { t->detect_3d(t->detect_3d_ud); @@ -2164,7 +2165,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::USE_OPAQUE_PREPASS, false); } -void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_depth_pass,bool p_shadow_pass) { +void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass) { RasterizerStorageGLES3::Material *m = NULL; RID m_src = p_instance->material_override.is_valid() ? p_instance->material_override : (p_material >= 0 ? p_instance->materials[p_material] : p_geometry->material); @@ -2238,11 +2239,11 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { //shader does not use discard and does not write a vertex position, use generic material if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { - p_material = storage->material_owner.getptr( !p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); + p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); no_cull = true; mirror = false; } else { - p_material = storage->material_owner.getptr( !p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); + p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); } } @@ -2289,10 +2290,8 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G } else { e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT; e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; - } - /* if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE) e->sort_flags|=RenderList::SORT_FLAG_INSTANCING; @@ -4090,7 +4089,6 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_shadow_atlas); _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_reflection_atlas, env); - bool use_mrt = false; render_list.clear(); @@ -4774,7 +4772,6 @@ void RasterizerSceneGLES3::initialize() { default_worldcoord_material_twosided = storage->material_create(); storage->shader_set_code(default_worldcoord_shader_twosided, "shader_type spatial; render_mode cull_disabled,world_vertex_coords;\n"); storage->material_set_shader(default_worldcoord_material_twosided, default_worldcoord_shader_twosided); - } { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 7e3d21adbb..cba9f08537 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1232,6 +1232,25 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_ return texture_owner.make_rid(ctex); } +void RasterizerStorageGLES3::texture_set_proxy(RID p_texture, RID p_proxy) { + + Texture *texture = texture_owner.get(p_texture); + ERR_FAIL_COND(!texture); + + if (texture->proxy) { + texture->proxy->proxy_owners.erase(texture); + texture->proxy = NULL; + } + + if (p_proxy.is_valid()) { + Texture *proxy = texture_owner.get(p_proxy); + ERR_FAIL_COND(!proxy); + ERR_FAIL_COND(proxy == texture); + proxy->proxy_owners.insert(texture); + texture->proxy = proxy; + } +} + RID RasterizerStorageGLES3::sky_create() { Sky *sky = memnew(Sky); @@ -1617,7 +1636,6 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { shaders.actions_scene.render_mode_values["cull_back"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_BACK); shaders.actions_scene.render_mode_values["cull_disabled"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_DISABLED); - shaders.actions_scene.render_mode_flags["unshaded"] = &p_shader->spatial.unshaded; shaders.actions_scene.render_mode_flags["depth_test_disable"] = &p_shader->spatial.no_depth_test; diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 7c86862425..d5efd5307c 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -242,6 +242,9 @@ public: struct Texture : public RID_Data { + Texture *proxy; + Set<Texture *> proxy_owners; + String path; uint32_t flags; int width, height; @@ -301,6 +304,15 @@ public: detect_srgb_ud = NULL; detect_normal = NULL; detect_normal_ud = NULL; + proxy = NULL; + } + + _ALWAYS_INLINE_ Texture *get_ptr() { + if (proxy) { + return proxy; //->get_ptr(); only one level of indirection, else not inlining possible. + } else { + return this; + } } ~Texture() { @@ -309,6 +321,14 @@ public: glDeleteTextures(1, &tex_id); } + + for (Set<Texture *>::Element *E = proxy_owners.front(); E; E = E->next()) { + E->get()->proxy = NULL; + } + + if (proxy) { + proxy->proxy_owners.erase(this); + } } }; @@ -343,6 +363,8 @@ public: virtual void texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata); virtual void texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata); + virtual void texture_set_proxy(RID p_texture, RID p_proxy); + /* SKY API */ struct Sky : public RID_Data { diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index d4ef256a33..9e234f5005 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -343,7 +343,7 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { glDeleteProgram(v.id); v.id = 0; - ERR_PRINT("NO LOG, WTF"); + ERR_PRINT("Vertex shader compilation failed with empty log"); } else { if (iloglen == 0) { @@ -451,7 +451,7 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { glDeleteShader(v.vert_id); glDeleteProgram(v.id); v.id = 0; - ERR_PRINT("NO LOG, WTF"); + ERR_PRINT("Fragment shader compilation failed with empty log"); } else { if (iloglen == 0) { @@ -624,7 +624,7 @@ void ShaderGLES3::setup(const char **p_conditional_defines, int p_conditional_co feedbacks = p_feedback; feedback_count = p_feedback_count; - //split vertex and shader code (thank you, retarded shader compiler programmers from you know what company). + //split vertex and shader code (thank you, shader compiler programmers from you know what company). { String globals_tag = "\nVERTEX_SHADER_GLOBALS"; String material_tag = "\nMATERIAL_UNIFORMS"; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 79b989be4a..676541649c 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1030,7 +1030,7 @@ LIGHT_SHADER_CODE #if defined(LIGHT_USE_RIM) - float rim_light = pow(1.0-cNdotV, (1.0-roughness)*16.0); + float rim_light = pow(max(0.0,1.0-cNdotV), max(0.0,(1.0-roughness)*16.0)); diffuse_light += rim_light * rim * mix(vec3(1.0),diffuse_color,rim_tint) * light_color; #endif } diff --git a/drivers/unix/rw_lock_posix.cpp b/drivers/unix/rw_lock_posix.cpp index ab2d6495bd..00125809c0 100644 --- a/drivers/unix/rw_lock_posix.cpp +++ b/drivers/unix/rw_lock_posix.cpp @@ -39,7 +39,7 @@ void RWLockPosix::read_lock() { int err = pthread_rwlock_rdlock(&rwlock); if (err != 0) { - perror("wtf: "); + perror("Acquiring lock failed"); } ERR_FAIL_COND(err != 0); } diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp index 3bc2397e6f..e88a7d7de1 100644 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ b/drivers/unix/stream_peer_tcp_posix.cpp @@ -213,7 +213,7 @@ Error StreamPeerTCPPosix::write(const uint8_t *p_data, int p_bytes, int &r_sent, if (errno != EAGAIN) { - perror("shit?"); + perror("Nothing sent"); disconnect_from_host(); ERR_PRINT("Server disconnected!\n"); return FAILED; @@ -270,7 +270,7 @@ Error StreamPeerTCPPosix::read(uint8_t *p_buffer, int p_bytes, int &r_received, if (errno != EAGAIN) { - perror("shit?"); + perror("Nothing read"); disconnect_from_host(); ERR_PRINT("Server disconnected!\n"); return FAILED; diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h index 9b0aca67d5..0cc153945d 100644 --- a/editor/dependency_editor.h +++ b/editor/dependency_editor.h @@ -35,6 +35,7 @@ #include "scene/gui/tab_container.h" #include "scene/gui/tree.h" +class EditorFileDialog; class EditorFileSystemDirectory; class EditorNode; diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 3a72f8e569..0bb059f425 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -235,7 +235,7 @@ void DocData::generate(bool p_basic_types) { ClassDB::get_property_list(name, &properties, true); for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY) + if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_INTERNAL) continue; PropertyDoc prop; diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index da41ea87ce..5f026abb6d 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -44,8 +44,8 @@ void EditorAbout::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { Ref<Font> font = EditorNode::get_singleton()->get_gui_base()->get_font("source", "EditorFonts"); - _tpl_text->add_font_override("font", font); - _license_text->add_font_override("font", font); + _tpl_text->add_font_override("normal_font", font); + _license_text->add_font_override("normal_font", font); } break; } } @@ -53,7 +53,6 @@ void EditorAbout::_notification(int p_what) { void EditorAbout::_license_tree_selected() { TreeItem *selected = _tpl_tree->get_selected(); - _tpl_text->select(0, 0, 0, 0); _tpl_text->set_text(selected->get_metadata(0)); } @@ -165,12 +164,10 @@ EditorAbout::EditorAbout() { // License - _license_text = memnew(TextEdit); + _license_text = memnew(RichTextLabel); _license_text->set_name(TTR("License")); _license_text->set_h_size_flags(Control::SIZE_EXPAND_FILL); _license_text->set_v_size_flags(Control::SIZE_EXPAND_FILL); - _license_text->set_wrap(true); - _license_text->set_readonly(true); _license_text->set_text(String::utf8(about_license)); tc->add_child(_license_text); @@ -239,11 +236,9 @@ EditorAbout::EditorAbout() { tpl_ti_all->set_metadata(0, long_text); tpl_hbc->add_child(_tpl_tree); - _tpl_text = memnew(TextEdit); + _tpl_text = memnew(RichTextLabel); _tpl_text->set_h_size_flags(Control::SIZE_EXPAND_FILL); _tpl_text->set_v_size_flags(Control::SIZE_EXPAND_FILL); - _tpl_text->set_wrap(true); - _tpl_text->set_readonly(true); tpl_hbc->add_child(_tpl_text); _tpl_tree->connect("item_selected", this, "_license_tree_selected"); diff --git a/editor/editor_about.h b/editor/editor_about.h index ce29027f05..fe40ce5f14 100644 --- a/editor/editor_about.h +++ b/editor/editor_about.h @@ -33,11 +33,11 @@ #include "scene/gui/control.h" #include "scene/gui/dialogs.h" #include "scene/gui/item_list.h" +#include "scene/gui/rich_text_label.h" #include "scene/gui/scroll_container.h" #include "scene/gui/separator.h" #include "scene/gui/split_container.h" #include "scene/gui/tab_container.h" -#include "scene/gui/text_edit.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" @@ -55,8 +55,8 @@ private: ScrollContainer *_populate_list(const String &p_name, const List<String> &p_sections, const char **p_src[], const int p_flag_single_column = 0); Tree *_tpl_tree; - TextEdit *_license_text; - TextEdit *_tpl_text; + RichTextLabel *_license_text; + RichTextLabel *_tpl_text; TextureRect *_logo; protected: diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 8c8d9c4c79..fc73964764 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -743,6 +743,18 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & custom_map["path_remap/remapped_paths"] = path_remaps; } + // Store icon and splash images directly, they need to bypass the import system and be loaded as images + String icon = ProjectSettings::get_singleton()->get("application/config/icon"); + String splash = ProjectSettings::get_singleton()->get("application/boot_splash/image"); + if (icon != String() && FileAccess::exists(icon)) { + Vector<uint8_t> array = FileAccess::get_file_as_array(icon); + p_func(p_udata, icon, array, idx, total); + } + if (splash != String() && FileAccess::exists(splash)) { + Vector<uint8_t> array = FileAccess::get_file_as_array(splash); + p_func(p_udata, splash, array, idx, total); + } + String config_file = "project.binary"; String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index eb5af2eaeb..eaa57fa46b 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -28,12 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "editor_file_dialog.h" - +#include "dependency_editor.h" #include "editor_resource_preview.h" #include "editor_scale.h" #include "editor_settings.h" #include "os/file_access.h" #include "os/keyboard.h" +#include "os/os.h" #include "print_string.h" #include "scene/gui/center_container.h" #include "scene/gui/label.h" @@ -159,6 +160,10 @@ void EditorFileDialog::_unhandled_input(const Ref<InputEvent> &p_event) { _make_dir(); handled = true; } + if (ED_IS_SHORTCUT("file_dialog/delete", p_event)) { + _delete_items(); + handled = true; + } if (ED_IS_SHORTCUT("file_dialog/focus_path", p_event)) { dir->grab_focus(); handled = true; @@ -512,6 +517,106 @@ void EditorFileDialog::_item_dc_selected(int p_item) { } } +void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p_pos) { + + // Right click on specific file(s) or folder(s). + item_menu->clear(); + item_menu->set_size(Size2(1, 1)); + + // Allow specific actions only on one item. + bool single_item_selected = item_list->get_selected_items().size() == 1; + + // Disallow deleting the .import folder, Godot kills a cat if you do and it is possibly a senseless novice action. + bool allow_delete = true; + for (int i = 0; i < item_list->get_item_count(); i++) { + if (!item_list->is_selected(i)) { + continue; + } + Dictionary item_meta = item_list->get_item_metadata(i); + if (item_meta["path"] == "res://.import") { + allow_delete = false; + break; + } + } + + if (single_item_selected) { + item_menu->add_icon_item(get_icon("CopyNodePath", "EditorIcons"), TTR("Copy Path"), ITEM_MENU_COPY_PATH); + } + if (allow_delete) { + item_menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete"), ITEM_MENU_DELETE, KEY_DELETE); + } + if (single_item_selected) { + item_menu->add_separator(); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + } + + if (item_menu->get_item_count() > 0) { + item_menu->set_position(item_list->get_global_position() + p_pos); + item_menu->popup(); + } +} + +void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) { + + // Right click on folder background. Deselect all files so that actions are applied on the current folder. + for (int i = 0; i < item_list->get_item_count(); i++) { + item_list->unselect(i); + } + + item_menu->clear(); + item_menu->set_size(Size2(1, 1)); + + if (can_create_dir) { + item_menu->add_icon_item(get_icon("folder", "FileDialog"), TTR("New Folder.."), ITEM_MENU_NEW_FOLDER, KEY_MASK_CMD | KEY_N); + } + item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5); + item_menu->add_separator(); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + + item_menu->set_position(item_list->get_global_position() + p_pos); + item_menu->popup(); +} + +void EditorFileDialog::_item_menu_id_pressed(int p_option) { + + switch (p_option) { + + case ITEM_MENU_COPY_PATH: { + Dictionary item_meta = item_list->get_item_metadata(item_list->get_current()); + OS::get_singleton()->set_clipboard(item_meta["path"]); + } break; + + case ITEM_MENU_DELETE: { + _delete_items(); + } break; + + case ITEM_MENU_REFRESH: { + invalidate(); + } break; + + case ITEM_MENU_NEW_FOLDER: { + _make_dir(); + } break; + + case ITEM_MENU_SHOW_IN_EXPLORER: { + String path; + int idx = item_list->get_current(); + if (idx == -1 || item_list->get_selected_items().size() == 0) { + // Folder background was clicked. Open this folder. + path = ProjectSettings::get_singleton()->globalize_path(dir_access->get_current_dir()); + } else { + // Specific item was clicked. Open folders directly, or the folder containing a selected file. + Dictionary item_meta = item_list->get_item_metadata(idx); + path = ProjectSettings::get_singleton()->globalize_path(item_meta["path"]); + if (!item_meta["dir"]) { + path = path.get_base_dir(); + } + } + OS::get_singleton()->shell_open(String("file://") + path); + } break; + } +} + bool EditorFileDialog::_is_open_should_be_disabled() { if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE) @@ -617,7 +722,7 @@ void EditorFileDialog::update_file_list() { Dictionary d; d["name"] = dir_name; - d["path"] = String(); + d["path"] = cdir.plus_file(dir_name); d["dir"] = true; item_list->set_item_metadata(item_list->get_item_count() - 1, d); @@ -657,8 +762,6 @@ void EditorFileDialog::update_file_list() { } } - String base_dir = dir_access->get_current_dir(); - while (!files.empty()) { bool match = patterns.empty(); @@ -679,7 +782,7 @@ void EditorFileDialog::update_file_list() { if (get_icon_func) { - Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get())); + Ref<Texture> icon = get_icon_func(cdir.plus_file(files.front()->get())); //ti->set_icon(0,icon); if (display_mode == DISPLAY_THUMBNAILS) { @@ -698,12 +801,11 @@ void EditorFileDialog::update_file_list() { Dictionary d; d["name"] = files.front()->get(); d["dir"] = false; - String fullpath = base_dir.plus_file(files.front()->get()); - + String fullpath = cdir.plus_file(files.front()->get()); if (display_mode == DISPLAY_THUMBNAILS) { EditorResourcePreview::get_singleton()->queue_resource_preview(fullpath, this, "_thumbnail_result", fullpath); } - d["path"] = base_dir.plus_file(files.front()->get()); + d["path"] = fullpath; //ti->set_metadata(0,d); item_list->set_item_metadata(item_list->get_item_count() - 1, d); @@ -723,7 +825,7 @@ void EditorFileDialog::update_file_list() { fav_down->set_disabled(true); get_ok()->set_disabled(_is_open_should_be_disabled()); for (int i = 0; i < favorites->get_item_count(); i++) { - if (favorites->get_item_metadata(i) == base_dir) { + if (favorites->get_item_metadata(i) == cdir) { favorites->select(i); favorite->set_pressed(true); if (i > 0) { @@ -854,27 +956,27 @@ void EditorFileDialog::set_mode(Mode p_mode) { case MODE_OPEN_FILE: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a File")); - makedir->hide(); + can_create_dir = false; break; case MODE_OPEN_FILES: get_ok()->set_text(TTR("Open")); set_title(TTR("Open File(s)")); - makedir->hide(); + can_create_dir = false; break; case MODE_OPEN_DIR: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a Directory")); - makedir->show(); + can_create_dir = true; break; case MODE_OPEN_ANY: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a File or Directory")); - makedir->show(); + can_create_dir = true; break; case MODE_SAVE_FILE: get_ok()->set_text(TTR("Save")); set_title(TTR("Save a File")); - makedir->show(); + can_create_dir = true; break; } @@ -883,6 +985,12 @@ void EditorFileDialog::set_mode(Mode p_mode) { } else { item_list->set_select_mode(ItemList::SELECT_SINGLE); } + + if (can_create_dir) { + makedir->show(); + } else { + makedir->hide(); + } } EditorFileDialog::Mode EditorFileDialog::get_mode() const { @@ -954,6 +1062,28 @@ void EditorFileDialog::_make_dir() { makedirname->grab_focus(); } +void EditorFileDialog::_delete_items() { + + // Collect the selected folders and files to delete and check them in the deletion dependency dialog. + Vector<String> folders; + Vector<String> files; + for (int i = 0; i < item_list->get_item_count(); i++) { + if (!item_list->is_selected(i)) { + continue; + } + Dictionary item_meta = item_list->get_item_metadata(i); + if (item_meta["dir"]) { + folders.push_back(item_meta["path"]); + } else { + files.push_back(item_meta["path"]); + } + } + if (folders.size() + files.size() > 0) { + remove_dialog->set_size(Size2(1, 1)); + remove_dialog->show(folders, files); + } +} + void EditorFileDialog::_select_drive(int p_idx) { String d = drives->get_item_text(p_idx); @@ -1181,6 +1311,9 @@ void EditorFileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_item_selected"), &EditorFileDialog::_item_selected); ClassDB::bind_method(D_METHOD("_items_clear_selection"), &EditorFileDialog::_items_clear_selection); + ClassDB::bind_method(D_METHOD("_item_list_item_rmb_selected"), &EditorFileDialog::_item_list_item_rmb_selected); + ClassDB::bind_method(D_METHOD("_item_list_rmb_clicked"), &EditorFileDialog::_item_list_rmb_clicked); + ClassDB::bind_method(D_METHOD("_item_menu_id_pressed"), &EditorFileDialog::_item_menu_id_pressed); ClassDB::bind_method(D_METHOD("_item_db_selected"), &EditorFileDialog::_item_dc_selected); ClassDB::bind_method(D_METHOD("_dir_entered"), &EditorFileDialog::_dir_entered); ClassDB::bind_method(D_METHOD("_file_entered"), &EditorFileDialog::_file_entered); @@ -1232,6 +1365,15 @@ void EditorFileDialog::_bind_methods() { ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::POOL_STRING_ARRAY, "paths"))); ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir"))); + ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List"), "set_display_mode", "get_display_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR), "set_current_dir", "get_current_dir"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file", PROPERTY_HINT_FILE, "*"), "set_current_file", "get_current_file"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path"), "set_current_path", "get_current_path"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_overwrite_warning"), "set_disable_overwrite_warning", "is_overwrite_warning_disabled"); + BIND_ENUM_CONSTANT(MODE_OPEN_FILE); BIND_ENUM_CONSTANT(MODE_OPEN_FILES); BIND_ENUM_CONSTANT(MODE_OPEN_DIR); @@ -1317,6 +1459,7 @@ EditorFileDialog::EditorFileDialog() { ED_SHORTCUT("file_dialog/toggle_favorite", TTR("Toggle Favorite"), KEY_MASK_ALT | KEY_F); ED_SHORTCUT("file_dialog/toggle_mode", TTR("Toggle Mode"), KEY_MASK_ALT | KEY_V); ED_SHORTCUT("file_dialog/create_folder", TTR("Create Folder"), KEY_MASK_CMD | KEY_N); + ED_SHORTCUT("file_dialog/delete", TTR("Delete"), KEY_DELETE); ED_SHORTCUT("file_dialog/focus_path", TTR("Focus Path"), KEY_MASK_CMD | KEY_D); ED_SHORTCUT("file_dialog/move_favorite_up", TTR("Move Favorite Up"), KEY_MASK_CMD | KEY_UP); ED_SHORTCUT("file_dialog/move_favorite_down", TTR("Move Favorite Down"), KEY_MASK_CMD | KEY_DOWN); @@ -1423,10 +1566,21 @@ EditorFileDialog::EditorFileDialog() { list_vb->add_child(memnew(Label(TTR("Directories & Files:")))); preview_hb->add_child(list_vb); + // Item (files and folders) list with context menu + item_list = memnew(ItemList); item_list->set_v_size_flags(SIZE_EXPAND_FILL); + item_list->connect("item_rmb_selected", this, "_item_list_item_rmb_selected"); + item_list->connect("rmb_clicked", this, "_item_list_rmb_clicked"); + item_list->set_allow_rmb_select(true); list_vb->add_child(item_list); + item_menu = memnew(PopupMenu); + item_menu->connect("id_pressed", this, "_item_menu_id_pressed"); + add_child(item_menu); + + // Other stuff + preview_vb = memnew(VBoxContainer); preview_hb->add_child(preview_vb); CenterContainer *prev_cc = memnew(CenterContainer); @@ -1465,9 +1619,11 @@ EditorFileDialog::EditorFileDialog() { confirm_save = memnew(ConfirmationDialog); confirm_save->set_as_toplevel(true); add_child(confirm_save); - confirm_save->connect("confirmed", this, "_save_confirm_pressed"); + remove_dialog = memnew(DependencyRemoveDialog); + add_child(remove_dialog); + makedialog = memnew(ConfirmationDialog); makedialog->set_title(TTR("Create Folder")); VBoxContainer *makevb = memnew(VBoxContainer); diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 0599d222f3..f4a9a174e7 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -39,6 +39,9 @@ #include "scene/gui/split_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" + +class DependencyRemoveDialog; + /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -75,6 +78,14 @@ public: static RegisterFunc unregister_func; private: + enum ItemMenu { + ITEM_MENU_COPY_PATH, + ITEM_MENU_DELETE, + ITEM_MENU_REFRESH, + ITEM_MENU_NEW_FOLDER, + ITEM_MENU_SHOW_IN_EXPLORER + }; + ConfirmationDialog *makedialog; LineEdit *makedirname; @@ -83,6 +94,7 @@ private: //Button *action; VBoxContainer *vbox; Mode mode; + bool can_create_dir; LineEdit *dir; ToolButton *dir_prev; @@ -91,6 +103,7 @@ private: OptionButton *drives; ItemList *item_list; + PopupMenu *item_menu; TextureRect *preview; VBoxContainer *preview_vb; HSplitContainer *list_hb; @@ -100,6 +113,7 @@ private: OptionButton *filter; DirAccess *dir_access; ConfirmationDialog *confirm_save; + DependencyRemoveDialog *remove_dialog; ToolButton *mode_thumbnails; ToolButton *mode_list; @@ -146,6 +160,10 @@ private: void _items_clear_selection(); void _item_dc_selected(int p_item); + void _item_list_item_rmb_selected(int p_item, const Vector2 &p_pos); + void _item_list_rmb_clicked(const Vector2 &p_pos); + void _item_menu_id_pressed(int p_option); + void _select_drive(int p_idx); void _dir_entered(String p_dir); void _file_entered(const String &p_file); @@ -156,6 +174,8 @@ private: void _make_dir(); void _make_dir_confirm(); + void _delete_items(); + void _update_drives(); void _go_up(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 1cc518ff31..d462cce908 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1244,8 +1244,10 @@ void EditorFileSystem::update_file(const String &p_file) { if (!FileAccess::exists(p_file)) { //was removed _delete_internal_files(p_file); - memdelete(fs->files[cpos]); - fs->files.remove(cpos); + if (cpos != -1) { // Might've never been part of the editor file system (*.* files deleted in Open dialog). + memdelete(fs->files[cpos]); + fs->files.remove(cpos); + } call_deferred("emit_signal", "filesystem_changed"); //update later return; } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 5fc27c2e3c..8f427582ae 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -78,50 +78,40 @@ void EditorHelpSearch::_sbox_input(const Ref<InputEvent> &p_ie) { } } -void EditorHelpSearch::_update_search() { +class EditorHelpSearch::IncrementalSearch : public Reference { + String term; + TreeItem *root; - search_options->clear(); - search_options->set_hide_root(true); + EditorHelpSearch *search; + Tree *search_options; - /* - TreeItem *root = search_options->create_item(); - _parse_fs(EditorFileSystem::get_singleton()->get_filesystem()); -*/ + DocData *doc; + Ref<Texture> def_icon; - List<StringName> type_list; - ClassDB::get_class_list(&type_list); + int phase; + Map<String, DocData::ClassDoc>::Element *iterator; - DocData *doc = EditorHelp::get_doc_data(); - String term = search_box->get_text(); - if (term.length() < 2) - return; - - TreeItem *root = search_options->create_item(); - - Ref<Texture> def_icon = get_icon("Node", "EditorIcons"); - //classes first - for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { + void phase1(Map<String, DocData::ClassDoc>::Element *E) { if (E->key().findn(term) != -1) { TreeItem *item = search_options->create_item(root); item->set_metadata(0, "class_name:" + E->key()); item->set_text(0, E->key() + " (Class)"); - if (has_icon(E->key(), "EditorIcons")) - item->set_icon(0, get_icon(E->key(), "EditorIcons")); + if (search->has_icon(E->key(), "EditorIcons")) + item->set_icon(0, search->get_icon(E->key(), "EditorIcons")); else item->set_icon(0, def_icon); } } - //class methods, etc second - for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { + void phase2(Map<String, DocData::ClassDoc>::Element *E) { DocData::ClassDoc &c = E->get(); Ref<Texture> cicon; - if (has_icon(E->key(), "EditorIcons")) - cicon = get_icon(E->key(), "EditorIcons"); + if (search->has_icon(E->key(), "EditorIcons")) + cicon = search->get_icon(E->key(), "EditorIcons"); else cicon = def_icon; @@ -180,72 +170,80 @@ void EditorHelpSearch::_update_search() { } } - //same but descriptions + bool slice() { - for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { + if (phase > 2) + return true; - DocData::ClassDoc &c = E->get(); + if (iterator) { - Ref<Texture> cicon; - if (has_icon(E->key(), "EditorIcons")) - cicon = get_icon(E->key(), "EditorIcons"); - else - cicon = def_icon; + switch (phase) { + + case 1: { + phase1(iterator); + } break; + case 2: { + phase2(iterator); + } break; + default: { + WARN_PRINT("illegal phase in IncrementalSearch"); + return true; + } + } - if (c.description.findn(term) != -1) { + iterator = iterator->next(); + } else { - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_desc:" + E->key()); - item->set_text(0, E->key() + " (Class Description)"); - item->set_icon(0, cicon); + phase += 1; + iterator = doc->class_list.front(); } - for (int i = 0; i < c.methods.size(); i++) { + return false; + } - if (c.methods[i].description.findn(term) != -1) { +public: + IncrementalSearch(EditorHelpSearch *p_search, Tree *p_search_options, const String &p_term) + : search(p_search), search_options(p_search_options) { - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_method_desc:" + E->key() + ":" + c.methods[i].name); - item->set_text(0, E->key() + "." + c.methods[i].name + " (Method Description)"); - item->set_icon(0, cicon); - } - } - - for (int i = 0; i < c.signals.size(); i++) { + def_icon = search->get_icon("Node", "EditorIcons"); + doc = EditorHelp::get_doc_data(); - if (c.signals[i].description.findn(term) != -1) { + term = p_term; - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_signal:" + E->key() + ":" + c.signals[i].name); - item->set_text(0, E->key() + "." + c.signals[i].name + " (Signal Description)"); - item->set_icon(0, cicon); - } - } + root = search_options->create_item(); + phase = 0; + iterator = 0; + } - for (int i = 0; i < c.constants.size(); i++) { + bool empty() const { - if (c.constants[i].description.findn(term) != -1) { + return root->get_children() == NULL; + } - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_constant:" + E->key() + ":" + c.constants[i].name); - item->set_text(0, E->key() + "." + c.constants[i].name + " (Constant Description)"); - item->set_icon(0, cicon); - } - } + bool work(uint64_t slot = 1000000 / 10) { - for (int i = 0; i < c.properties.size(); i++) { + const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot; - if (c.properties[i].description.findn(term) != -1) { + while (!slice()) { - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_property_desc:" + E->key() + ":" + c.properties[i].name); - item->set_text(0, E->key() + "." + c.properties[i].name + " (Property Description)"); - item->set_icon(0, cicon); - } + if (OS::get_singleton()->get_ticks_usec() > until) + return false; } + + return true; } +}; - get_ok()->set_disabled(root->get_children() == NULL); +void EditorHelpSearch::_update_search() { + search_options->clear(); + search_options->set_hide_root(true); + + String term = search_box->get_text(); + if (term.length() < 2) + return; + + search = Ref<IncrementalSearch>(memnew(IncrementalSearch(this, search_options, term))); + set_process(true); } void EditorHelpSearch::_confirmed() { @@ -281,6 +279,20 @@ void EditorHelpSearch::_notification(int p_what) { //_update_icons search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + } else if (p_what == NOTIFICATION_PROCESS) { + + if (search.is_valid()) { + + if (search->work()) { + + get_ok()->set_disabled(search->empty()); + search = Ref<IncrementalSearch>(); + set_process(false); + } + } else { + + set_process(false); + } } } diff --git a/editor/editor_help.h b/editor/editor_help.h index 92c0e2f4d1..a224c7f8ee 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -53,6 +53,9 @@ class EditorHelpSearch : public ConfirmationDialog { Tree *search_options; String base_type; + class IncrementalSearch; + Ref<IncrementalSearch> search; + void _update_search(); void _sbox_input(const Ref<InputEvent> &p_ie); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index fbf6c86c35..31ed86d05a 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1394,11 +1394,13 @@ void EditorNode::_property_editor_back() { } void EditorNode::_menu_collapseall() { - property_editor->collapse_all_parent_nodes(); + + property_editor->collapse_all_folding(); } void EditorNode::_menu_expandall() { - property_editor->expand_all_parent_nodes(); + + property_editor->expand_all_folding(); } void EditorNode::_save_default_environment() { @@ -1495,7 +1497,7 @@ void EditorNode::_edit_current() { if (FileAccess::exists(base_path + ".import")) { editable_warning = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); } else { - if (!get_edited_scene() || get_edited_scene()->get_filename() != base_path) { + if ((!get_edited_scene() || get_edited_scene()->get_filename() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") { editable_warning = TTR("This resource belongs to a scene that was instanced or inherited.\nChanges to it will not be kept when saving the current scene."); } } @@ -1674,7 +1676,6 @@ void EditorNode::_resource_selected(const RES &p_res, const String &p_property) void EditorNode::_run(bool p_current, const String &p_custom) { if (editor_run.get_status() == EditorRun::STATUS_PLAY) { - play_button->set_pressed(!_playing_edited); play_scene_button->set_pressed(_playing_edited); return; @@ -1806,6 +1807,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { play_button->set_pressed(true); play_button->set_icon(gui_base->get_icon("Reload", "EditorIcons")); } + stop_button->set_disabled(false); _playing_edited = p_current; } @@ -2277,6 +2279,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons")); play_custom_scene_button->set_pressed(false); play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom", "EditorIcons")); + stop_button->set_disabled(true); + if (bool(EDITOR_DEF("run/output/always_close_output_on_stop", true))) { for (int i = 0; i < bottom_panel_items.size(); i++) { if (bottom_panel_items[i].control == log) { @@ -5264,6 +5268,7 @@ EditorNode::EditorNode() { stop_button->set_icon(gui_base->get_icon("Stop", "EditorIcons")); stop_button->connect("pressed", this, "_menu_option", make_binds(RUN_STOP)); stop_button->set_tooltip(TTR("Stop the scene.")); + stop_button->set_disabled(true); stop_button->set_shortcut(ED_SHORTCUT("editor/stop", TTR("Stop"), KEY_F8)); run_native = memnew(EditorRunNative); @@ -5441,7 +5446,7 @@ EditorNode::EditorNode() { 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/expand_all_properties", false)) == false); + property_editor->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false))); property_editor->hide_top_label(); property_editor->register_text_enter(search_box); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 638b23382d..2f73e459ed 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -416,6 +416,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["editors/3d/freelook/freelook_modifier_speed_factor"] = PropertyInfo(Variant::REAL, "editors/3d/freelook/freelook_modifier_speed_factor", PROPERTY_HINT_RANGE, "0.0, 10.0, 0.1"); _initial_set("editors/3d/freelook/freelook_speed_zoom_link", false); + _initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8)); _initial_set("editors/2d/bone_width", 5); _initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9)); _initial_set("editors/2d/bone_color2", Color(0.75, 0.75, 0.75, 0.9)); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index ae29b7420e..23c32a5793 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -793,6 +793,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // TextEdit theme->set_stylebox("normal", "TextEdit", style_widget); theme->set_stylebox("focus", "TextEdit", style_widget_hover); + theme->set_stylebox("read_only", "TextEdit", style_widget_disabled); theme->set_constant("side_margin", "TabContainer", 0); theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons")); theme->set_color("font_color", "TextEdit", font_color); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index d18e97fe83..ddcdb5a321 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2294,7 +2294,7 @@ void CanvasItemEditor::_draw_focus() { void CanvasItemEditor::_draw_guides() { - Color guide_color = Color(0.6, 0.0, 0.8); + Color guide_color = EditorSettings::get_singleton()->get("editors/2d/guides_color"); Transform2D xform = viewport_scrollable->get_transform() * transform; // Guides already there @@ -4314,7 +4314,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { show_grid = false; show_helpers = false; - show_rulers = false; + show_rulers = true; show_guides = true; zoom = 1; grid_offset = Point2(); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index ed04c90cc5..558f44769d 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -235,29 +235,34 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from) { Ref<Material> material = p_from; ERR_FAIL_COND_V(material.is_null(), Ref<Texture>()); - VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid()); + if (material->get_shader_mode() == Shader::MODE_SPATIAL) { - VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture + VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid()); - preview_done = false; - VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant()); + VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture - while (!preview_done) { - OS::get_singleton()->delay_usec(10); - } + preview_done = false; + VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant()); - Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture); - VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID()); + while (!preview_done) { + OS::get_singleton()->delay_usec(10); + } - ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>()); + Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture); + VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID()); - int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); - thumbnail_size *= EDSCALE; - img->convert(Image::FORMAT_RGBA8); - img->resize(thumbnail_size, thumbnail_size); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img, 0); - return ptex; + ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>()); + + int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); + thumbnail_size *= EDSCALE; + img->convert(Image::FORMAT_RGBA8); + img->resize(thumbnail_size, thumbnail_size); + Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); + ptex->create_from_image(img, 0); + return ptex; + } + + return Ref<Texture>(); } EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 19293360ed..3a443e1bf7 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1042,8 +1042,13 @@ void ScriptTextEditor::_edit_option(int p_op) { String delimiter = "#"; List<String> comment_delimiters; scr->get_language()->get_comment_delimiters(&comment_delimiters); - if (!comment_delimiters.empty()) { - delimiter = comment_delimiters.front()->get(); + + for (List<String>::Element *E = comment_delimiters.front(); E; E = E->next()) { + String script_delimiter = E->get(); + if (script_delimiter.find(" ") == -1) { + delimiter = script_delimiter; + break; + } } tx->begin_complex_operation(); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 60d7e59991..b4d89526b0 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -508,7 +508,8 @@ public: } else if (current->has_setting("application/config/name")) { project_name->set_text(current->get("application/config/name")); } - project_name->grab_focus(); + + project_name->call_deferred("grab_focus"); create_dir->hide(); status_btn->hide(); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 6f9454be2c..11c7e07b6a 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -2665,18 +2665,14 @@ TreeItem *PropertyEditor::get_parent_node(String p_path, HashMap<String, TreeIte item->set_editable(1, false); item->set_selectable(1, subsection_selectable); - if (use_folding || folding_behaviour != FB_UNDEFINED) { // Even if you disabled folding (expand all by default), you still can collapse all manually. + if (use_folding) { // if (!obj->editor_is_section_unfolded(p_path)) { updating_folding = true; - if (folding_behaviour == FB_COLLAPSEALL) - item->set_collapsed(true); - else if (folding_behaviour == FB_EXPANDALL || is_expandall_enabled) - item->set_collapsed(false); - else - item->set_collapsed(true); + item->set_collapsed(true); updating_folding = false; } item->set_metadata(0, p_path); + foldable_property_cache.push_back(p_path); } if (item->get_parent() == root) { @@ -2725,6 +2721,7 @@ void PropertyEditor::refresh() { void PropertyEditor::update_tree() { tree->clear(); + foldable_property_cache.clear(); if (!obj) return; @@ -3733,7 +3730,7 @@ void PropertyEditor::_item_edited() { _edit_set(name, item->get_text(1), refresh_all); } } break; - // math types + // math types case Variant::VECTOR3: { @@ -4212,29 +4209,29 @@ void PropertyEditor::set_subsection_selectable(bool p_selectable) { update_tree(); } -bool PropertyEditor::is_expand_all_properties_enabled() const { - - return (use_folding == false); -} - void PropertyEditor::set_use_folding(bool p_enable) { use_folding = p_enable; tree->set_hide_folding(false); } -void PropertyEditor::collapse_all_parent_nodes() { - - folding_behaviour = FB_COLLAPSEALL; +void PropertyEditor::collapse_all_folding() { + if (!obj) + return; + for (List<String>::Element *E = foldable_property_cache.front(); E; E = E->next()) { + obj->editor_set_section_unfold(E->get(), false); + } update_tree(); - folding_behaviour = FB_UNDEFINED; } -void PropertyEditor::expand_all_parent_nodes() { +void PropertyEditor::expand_all_folding() { - folding_behaviour = FB_EXPANDALL; + if (!obj) + return; + for (List<String>::Element *E = foldable_property_cache.front(); E; E = E->next()) { + obj->editor_set_section_unfold(E->get(), true); + } update_tree(); - folding_behaviour = FB_UNDEFINED; } PropertyEditor::PropertyEditor() { @@ -4309,8 +4306,6 @@ PropertyEditor::PropertyEditor() { subsection_selectable = false; property_selectable = false; show_type_icons = false; // maybe one day will return. - folding_behaviour = FB_UNDEFINED; - is_expandall_enabled = bool(EDITOR_DEF("interface/editor/expand_all_properties", true)); } PropertyEditor::~PropertyEditor() { diff --git a/editor/property_editor.h b/editor/property_editor.h index a337a05e46..bcabccc6fd 100644 --- a/editor/property_editor.h +++ b/editor/property_editor.h @@ -203,18 +203,9 @@ class PropertyEditor : public Control { bool hide_script; bool use_folding; bool property_selectable; - bool is_expandall_enabled; - bool updating_folding; - enum FOLDING_BEHAVIOUR { - FB_UNDEFINED, - FB_COLLAPSEALL, - FB_EXPANDALL, - FB_EXPANDALL_FORCE - }; - FOLDING_BEHAVIOUR folding_behaviour; - + List<String> foldable_property_cache; HashMap<String, String> pending; String selected_property; @@ -314,10 +305,8 @@ public: void set_use_folding(bool p_enable); - bool is_expand_all_properties_enabled() const; - - void collapse_all_parent_nodes(); - void expand_all_parent_nodes(); + void collapse_all_folding(); + void expand_all_folding(); PropertyEditor(); ~PropertyEditor(); }; diff --git a/editor/translations/README.md b/editor/translations/README.md index 351bc9e2d1..f30f4e61fb 100644 --- a/editor/translations/README.md +++ b/editor/translations/README.md @@ -16,5 +16,8 @@ Link if you missed it: https://hosted.weblate.org/projects/godot-engine/godot ## Adding new languages If you want to translate for a language which is not featured yet on Weblate, -open an issue on this repo to ask that the language is added, or contact -Akien/@akien-mga directly on IRC (#godotengine channel on Freenode). +you can add it (when logged in) by clicking the "Start new translation" +button at the bottom of the page. + +Alternatively, you can use this +[direct link](https://hosted.weblate.org/new-lang/godot-engine/godot/). diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp index 39ca754dc7..7a65996036 100644 --- a/modules/gdnative/gdnative/basis.cpp +++ b/modules/gdnative/gdnative/basis.cpp @@ -221,7 +221,7 @@ godot_basis GDAPI godot_basis_operator_add(const godot_basis *p_self, const godo return raw_dest; } -godot_basis GDAPI godot_basis_operator_substract(const godot_basis *p_self, const godot_basis *p_b) { +godot_basis GDAPI godot_basis_operator_subtract(const godot_basis *p_self, const godot_basis *p_b) { godot_basis raw_dest; Basis *dest = (Basis *)&raw_dest; const Basis *self = (const Basis *)p_self; diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quat.cpp index 2d012c069f..c308e5973d 100644 --- a/modules/gdnative/gdnative/quat.cpp +++ b/modules/gdnative/gdnative/quat.cpp @@ -181,7 +181,7 @@ godot_quat GDAPI godot_quat_operator_add(const godot_quat *p_self, const godot_q return raw_dest; } -godot_quat GDAPI godot_quat_operator_substract(const godot_quat *p_self, const godot_quat *p_b) { +godot_quat GDAPI godot_quat_operator_subtract(const godot_quat *p_self, const godot_quat *p_b) { godot_quat raw_dest; Quat *dest = (Quat *)&raw_dest; const Quat *self = (const Quat *)p_self; diff --git a/modules/gdnative/gdnative/vector2.cpp b/modules/gdnative/gdnative/vector2.cpp index 7a5b29e0c4..7be08929b1 100644 --- a/modules/gdnative/gdnative/vector2.cpp +++ b/modules/gdnative/gdnative/vector2.cpp @@ -207,7 +207,7 @@ godot_vector2 GDAPI godot_vector2_operator_add(const godot_vector2 *p_self, cons return raw_dest; } -godot_vector2 GDAPI godot_vector2_operator_substract(const godot_vector2 *p_self, const godot_vector2 *p_b) { +godot_vector2 GDAPI godot_vector2_operator_subtract(const godot_vector2 *p_self, const godot_vector2 *p_b) { godot_vector2 raw_dest; Vector2 *dest = (Vector2 *)&raw_dest; const Vector2 *self = (const Vector2 *)p_self; diff --git a/modules/gdnative/gdnative/vector3.cpp b/modules/gdnative/gdnative/vector3.cpp index 11ffb3320b..0027d236f2 100644 --- a/modules/gdnative/gdnative/vector3.cpp +++ b/modules/gdnative/gdnative/vector3.cpp @@ -224,7 +224,7 @@ godot_vector3 GDAPI godot_vector3_operator_add(const godot_vector3 *p_self, cons return raw_dest; } -godot_vector3 GDAPI godot_vector3_operator_substract(const godot_vector3 *p_self, const godot_vector3 *p_b) { +godot_vector3 GDAPI godot_vector3_operator_subtract(const godot_vector3 *p_self, const godot_vector3 *p_b) { godot_vector3 raw_dest; Vector3 *dest = (Vector3 *)&raw_dest; Vector3 *self = (Vector3 *)p_self; diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 488ed93206..31f3b0b77b 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -387,7 +387,7 @@ ] }, { - "name": "godot_vector2_operator_substract", + "name": "godot_vector2_operator_subtract", "return_type": "godot_vector2", "arguments": [ ["const godot_vector2 *", "p_self"], @@ -663,7 +663,7 @@ ] }, { - "name": "godot_quat_operator_substract", + "name": "godot_quat_operator_subtract", "return_type": "godot_quat", "arguments": [ ["const godot_quat *", "p_self"], @@ -907,7 +907,7 @@ ] }, { - "name": "godot_basis_operator_substract", + "name": "godot_basis_operator_subtract", "return_type": "godot_basis", "arguments": [ ["const godot_basis *", "p_self"], @@ -1142,7 +1142,7 @@ ] }, { - "name": "godot_vector3_operator_substract", + "name": "godot_vector3_operator_subtract", "return_type": "godot_vector3", "arguments": [ ["const godot_vector3 *", "p_self"], diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h index 49ca765a01..4898eab24c 100644 --- a/modules/gdnative/include/gdnative/basis.h +++ b/modules/gdnative/include/gdnative/basis.h @@ -111,7 +111,7 @@ godot_bool GDAPI godot_basis_operator_equal(const godot_basis *p_self, const god godot_basis GDAPI godot_basis_operator_add(const godot_basis *p_self, const godot_basis *p_b); -godot_basis GDAPI godot_basis_operator_substract(const godot_basis *p_self, const godot_basis *p_b); +godot_basis GDAPI godot_basis_operator_subtract(const godot_basis *p_self, const godot_basis *p_b); godot_basis GDAPI godot_basis_operator_multiply_vector(const godot_basis *p_self, const godot_basis *p_b); diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h index 6e69d43469..f7f5606428 100644 --- a/modules/gdnative/include/gdnative/gdnative.h +++ b/modules/gdnative/include/gdnative/gdnative.h @@ -115,8 +115,6 @@ typedef enum { GODOT_ERR_HELP, ///< user requested help!! GODOT_ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior. GODOT_ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames - GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though - GODOT_ERR_WTF = GODOT_ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above } godot_error; ////// bool diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h index acae6e3e90..2be9d8849d 100644 --- a/modules/gdnative/include/gdnative/quat.h +++ b/modules/gdnative/include/gdnative/quat.h @@ -98,7 +98,7 @@ godot_quat GDAPI godot_quat_operator_multiply(const godot_quat *p_self, const go godot_quat GDAPI godot_quat_operator_add(const godot_quat *p_self, const godot_quat *p_b); -godot_quat GDAPI godot_quat_operator_substract(const godot_quat *p_self, const godot_quat *p_b); +godot_quat GDAPI godot_quat_operator_subtract(const godot_quat *p_self, const godot_quat *p_b); godot_quat GDAPI godot_quat_operator_divide(const godot_quat *p_self, const godot_real p_b); diff --git a/modules/gdnative/include/gdnative/vector2.h b/modules/gdnative/include/gdnative/vector2.h index 07105abaf2..4d1117e3aa 100644 --- a/modules/gdnative/include/gdnative/vector2.h +++ b/modules/gdnative/include/gdnative/vector2.h @@ -106,7 +106,7 @@ godot_vector2 GDAPI godot_vector2_clamped(const godot_vector2 *p_self, const god godot_vector2 GDAPI godot_vector2_operator_add(const godot_vector2 *p_self, const godot_vector2 *p_b); -godot_vector2 GDAPI godot_vector2_operator_substract(const godot_vector2 *p_self, const godot_vector2 *p_b); +godot_vector2 GDAPI godot_vector2_operator_subtract(const godot_vector2 *p_self, const godot_vector2 *p_b); godot_vector2 GDAPI godot_vector2_operator_multiply_vector(const godot_vector2 *p_self, const godot_vector2 *p_b); diff --git a/modules/gdnative/include/gdnative/vector3.h b/modules/gdnative/include/gdnative/vector3.h index 3ed23778ec..135a13acc8 100644 --- a/modules/gdnative/include/gdnative/vector3.h +++ b/modules/gdnative/include/gdnative/vector3.h @@ -117,7 +117,7 @@ godot_vector3 GDAPI godot_vector3_reflect(const godot_vector3 *p_self, const god godot_vector3 GDAPI godot_vector3_operator_add(const godot_vector3 *p_self, const godot_vector3 *p_b); -godot_vector3 GDAPI godot_vector3_operator_substract(const godot_vector3 *p_self, const godot_vector3 *p_b); +godot_vector3 GDAPI godot_vector3_operator_subtract(const godot_vector3 *p_self, const godot_vector3 *p_b); godot_vector3 GDAPI godot_vector3_operator_multiply_vector(const godot_vector3 *p_self, const godot_vector3 *p_b); diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 34099bf528..365def75bc 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -103,16 +103,34 @@ static void actual_discoverer_handler() { Set<String> file_paths = get_gdnative_singletons(dir); + bool changed = false; + Array current_files = ProjectSettings::get_singleton()->get("gdnative/singletons"); Array files; files.resize(file_paths.size()); int i = 0; for (Set<String>::Element *E = file_paths.front(); E; i++, E = E->next()) { + if (!current_files.has(E->get())) { + changed = true; + } files.set(i, E->get()); } - ProjectSettings::get_singleton()->set("gdnative/singletons", files); + // Check for removed files + if (!changed) { + for (int i = 0; i < current_files.size(); i++) { + if (!file_paths.has(current_files[i])) { + changed = true; + break; + } + } + } - ProjectSettings::get_singleton()->save(); + if (changed) { + + ProjectSettings::get_singleton()->set("gdnative/singletons", files); + + ProjectSettings::get_singleton()->save(); + } } static GDNativeSingletonDiscover *discoverer = NULL; diff --git a/modules/mono/glue/cs_files/Error.cs b/modules/mono/glue/cs_files/Error.cs index 3f4a92603d..dee4b88f74 100644 --- a/modules/mono/glue/cs_files/Error.cs +++ b/modules/mono/glue/cs_files/Error.cs @@ -42,7 +42,6 @@ namespace Godot ERR_CYCLIC_LINK = 40, ERR_BUSY = 44, ERR_HELP = 46, - ERR_BUG = 47, - ERR_WTF = 49 + ERR_BUG = 47 } } diff --git a/modules/opus/audio_stream_opus.cpp b/modules/opus/audio_stream_opus.cpp index 06eab4c94d..5742102dae 100644 --- a/modules/opus/audio_stream_opus.cpp +++ b/modules/opus/audio_stream_opus.cpp @@ -62,7 +62,7 @@ int AudioStreamPlaybackOpus::_op_seek_func(void *_stream, opus_int64 _offset, in fa->seek_end(_offset); } break; default: { - ERR_PRINT("BUG, wtf was whence set to?\n"); + ERR_PRINT("Opus seek function failure: Unexpected value in _whence\n"); } } int ret = fa->eof_reached() ? -1 : 0; diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp index 072f18b990..ac436c3c26 100644 --- a/modules/squish/image_compress_squish.cpp +++ b/modules/squish/image_compress_squish.cpp @@ -64,7 +64,7 @@ void image_decompress_squish(Image *p_image) { } else if (p_image->get_format() == Image::FORMAT_RGTC_RG) { squish_flags = squish::kBc5; } else { - print_line("wtf askd to decompress.. " + itos(p_image->get_format())); + print_line("Can't decompress unknown format: " + itos(p_image->get_format())); ERR_FAIL_COND(true); return; } diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index 49a4db237a..c88662454c 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -47,6 +47,11 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f f->close(); + // Re-implementation of tinyexr's LoadEXRFromMemory using Godot types to store the Image data + // and Godot's error codes. + // When debugging after updating the thirdparty library, check that we're still in sync with + // their API usage in LoadEXRFromMemory. + EXRVersion exr_version; EXRImage exr_image; EXRHeader exr_header; @@ -68,6 +73,13 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f return ERR_FILE_CORRUPT; } + // Read HALF channel as FLOAT. (GH-13490) + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } + InitEXRImage(&exr_image); ret = LoadEXRImageFromMemory(&exr_image, &exr_header, w.ptr(), src_image_len, &err); if (ret != TINYEXR_SUCCESS) { @@ -95,23 +107,25 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f } if (idxR == -1) { - ERR_PRINT("R channel not found"); + ERR_PRINT("TinyEXR: R channel not found."); // @todo { free exr_image } return ERR_FILE_CORRUPT; } if (idxG == -1) { - ERR_PRINT("G channel not found\n") + ERR_PRINT("TinyEXR: G channel not found.") // @todo { free exr_image } return ERR_FILE_CORRUPT; } if (idxB == -1) { - ERR_PRINT("B channel not found\n") + ERR_PRINT("TinyEXR: B channel not found.") // @todo { free exr_image } return ERR_FILE_CORRUPT; } + // EXR image data loaded, now parse it into Godot-friendly image data + PoolVector<uint8_t> imgdata; Image::Format format; @@ -126,7 +140,6 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f } { - PoolVector<uint8_t>::Write wd = imgdata.write(); uint16_t *iw = (uint16_t *)wd.ptr(); @@ -151,11 +164,13 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f } } - print_line("EXR w: " + itos(exr_image.width) + " h:" + itos(exr_image.height) + " format " + Image::get_format_name(format)); p_image->create(exr_image.width, exr_image.height, false, format, imgdata); w = PoolVector<uint8_t>::Write(); + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return OK; } diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index b6ce10381d..ecdca7eb42 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -53,7 +53,7 @@ void register_visual_script_types() { ClassDB::register_class<VisualScript>(); ClassDB::register_virtual_class<VisualScriptNode>(); - ClassDB::register_virtual_class<VisualScriptFunctionState>(); + ClassDB::register_class<VisualScriptFunctionState>(); ClassDB::register_class<VisualScriptFunction>(); ClassDB::register_class<VisualScriptOperator>(); ClassDB::register_class<VisualScriptVariableSet>(); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 26f2d687d8..bb6c32e9e0 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2289,7 +2289,7 @@ void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p binds.push_back(p_binds[i]); } binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing - p_obj->connect(p_signal, this, "_signal_callback", binds); + p_obj->connect(p_signal, this, "_signal_callback", binds, CONNECT_ONESHOT); } bool VisualScriptFunctionState::is_valid() const { diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 95ad7256b3..5f98951bec 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -390,7 +390,7 @@ PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const { { Variant::NIL, Variant::NIL }, //OP_GREATER_EQUAL, //mathematic { Variant::NIL, Variant::NIL }, //OP_ADD, - { Variant::NIL, Variant::NIL }, //OP_SUBSTRACT, + { Variant::NIL, Variant::NIL }, //OP_SUBTRACT, { Variant::NIL, Variant::NIL }, //OP_MULTIPLY, { Variant::NIL, Variant::NIL }, //OP_DIVIDE, { Variant::NIL, Variant::NIL }, //OP_NEGATE, @@ -433,7 +433,7 @@ PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const { Variant::BOOL, //OP_GREATER_EQUAL, //mathematic Variant::NIL, //OP_ADD, - Variant::NIL, //OP_SUBSTRACT, + Variant::NIL, //OP_SUBTRACT, Variant::NIL, //OP_MULTIPLY, Variant::NIL, //OP_DIVIDE, Variant::NIL, //OP_NEGATE, @@ -474,7 +474,7 @@ static const char *op_names[] = { "GreaterEq", //OP_GREATER_EQUAL, //mathematic "Add", //OP_ADD, - "Subtract", //OP_SUBSTRACT, + "Subtract", //OP_SUBTRACT, "Multiply", //OP_MULTIPLY, "Divide", //OP_DIVIDE, "Negate", //OP_NEGATE, @@ -514,7 +514,7 @@ String VisualScriptOperator::get_text() const { L"A \u2265 B", //OP_GREATER_EQUAL, //mathematic L"A + B", //OP_ADD, - L"A - B", //OP_SUBSTRACT, + L"A - B", //OP_SUBTRACT, L"A x B", //OP_MULTIPLY, L"A \u00F7 B", //OP_DIVIDE, L"\u00AC A", //OP_NEGATE, diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 9fb6fa8197..03c0bfb1c2 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -64,7 +64,7 @@ int AudioStreamPlaybackOGGVorbis::_ov_seek_func(void *_f, ogg_int64_t offs, int fa->seek_end(offs); } else { - ERR_PRINT("BUG, wtf was whence set to?\n"); + ERR_PRINT("Vorbis seek function failure: Unexpected value in _whence\n"); } int ret = fa->eof_reached() ? -1 : 0; //printf("returning %i\n",ret); diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 11c49fbb50..4a44d1c5f9 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -31,7 +31,7 @@ android { disable 'MissingTranslation' } - compileSdkVersion 24 + compileSdkVersion 26 buildToolsVersion "26.0.1" useLibrary 'org.apache.http.legacy' diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 41dcba5c2c..4daf06142d 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -970,7 +970,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC boolean indeterminate; switch (newState) { case IDownloaderClient.STATE_IDLE: - Log.d("GODOT", "STATE IDLE"); + Log.d("GODOT", "DOWNLOAD STATE IDLE"); // STATE_IDLE means the service is listening, so it's // safe to start making calls via mRemoteService. paused = false; @@ -978,13 +978,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC break; case IDownloaderClient.STATE_CONNECTING: case IDownloaderClient.STATE_FETCHING_URL: - Log.d("GODOT", "STATE CONNECTION / FETCHING URL"); + Log.d("GODOT", "DOWNLOAD STATE CONNECTION / FETCHING URL"); showDashboard = true; paused = false; indeterminate = true; break; case IDownloaderClient.STATE_DOWNLOADING: - Log.d("GODOT", "STATE DOWNLOADING"); + Log.d("GODOT", "DOWNLOAD STATE DOWNLOADING"); paused = false; showDashboard = true; indeterminate = false; @@ -994,14 +994,14 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC case IDownloaderClient.STATE_FAILED: case IDownloaderClient.STATE_FAILED_FETCHING_URL: case IDownloaderClient.STATE_FAILED_UNLICENSED: - Log.d("GODOT", "MANY TYPES OF FAILING"); + Log.d("GODOT", "DOWNLOAD STATE: FAILED, CANCELLED, UNLICENSED OR FAILED TO FETCH URL"); paused = true; showDashboard = false; indeterminate = false; break; case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION: case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION: - Log.d("GODOT", "PAUSED FOR SOME STUPID REASON"); + Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY MISSING CELLULAR PERMISSION"); showDashboard = false; paused = true; indeterminate = false; @@ -1009,18 +1009,18 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC break; case IDownloaderClient.STATE_PAUSED_BY_REQUEST: - Log.d("GODOT", "PAUSED BY STUPID USER"); + Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY USER"); paused = true; indeterminate = false; break; case IDownloaderClient.STATE_PAUSED_ROAMING: case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE: - Log.d("GODOT", "PAUSED BY ROAMING WTF!?"); + Log.d("GODOT", "DOWNLOAD STATE: PAUSED BY ROAMING OR SDCARD UNAVAILABLE"); paused = true; indeterminate = false; break; case IDownloaderClient.STATE_COMPLETED: - Log.d("GODOT", "COMPLETED"); + Log.d("GODOT", "DOWNLOAD STATE: COMPLETED"); showDashboard = false; paused = false; indeterminate = false; @@ -1028,7 +1028,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC initializeGodot(); return; default: - Log.d("GODOT", "DEFAULT ????"); + Log.d("GODOT", "DOWNLOAD STATE: DEFAULT"); paused = true; indeterminate = true; showDashboard = true; diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 9a740a7bea..6543ca7dd2 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -43,7 +43,6 @@ #include "servers/visual_server.h" #include <ApplicationServices/ApplicationServices.h> -//bitch #undef CursorShape /** @author Juan Linietsky <reduzio@gmail.com> diff --git a/platform/server/os_server.h b/platform/server/os_server.h index 03f7c2a6c8..40b10c019f 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -38,7 +38,6 @@ #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" -//bitch #undef CursorShape /** @author Juan Linietsky <reduzio@gmail.com> diff --git a/platform/windows/detect.py b/platform/windows/detect.py index fbb02c9d1b..890decf962 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -64,6 +64,10 @@ def get_opts(): return [ ('mingw_prefix_32', 'MinGW prefix (Win32)', mingw32), ('mingw_prefix_64', 'MinGW prefix (Win64)', mingw64), + # Targeted Windows version: 7 (and later), minimum supported version + # XP support dropped after EOL due to missing API for IPv6 and other issues + # Vista support dropped after EOL due to GH-10243 + ('target_win_version', 'Targeted Windows version, >= 0x0601 (Windows 7)', '0x0601'), EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')), ] @@ -97,11 +101,6 @@ def configure(env): env.Append(CPPPATH=['#platform/windows']) - # Targeted Windows version: 7 (and later), minimum supported version - # XP support dropped after EOL due to missing API for IPv6 and other issues - # Vista support dropped after EOL due to GH-10243 - winver = "0x0601" - if (os.name == "nt" and os.getenv("VCINSTALLDIR")): # MSVC env['ENV']['TMP'] = os.environ['TMP'] @@ -175,7 +174,7 @@ def configure(env): env.Append(CCFLAGS=['/DWASAPI_ENABLED']) env.Append(CCFLAGS=['/DTYPED_METHOD_BIND']) env.Append(CCFLAGS=['/DWIN32']) - env.Append(CCFLAGS=['/DWINVER=%s' % winver, '/D_WIN32_WINNT=%s' % winver]) + env.Append(CCFLAGS=['/DWINVER=%s' % env['target_win_version'], '/D_WIN32_WINNT=%s' % env['target_win_version']]) if env["bits"] == "64": env.Append(CCFLAGS=['/D_WIN64']) diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 9bcbb6ddb6..79a760f055 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -73,22 +73,17 @@ static String format_error_message(DWORD id) { LPWSTR messageBuffer = NULL; size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); + NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); - String msg = "Error "+itos(id)+": "+String(messageBuffer,size); + String msg = "Error " + itos(id) + ": " + String(messageBuffer, size); LocalFree(messageBuffer); return msg; - } - - extern HINSTANCE godot_hinstance; - - void RedirectIOToConsole() { int hConHandle; @@ -228,7 +223,17 @@ bool OS_Windows::can_draw() const { #define SIGNATURE_MASK 0xFFFFFF00 #define IsPenEvent(dw) (((dw)&SIGNATURE_MASK) == MI_WP_SIGNATURE) -void OS_Windows::_touch_event(bool p_pressed, int p_x, int p_y, int idx) { +void OS_Windows::_touch_event(bool p_pressed, float p_x, float p_y, int idx) { + + // Defensive + if (touch_state.has(idx) == p_pressed) + return; + + if (p_pressed) { + touch_state.insert(idx, Vector2(p_x, p_y)); + } else { + touch_state.erase(idx); + } Ref<InputEventScreenTouch> event; event.instance(); @@ -241,7 +246,17 @@ void OS_Windows::_touch_event(bool p_pressed, int p_x, int p_y, int idx) { } }; -void OS_Windows::_drag_event(int p_x, int p_y, int idx) { +void OS_Windows::_drag_event(float p_x, float p_y, int idx) { + + Map<int, Vector2>::Element *curr = touch_state.find(idx); + // Defensive + if (!curr) + return; + + if (curr->get() == Vector2(p_x, p_y)) + return; + + curr->get() = Vector2(p_x, p_y); Ref<InputEventScreenDrag> event; event.instance(); @@ -271,6 +286,13 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) { ReleaseCapture(); } + + // Release every touch to avoid sticky points + for (Map<int, Vector2>::Element *E = touch_state.front(); E; E = E->next()) { + _touch_event(false, E->get().x, E->get().y, E->key()); + } + touch_state.clear(); + break; } case WM_ACTIVATE: // Watch For Window Activate Message @@ -674,7 +696,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) print_line("input lang change"); } break; -#if WINVER >= 0x0601 // for windows 7 case WM_TOUCH: { BOOL bHandled = FALSE; @@ -687,10 +708,10 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) //do something with each touch input entry if (ti.dwFlags & TOUCHEVENTF_MOVE) { - _drag_event(ti.x / 100, ti.y / 100, ti.dwID); + _drag_event(ti.x / 100.0f, ti.y / 100.0f, ti.dwID); } else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) { - _touch_event(ti.dwFlags & TOUCHEVENTF_DOWN != 0, ti.x / 100, ti.y / 100, ti.dwID); + _touch_event(ti.dwFlags & TOUCHEVENTF_DOWN, ti.x / 100.0f, ti.y / 100.0f, ti.dwID); }; } bHandled = TRUE; @@ -708,7 +729,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } break; -#endif case WM_DEVICECHANGE: { joypad->probe_joypads(); @@ -1092,7 +1112,7 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int tme.dwHoverTime = HOVER_DEFAULT; TrackMouseEvent(&tme); - //RegisterTouchWindow(hWnd, 0); // Windows 7 + RegisterTouchWindow(hWnd, 0); _ensure_user_data_dir(); @@ -1206,6 +1226,7 @@ void OS_Windows::finalize() { memdelete(joypad); memdelete(input); + touch_state.clear(); visual_server->finish(); memdelete(visual_server); @@ -1608,17 +1629,23 @@ void OS_Windows::_update_window_style(bool repaint) { Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { + typedef DLL_DIRECTORY_COOKIE(WINAPI * PAddDllDirectory)(PCWSTR); + typedef BOOL(WINAPI * PRemoveDllDirectory)(DLL_DIRECTORY_COOKIE); + + PAddDllDirectory add_dll_directory = (PAddDllDirectory)GetProcAddress(GetModuleHandle("kernel32.dll"), "AddDllDirectory"); + PRemoveDllDirectory remove_dll_directory = (PRemoveDllDirectory)GetProcAddress(GetModuleHandle("kernel32.dll"), "RemoveDllDirectory"); + bool has_dll_directory_api = ((add_dll_directory != NULL) && (remove_dll_directory != NULL)); DLL_DIRECTORY_COOKIE cookie; - if (p_also_set_library_path) { - cookie = AddDllDirectory(p_path.get_base_dir().c_str()); + if (p_also_set_library_path && has_dll_directory_api) { + cookie = add_dll_directory(p_path.get_base_dir().c_str()); } - p_library_handle = (void *)LoadLibraryExW(p_path.c_str(), NULL, p_also_set_library_path ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0); + p_library_handle = (void *)LoadLibraryExW(p_path.c_str(), NULL, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0); - if (p_also_set_library_path) { - RemoveDllDirectory(cookie); + if (p_also_set_library_path && has_dll_directory_api) { + remove_dll_directory(cookie); } if (!p_library_handle) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index e98f8277df..af1ccd4446 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -117,6 +117,7 @@ class OS_Windows : public OS { InputDefault *input; JoypadWindows *joypad; + Map<int, Vector2> touch_state; PowerWindows *power_manager; @@ -132,8 +133,8 @@ class OS_Windows : public OS { CrashHandler crash_handler; - void _drag_event(int p_x, int p_y, int idx); - void _touch_event(bool p_pressed, int p_x, int p_y, int idx); + void _drag_event(float p_x, float p_y, int idx); + void _touch_event(bool p_pressed, float p_x, float p_y, int idx); void _update_window_style(bool repaint = true); @@ -212,7 +213,7 @@ public: virtual void set_borderless_window(int p_borderless); virtual bool get_borderless_window(); - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle,bool p_also_set_library_path=false); + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); virtual Error close_dynamic_library(void *p_library_handle); virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); diff --git a/platform/windows/stream_peer_winsock.cpp b/platform/windows/stream_peer_winsock.cpp index a9d9cb9373..8b83215325 100644 --- a/platform/windows/stream_peer_winsock.cpp +++ b/platform/windows/stream_peer_winsock.cpp @@ -141,7 +141,7 @@ Error StreamPeerWinsock::write(const uint8_t *p_data, int p_bytes, int &r_sent, if (WSAGetLastError() != WSAEWOULDBLOCK) { - perror("shit?"); + perror("Nothing sent"); disconnect_from_host(); ERR_PRINT("Server disconnected!\n"); return FAILED; @@ -197,7 +197,7 @@ Error StreamPeerWinsock::read(uint8_t *p_buffer, int p_bytes, int &r_received, b if (WSAGetLastError() != WSAEWOULDBLOCK) { - perror("shit?"); + perror("Nothing read"); disconnect_from_host(); ERR_PRINT("Server disconnected!\n"); return FAILED; diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 3d07851c4f..d7dbe71da4 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -55,6 +55,7 @@ def get_opts(): BoolVariable('pulseaudio', 'Detect & use pulseaudio', True), BoolVariable('udev', 'Use udev for gamepad connection callbacks', False), EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')), + BoolVariable('touch', 'Enable touch events', True), ] @@ -141,6 +142,14 @@ def configure(env): env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xrandr --cflags --libs') + if (env['touch']): + x11_error = os.system("pkg-config xi --modversion > /dev/null ") + if (x11_error): + print("xi not found.. cannot build with touch. Aborting.") + sys.exit(255) + env.ParseConfig('pkg-config xi --cflags --libs') + env.Append(CPPFLAGS=['-DTOUCH_ENABLED']) + # FIXME: Check for existence of the libs before parsing their flags with pkg-config if not env['builtin_openssl']: diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index d1aa129e77..bf63921b06 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -178,6 +178,50 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au } } +#ifdef TOUCH_ENABLED + if (!XQueryExtension(x11_display, "XInputExtension", &touch.opcode, &event_base, &error_base)) { + fprintf(stderr, "XInput extension not available"); + } else { + // 2.2 is the first release with multitouch + int xi_major = 2; + int xi_minor = 2; + if (XIQueryVersion(x11_display, &xi_major, &xi_minor) != Success) { + fprintf(stderr, "XInput 2.2 not available (server supports %d.%d)\n", xi_major, xi_minor); + touch.opcode = 0; + } else { + int dev_count; + XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count); + + for (int i = 0; i < dev_count; i++) { + XIDeviceInfo *dev = &info[i]; + if (!dev->enabled) + continue; + /*if (dev->use != XIMasterPointer) + continue;*/ + + bool direct_touch = false; + for (int j = 0; j < dev->num_classes; j++) { + if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) { + direct_touch = true; + printf("%d) %d %s\n", i, dev->attachment, dev->name); + break; + } + } + if (direct_touch) { + touch.devices.push_back(dev->deviceid); + fprintf(stderr, "Using touch device: %s\n", dev->name); + } + } + + XIFreeDeviceInfo(info); + + if (!touch.devices.size()) { + fprintf(stderr, "No suitable touch device found\n"); + } + } + } +#endif + xim = XOpenIM(x11_display, NULL, NULL, NULL); if (xim == NULL) { @@ -308,6 +352,32 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr); +#ifdef TOUCH_ENABLED + if (touch.devices.size()) { + + // Must be alive after this block + static unsigned char mask_data[XIMaskLen(XI_LASTEVENT)] = {}; + + touch.event_mask.deviceid = XIAllMasterDevices; + touch.event_mask.mask_len = sizeof(mask_data); + touch.event_mask.mask = mask_data; + + XISetMask(touch.event_mask.mask, XI_TouchBegin); + XISetMask(touch.event_mask.mask, XI_TouchUpdate); + XISetMask(touch.event_mask.mask, XI_TouchEnd); + XISetMask(touch.event_mask.mask, XI_TouchOwnership); + + XISelectEvents(x11_display, x11_window, &touch.event_mask, 1); + + XIClearMask(touch.event_mask.mask, XI_TouchOwnership); + + // Grab touch devices to avoid OS gesture interference + for (int i = 0; i < touch.devices.size(); ++i) { + XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask); + } + } +#endif + /* set the titlebar name */ XStoreName(x11_display, x11_window, "Godot"); @@ -487,6 +557,10 @@ void OS_X11::finalize() { #ifdef JOYDEV_ENABLED memdelete(joypad); #endif +#ifdef TOUCH_ENABLED + touch.devices.clear(); + touch.state.clear(); +#endif memdelete(input); visual_server->finish(); @@ -1435,6 +1509,69 @@ void OS_X11::process_xevents() { continue; } +#ifdef TOUCH_ENABLED + if (XGetEventData(x11_display, &event.xcookie)) { + + if (event.xcookie.extension == touch.opcode) { + + XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data; + int index = event_data->detail; + Vector2 pos = Vector2(event_data->event_x, event_data->event_y); + + switch (event_data->evtype) { + + case XI_TouchBegin: // Fall-through + XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch); + + case XI_TouchEnd: { + + bool is_begin = event_data->evtype == XI_TouchBegin; + + Ref<InputEventScreenTouch> st; + st.instance(); + st->set_index(index); + st->set_position(pos); + st->set_pressed(is_begin); + + if (is_begin) { + if (touch.state.has(index)) // Defensive + break; + touch.state[index] = pos; + input->parse_input_event(st); + } else { + if (!touch.state.has(index)) // Defensive + break; + touch.state.erase(index); + input->parse_input_event(st); + } + } break; + + case XI_TouchUpdate: { + + Map<int, Vector2>::Element *curr_pos_elem = touch.state.find(index); + if (!curr_pos_elem) { // Defensive + break; + } + + if (curr_pos_elem->value() != pos) { + + Ref<InputEventScreenDrag> sd; + sd.instance(); + sd->set_index(index); + sd->set_position(pos); + sd->set_relative(pos - curr_pos_elem->value()); + input->parse_input_event(sd); + + curr_pos_elem->value() = pos; + } + } break; + } + } + + XFreeEventData(x11_display, &event.xcookie); + } +#endif + switch (event.type) { case Expose: Main::force_redraw(); @@ -1477,6 +1614,12 @@ void OS_X11::process_xevents() { ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime); } +#ifdef TOUCH_ENABLED + // Grab touch devices to avoid OS gesture interference + for (int i = 0; i < touch.devices.size(); ++i) { + XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask); + } +#endif if (xic) { XSetICFocus(xic); } @@ -1493,6 +1636,23 @@ void OS_X11::process_xevents() { } XUngrabPointer(x11_display, CurrentTime); } +#ifdef TOUCH_ENABLED + // Ungrab touch devices so input works as usual while we are unfocused + for (int i = 0; i < touch.devices.size(); ++i) { + XIUngrabDevice(x11_display, touch.devices[i], CurrentTime); + } + + // Release every pointer to avoid sticky points + for (Map<int, Vector2>::Element *E = touch.state.front(); E; E = E->next()) { + + Ref<InputEventScreenTouch> st; + st.instance(); + st->set_index(E->key()); + st->set_position(E->get()); + input->parse_input_event(st); + } + touch.state.clear(); +#endif if (xic) { XUnsetICFocus(xic); } diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index a74e6ee5f3..84dff2e089 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -48,6 +48,9 @@ #include <X11/Xlib.h> #include <X11/extensions/Xrandr.h> #include <X11/keysym.h> +#ifdef TOUCH_ENABLED +#include <X11/extensions/XInput2.h> +#endif // Hints for X11 fullscreen typedef struct { @@ -117,6 +120,14 @@ class OS_X11 : public OS_Unix { Point2i last_click_pos; uint64_t last_click_ms; uint32_t last_button_state; +#ifdef TOUCH_ENABLED + struct { + int opcode; + Vector<int> devices; + XIEventMask event_mask; + Map<int, Vector2> state; + } touch; +#endif unsigned int get_mouse_button_state(unsigned int p_x11_state); void get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state); diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 66abe1baa8..9a3debbe90 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -184,6 +184,11 @@ RID CanvasItemMaterial::get_shader_rid() const { return shader_map[current_key].shader; } +Shader::Mode CanvasItemMaterial::get_shader_mode() const { + + return Shader::MODE_CANVAS_ITEM; +} + void CanvasItemMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index c877a94755..ccbb528d6f 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -123,6 +123,8 @@ public: RID get_shader_rid() const; + virtual Shader::Mode get_shader_mode() const; + CanvasItemMaterial(); virtual ~CanvasItemMaterial(); }; diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index aee5d89150..7d53557216 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -291,7 +291,7 @@ void Particles2D::_notification(int p_what) { texture_rid = texture->get_rid(); RID normal_rid; if (normal_map.is_valid()) - normal_rid = texture->get_rid(); + normal_rid = normal_map->get_rid(); VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid, h_frames, v_frames); diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 2a032f5d96..f8685a7b7c 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -869,6 +869,7 @@ void ParticlesMaterial::_update_shader() { } //scale by scale code += " float base_scale = mix(scale*tex_scale,1.0,scale_random*scale_rand);\n"; + code += " if (base_scale==0.0) base_scale=0.000001;\n"; if (trail_size_modifier.is_valid()) { code += " if (trail_divisor > 1) { base_scale *= textureLod(trail_size_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0).r; } \n"; } @@ -1360,6 +1361,11 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { } } +Shader::Mode ParticlesMaterial::get_shader_mode() const { + + return Shader::MODE_PARTICLES; +} + void ParticlesMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread); diff --git a/scene/3d/particles.h b/scene/3d/particles.h index 30080360bb..5b8121e937 100644 --- a/scene/3d/particles.h +++ b/scene/3d/particles.h @@ -390,6 +390,8 @@ public: RID get_shader_rid() const; + virtual Shader::Mode get_shader_mode() const; + ParticlesMaterial(); ~ParticlesMaterial(); }; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 206f3ccca2..f3e750d0da 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1324,7 +1324,9 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_root"), &AnimationPlayer::get_root); ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_position"), &AnimationPlayer::get_current_animation_position); + ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance); + ClassDB::bind_method(D_METHOD("get_anim_position"), &AnimationPlayer::get_current_animation_position); + ClassDB::bind_method(D_METHOD("get_anim_length"), &AnimationPlayer::get_current_animation_length); ClassDB::bind_method(D_METHOD("find_animation", "animation"), &AnimationPlayer::find_animation); @@ -1333,15 +1335,15 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation_process_mode", "mode"), &AnimationPlayer::set_animation_process_mode); ClassDB::bind_method(D_METHOD("get_animation_process_mode"), &AnimationPlayer::get_animation_process_mode); - ClassDB::bind_method(D_METHOD("get_current_animation_position"), &AnimationPlayer::get_current_animation_position); - ClassDB::bind_method(D_METHOD("get_current_animation_length"), &AnimationPlayer::get_current_animation_length); - - ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance); - ADD_GROUP("Playback Options", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root", "get_root"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "autoplay"), "set_autoplay", "get_autoplay"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_anim"), "set_current_anim", "get_current_anim"); ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index dbd7c1bbc0..7a0593bc87 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -664,11 +664,16 @@ ColorPicker *ColorPickerButton::get_picker() { return picker; } +PopupPanel *ColorPickerButton::get_popup() { + return popup; +} + void ColorPickerButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPickerButton::set_pick_color); ClassDB::bind_method(D_METHOD("get_pick_color"), &ColorPickerButton::get_pick_color); ClassDB::bind_method(D_METHOD("get_picker"), &ColorPickerButton::get_picker); + ClassDB::bind_method(D_METHOD("get_popup"), &ColorPickerButton::get_popup); ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPickerButton::set_edit_alpha); ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPickerButton::is_editing_alpha); ClassDB::bind_method(D_METHOD("_color_changed"), &ColorPickerButton::_color_changed); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 7de67a707c..c02cdc8608 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -130,6 +130,7 @@ public: bool is_editing_alpha() const; ColorPicker *get_picker(); + PopupPanel *get_popup(); ColorPickerButton(); }; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index f3711b86b6..4ee6f93c9a 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -202,10 +202,10 @@ void PopupMenu::_activate_submenu(int over) { void PopupMenu::_submenu_timeout() { - if (mouse_over == submenu_over) { + if (mouse_over == submenu_over) _activate_submenu(mouse_over); - submenu_over = -1; - } + + submenu_over = -1; } void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 124c268c8a..9cf4c105b4 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -793,6 +793,17 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { selection.click = item; selection.click_char = line; + + // Erase previous selection. + if (selection.active) { + selection.from = NULL; + selection.from_char = NULL; + selection.to = NULL; + selection.to_char = NULL; + selection.active = false; + + update(); + } } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 6fa73e4b58..396186d487 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -594,6 +594,12 @@ void TextEdit::_notification(int p_what) { int xmargin_end = cache.size.width - cache.style_normal->get_margin(MARGIN_RIGHT); //let's do it easy for now: cache.style_normal->draw(ci, Rect2(Point2(), cache.size)); + float readonly_alpha = 1.0; // used to set the input text color when in read-only mode + if (readonly) { + cache.style_readonly->draw(ci, Rect2(Point2(), cache.size)); + readonly_alpha = .5; + draw_caret = false; + } if (has_focus()) cache.style_focus->draw(ci, Rect2(Point2(), cache.size)); @@ -604,6 +610,8 @@ void TextEdit::_notification(int p_what) { int tab_w = cache.font->get_char_size(' ').width * indent_size; Color color = cache.font_color; + color.a *= readonly_alpha; + int in_region = -1; if (syntax_coloring) { @@ -823,10 +831,16 @@ void TextEdit::_notification(int p_what) { int char_margin = xmargin_beg - cursor.x_ofs; int char_ofs = 0; - int ofs_y = (i * get_row_height() + cache.line_spacing / 2); - if (smooth_scroll_enabled) { - ofs_y -= (v_scroll->get_value() - get_line_scroll_pos()) * get_row_height(); + + int ofs_readonly = 0; + int ofs_x = 0; + if (readonly) { + ofs_readonly = cache.style_readonly->get_offset().y / 2; + ofs_x = cache.style_readonly->get_offset().x / 2; } + int ofs_y = (i * get_row_height() + cache.line_spacing / 2) + ofs_readonly; + if (smooth_scroll_enabled) + ofs_y -= ((v_scroll->get_value() - get_line_scroll_pos()) * get_row_height()); bool prev_is_char = false; bool prev_is_number = false; @@ -852,27 +866,27 @@ void TextEdit::_notification(int p_what) { if (text.is_marked(line)) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color); } if (str.length() == 0) { // draw line background if empty as we won't loop at at all if (line == cursor.line && highlight_current_line) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_end, get_row_height()), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, get_row_height()), cache.current_line_color); } // give visual indication of empty selected line if (selection.active && line >= selection.from_line && line <= selection.to_line) { int char_w = cache.font->get_char_size(' ').width; - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y, char_w, get_row_height()), cache.selection_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, get_row_height()), cache.selection_color); } } if (text.is_breakpoint(line) && !draw_breakpoint_gutter) { #ifdef TOOLS_ENABLED - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color); #else - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color); #endif } @@ -895,11 +909,11 @@ void TextEdit::_notification(int p_what) { if (is_folded(line)) { int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2; int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2; - cache.folded_icon->draw(ci, Point2(gutter_left + xofs, ofs_y + yofs), Color(0.8f, 0.8f, 0.8f, 0.8f)); + cache.folded_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), Color(0.8f, 0.8f, 0.8f, 0.8f)); } else if (can_fold(line)) { int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3; int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2; - cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs, ofs_y + yofs), Color(0.8f, 0.8f, 0.8f, 0.8f)); + cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), Color(0.8f, 0.8f, 0.8f, 0.8f)); } } @@ -909,7 +923,7 @@ void TextEdit::_notification(int p_what) { fc = line_num_padding + fc; } - cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width, ofs_y + cache.font->get_ascent()), fc, cache.line_number_color); + cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, ofs_y + cache.font->get_ascent()), fc, cache.line_number_color); } //loop through charcters in one line for (int j = 0; j < str.length(); j++) { @@ -924,6 +938,7 @@ void TextEdit::_notification(int p_what) { if (syntax_coloring && deregion == 0) { color = cache.font_color; //reset + color.a *= readonly_alpha; //find keyword bool is_char = _is_text_char(str[j]); bool is_symbol = _is_symbol(str[j]); @@ -1107,7 +1122,7 @@ void TextEdit::_notification(int p_what) { if (line == cursor.line && highlight_current_line) { // if its the first char draw behind line numbers if (j == 0) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, (char_ofs + char_margin), get_row_height()), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, (char_ofs + char_margin + ofs_x), get_row_height()), cache.current_line_color); } // if its the last char draw to end of the line if (j == str.length() - 1) { @@ -1115,24 +1130,24 @@ void TextEdit::_notification(int p_what) { } // actual text if (!in_selection) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color); } } if (in_selection) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.selection_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.selection_color); } if (in_search_result) { Color border_color = (line == search_result_line && j >= search_result_col && j < search_result_col + search_text.length()) ? cache.font_color : cache.search_result_border_color; - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, 1)), border_color); - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y + get_row_height() - 1), Size2i(char_w, 1)), border_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, 1)), border_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y + get_row_height() - 1), Size2i(char_w, 1)), border_color); if (j == search_text_col) - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(1, get_row_height())), border_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(1, get_row_height())), border_color); if (j == search_text_col + search_text.length() - 1) - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w - 1, ofs_y), Size2i(1, get_row_height())), border_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color); } if (highlight_all_occurrences) { @@ -1151,7 +1166,7 @@ void TextEdit::_notification(int p_what) { } if (in_highlighted_word) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.word_highlighted_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.word_highlighted_color); } } } @@ -1162,7 +1177,7 @@ void TextEdit::_notification(int p_what) { if (brace_open_mismatch) color = cache.brace_mismatch_color; - cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + cache.font->draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); } if ( @@ -1171,13 +1186,13 @@ void TextEdit::_notification(int p_what) { if (brace_close_mismatch) color = cache.brace_mismatch_color; - cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + cache.font->draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); } } if (cursor.column == j && cursor.line == line) { - cursor_pos = Point2i(char_ofs + char_margin, ofs_y); + cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y); if (insert_mode) { cursor_pos.y += (get_row_height() - 3); @@ -1204,7 +1219,7 @@ void TextEdit::_notification(int p_what) { VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color); } - cache.font->draw_char(ci, Point2(char_ofs + char_margin, ofs_y + ascent), cchar, next, color); + cache.font->draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color); char_ofs += im_char_width; ofs++; @@ -1227,18 +1242,19 @@ void TextEdit::_notification(int p_what) { color = cache.caret_background_color; } else if (!syntax_coloring && block_caret) { color = cache.font_color; + color.a *= readonly_alpha; } if (str[j] >= 32) { - int w = cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + int w = cache.font->draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); if (underlined) { - draw_rect(Rect2(char_ofs + char_margin, ofs_y + ascent + 2, w, 1), in_selection && override_selected_font_color ? cache.font_selected_color : color); + draw_rect(Rect2(char_ofs + char_margin + ofs_x, ofs_y + ascent + 2, w, 1), in_selection && override_selected_font_color ? cache.font_selected_color : color); } } else if (draw_tabs && str[j] == '\t') { int yofs = (get_row_height() - cache.tab_icon->get_height()) / 2; - cache.tab_icon->draw(ci, Point2(char_ofs + char_margin, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color); + cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color); } char_ofs += char_w; @@ -1246,13 +1262,13 @@ void TextEdit::_notification(int p_what) { if (j == str.length() - 1 && is_folded(line)) { int yofs = (get_row_height() - cache.folded_eol_icon->get_height()) / 2; int xofs = cache.folded_eol_icon->get_width() / 2; - cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin + xofs, ofs_y + yofs), Color(1, 1, 1, 1)); + cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin + xofs + ofs_x, ofs_y + yofs), Color(1, 1, 1, 1)); } } if (cursor.column == str.length() && cursor.line == line && (char_ofs + char_margin) >= xmargin_beg) { - cursor_pos = Point2i(char_ofs + char_margin, ofs_y); + cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y); if (insert_mode) { cursor_pos.y += (get_row_height() - 3); @@ -1277,7 +1293,7 @@ void TextEdit::_notification(int p_what) { VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color); } - cache.font->draw_char(ci, Point2(char_ofs + char_margin, ofs_y + ascent), cchar, next, color); + cache.font->draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color); char_ofs += im_char_width; ofs++; @@ -3913,6 +3929,7 @@ void TextEdit::clear() { void TextEdit::set_readonly(bool p_readonly) { readonly = p_readonly; + update(); } bool TextEdit::is_readonly() const { @@ -3950,6 +3967,7 @@ void TextEdit::_update_caches() { cache.style_normal = get_stylebox("normal"); cache.style_focus = get_stylebox("focus"); + cache.style_readonly = get_stylebox("read_only"); cache.completion_background_color = get_color("completion_background_color"); cache.completion_selected_color = get_color("completion_selected_color"); cache.completion_existing_color = get_color("completion_existing_color"); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index bb9ca87d06..428c850a1b 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -78,6 +78,7 @@ class TextEdit : public Control { Ref<Texture> folded_eol_icon; Ref<StyleBox> style_normal; Ref<StyleBox> style_focus; + Ref<StyleBox> style_readonly; Ref<Font> font; Color completion_background_color; Color completion_selected_color; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index f74bf161f0..5ee286c2d5 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -418,12 +418,12 @@ void SceneTree::input_event(const Ref<InputEvent> &p_event) { if (!input_handled) { call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_unhandled_input", ev); //special one for GUI, as controls use their own process check - input_handled = true; _flush_ugc(); + // input_handled = true; - no reason to set this as handled root_lock--; //MessageQueue::get_singleton()->flush(); //flushing here causes UI and other places slowness } else { - input_handled = true; + // input_handled = true; - no reason to set this as handled root_lock--; } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 1fc2d4b16e..d864b0f763 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -69,6 +69,8 @@ void ViewportTexture::setup_local_to_scene() { ERR_FAIL_COND(!vp); vp->viewport_textures.insert(this); + + VS::get_singleton()->texture_set_proxy(proxy, vp->texture_rid); } void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) { @@ -105,8 +107,8 @@ Size2 ViewportTexture::get_size() const { } RID ViewportTexture::get_rid() const { - ERR_FAIL_COND_V(!vp, RID()); - return vp->texture_rid; + //ERR_FAIL_COND_V(!vp, RID()); + return proxy; } bool ViewportTexture::has_alpha() const { @@ -147,6 +149,7 @@ ViewportTexture::ViewportTexture() { vp = NULL; set_local_to_scene(true); + proxy = VS::get_singleton()->texture_create(); } ViewportTexture::~ViewportTexture() { @@ -154,6 +157,8 @@ ViewportTexture::~ViewportTexture() { if (vp) { vp->viewport_textures.erase(this); } + + VS::get_singleton()->free(proxy); } ///////////////////////////////////// @@ -2813,6 +2818,7 @@ Viewport::Viewport() { default_texture.instance(); default_texture->vp = const_cast<Viewport *>(this); viewport_textures.insert(default_texture.ptr()); + VS::get_singleton()->texture_set_proxy(default_texture->proxy, texture_rid); //internal_listener = SpatialSoundServer::get_singleton()->listener_create(); audio_listener = false; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 6bbd4b26b5..0835e3f69a 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -59,6 +59,8 @@ class ViewportTexture : public Texture { friend class Viewport; Viewport *vp; + RID proxy; + protected: static void _bind_methods(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index c99bc3c9ef..d6557f508e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -529,6 +529,7 @@ void register_scene_types() { ClassDB::register_class<LargeTexture>(); ClassDB::register_class<CurveTexture>(); ClassDB::register_class<GradientTexture>(); + ClassDB::register_class<ProxyTexture>(); ClassDB::register_class<CubeMap>(); ClassDB::register_class<Animation>(); ClassDB::register_virtual_class<Font>(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index c5feecd7c4..651b7543c6 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -257,6 +257,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // LinkButton + theme->set_stylebox("focus", "LinkButton", focus); + theme->set_font("font", "LinkButton", default_font); theme->set_color("font_color", "LinkButton", control_font_color); @@ -448,6 +450,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("normal", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3)); theme->set_stylebox("focus", "TextEdit", focus); + theme->set_stylebox("read_only", "TextEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4)); theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3)); theme->set_icon("tab", "TextEdit", make_icon(tab_png)); diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 255bb4c6dd..c6b37cad5a 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -410,6 +410,10 @@ static const unsigned char tree_bg_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xd, 0xf6, 0xb4, 0x61, 0xf5, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char tree_bg_disabled_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x95, 0xce, 0x31, 0x12, 0x2, 0x21, 0x10, 0x44, 0xd1, 0x3f, 0x40, 0xa1, 0x44, 0xa6, 0x46, 0xde, 0x63, 0x4f, 0xe5, 0x15, 0x38, 0xb2, 0xd6, 0x6, 0xb0, 0xc8, 0x30, 0x6, 0x96, 0xac, 0x56, 0x99, 0xf8, 0xb3, 0x7e, 0x51, 0xcb, 0xf9, 0x1a, 0xb3, 0x3f, 0xa, 0xaf, 0xc, 0xad, 0x2d, 0xcb, 0xe5, 0x76, 0x38, 0x5, 0x76, 0xec, 0x6c, 0xf7, 0xe0, 0x53, 0xe0, 0x13, 0xa1, 0x27, 0x27, 0x43, 0x26, 0x81, 0x20, 0xc8, 0x70, 0xfc, 0xe8, 0xf, 0x34, 0x67, 0xd8, 0x9c, 0x86, 0x61, 0x2e, 0x68, 0xe9, 0x91, 0xaf, 0x4b, 0x5a, 0x7d, 0x2a, 0x2c, 0x3, 0xed, 0xef, 0x1e, 0x6b, 0xcb, 0x4f, 0xa6, 0x66, 0x2b, 0x25, 0x6, 0x1, 0x37, 0x40, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char tree_bg_focus_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0x73, 0x7a, 0x7a, 0xf4, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdb, 0xb, 0x4, 0x12, 0x2d, 0x3a, 0xb5, 0x1b, 0x14, 0x49, 0x0, 0x0, 0x2, 0xd9, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xc5, 0x57, 0x31, 0x8e, 0x14, 0x31, 0x10, 0xac, 0xea, 0x3d, 0x11, 0x91, 0xdf, 0x49, 0xf7, 0xf, 0x78, 0x1, 0xf, 0x40, 0x84, 0x44, 0x10, 0xf2, 0x20, 0x42, 0x62, 0x12, 0xc4, 0x3, 0x78, 0x1, 0xff, 0x21, 0x42, 0xb8, 0x8a, 0xc0, 0x1e, 0x4f, 0xdb, 0xe3, 0xb9, 0xbb, 0x45, 0x20, 0x7c, 0x1a, 0xdd, 0x8c, 0xec, 0xed, 0xae, 0xae, 0xea, 0xee, 0xe9, 0xe1, 0xfd, 0xed, 0xdd, 0xb, 0x0, 0xdf, 0xf1, 0x7f, 0xd6, 0x4b, 0xde, 0xdf, 0xde, 0xf9, 0xcb, 0xeb, 0x9f, 0xff, 0xc5, 0xfb, 0x9b, 0xaf, 0xcf, 0x70, 0xb3, 0x3d, 0x3c, 0xff, 0xf0, 0xd, 0x24, 0x11, 0x71, 0x1, 0x49, 0x90, 0x4, 0x0, 0x4, 0xd3, 0x2f, 0xb6, 0x7b, 0xf, 0xff, 0x86, 0x2d, 0x8c, 0x47, 0x60, 0x1b, 0x0, 0x61, 0x1b, 0xb6, 0x21, 0x15, 0xd8, 0xc6, 0x8f, 0x8f, 0xaf, 0x0, 0x60, 0x7, 0x0, 0xa2, 0x2, 0x20, 0x11, 0x41, 0x30, 0xa2, 0x2, 0xc1, 0xb5, 0x0, 0x8c, 0x79, 0xd9, 0x80, 0x24, 0x48, 0x0, 0x48, 0x28, 0x9d, 0xb9, 0xd9, 0xd, 0xb0, 0x31, 0x40, 0x5c, 0x2e, 0x1, 0x46, 0x0, 0xd, 0xd0, 0xb6, 0xef, 0x35, 0x8e, 0x13, 0x6, 0xbc, 0x33, 0x60, 0xa3, 0x9a, 0x11, 0x6c, 0x82, 0xe6, 0xa, 0x0, 0x86, 0xe8, 0x2f, 0x71, 0xa9, 0xf7, 0x9c, 0x4d, 0x1f, 0x69, 0x5e, 0x1, 0xd8, 0xa3, 0x37, 0xa4, 0xa, 0x27, 0x1a, 0x13, 0x79, 0x25, 0x9, 0xaa, 0xe3, 0xd8, 0x9c, 0x5f, 0xea, 0x7d, 0x67, 0x80, 0xd7, 0x31, 0x20, 0xab, 0x3, 0x20, 0x5, 0x20, 0x2a, 0x13, 0x41, 0x40, 0x2b, 0x0, 0x76, 0x22, 0xb9, 0xb1, 0xd1, 0x92, 0x91, 0x5d, 0x86, 0xf3, 0x35, 0xef, 0x5, 0xa3, 0x25, 0x60, 0xd, 0x6e, 0x66, 0xe5, 0x0, 0xc0, 0xa8, 0x54, 0x1, 0x6, 0xe9, 0x16, 0x9f, 0x4f, 0xdc, 0x1c, 0x13, 0xed, 0xb1, 0x55, 0x31, 0x78, 0x70, 0x8e, 0xca, 0xcb, 0x8e, 0x6a, 0xbe, 0x56, 0x88, 0x67, 0x38, 0xdb, 0x75, 0x58, 0x76, 0xdf, 0x1b, 0x6c, 0x7a, 0xc, 0x6c, 0x90, 0x0, 0xfd, 0xe0, 0xe8, 0x98, 0xe4, 0x4, 0xe2, 0x69, 0xc, 0xe4, 0x40, 0xaa, 0xf9, 0x63, 0x70, 0xbb, 0x4, 0x16, 0x9c, 0x12, 0xa7, 0x3e, 0xe7, 0x38, 0xb3, 0x4, 0x2b, 0x6f, 0xc7, 0x23, 0xbb, 0xc3, 0x66, 0xdb, 0x38, 0x7, 0x0, 0xcf, 0x32, 0x34, 0xb6, 0x52, 0xb4, 0x3c, 0xf7, 0x35, 0x10, 0xd9, 0xf7, 0x6, 0x56, 0x93, 0x4, 0x4b, 0x0, 0x43, 0x28, 0xf9, 0x4a, 0x3d, 0x6e, 0xb0, 0x3e, 0x9, 0x31, 0xa9, 0x62, 0xd6, 0xc4, 0x36, 0x9c, 0xf2, 0xd9, 0xbd, 0x41, 0x2d, 0x24, 0x68, 0xc7, 0x1f, 0x62, 0x60, 0x6a, 0xc1, 0x7f, 0x95, 0x81, 0xaa, 0x13, 0x61, 0x9, 0xa6, 0xf6, 0x1c, 0x30, 0x17, 0x11, 0x6f, 0x48, 0x12, 0x3b, 0xf3, 0x7b, 0xc2, 0xeb, 0xca, 0x92, 0xb7, 0x72, 0x5f, 0x31, 0x90, 0x11, 0x4e, 0x48, 0xb3, 0x13, 0xa6, 0xcc, 0x3e, 0x51, 0x60, 0x91, 0x53, 0x55, 0x87, 0xf3, 0x2a, 0x98, 0xff, 0x7c, 0x6c, 0x1a, 0xf9, 0xec, 0xda, 0xeb, 0x94, 0x13, 0x43, 0xdd, 0x3f, 0x2a, 0x41, 0xd2, 0xb, 0x27, 0x65, 0xe8, 0x13, 0x20, 0x29, 0x3f, 0xc6, 0x7c, 0x48, 0x65, 0x8, 0x41, 0xda, 0xa4, 0xd5, 0x11, 0xc0, 0x2a, 0x61, 0xce, 0x18, 0x58, 0xd2, 0xbe, 0x98, 0x48, 0x96, 0xdd, 0xf5, 0xbc, 0x11, 0x65, 0xb6, 0x12, 0x55, 0xcb, 0xde, 0xb3, 0x78, 0x27, 0x78, 0xdc, 0xcb, 0x72, 0xe6, 0xd7, 0x8a, 0x27, 0xe6, 0x52, 0x1f, 0x10, 0xe0, 0xb8, 0x92, 0x81, 0xb4, 0x3f, 0x1, 0x1d, 0xed, 0x6c, 0xd4, 0xef, 0x12, 0x2f, 0x73, 0xa0, 0xe, 0xf, 0x42, 0x24, 0x20, 0xf, 0x91, 0xbf, 0x6e, 0x44, 0xfb, 0xde, 0xa1, 0x4, 0xa5, 0x7, 0xaa, 0xa0, 0x23, 0xad, 0xd4, 0x4b, 0xaa, 0x73, 0x0, 0xb7, 0xa1, 0x82, 0x87, 0x46, 0x74, 0x9a, 0xf, 0x48, 0x5d, 0xb3, 0xd, 0xa2, 0xb0, 0x96, 0xe5, 0x7d, 0xc8, 0x81, 0x19, 0xf1, 0x36, 0x2b, 0xba, 0xbd, 0x5e, 0xb3, 0xb7, 0x55, 0x12, 0x76, 0x90, 0xc4, 0x3a, 0x1, 0xa7, 0x66, 0xbc, 0x3, 0x90, 0xe0, 0x8, 0xc8, 0x42, 0x29, 0xa5, 0x7b, 0xa2, 0x63, 0x9f, 0x88, 0x26, 0xa, 0x9c, 0x85, 0x6f, 0x7b, 0x2b, 0x0, 0x92, 0x51, 0x4a, 0x81, 0x5c, 0x2a, 0xcb, 0x2a, 0x47, 0x0, 0xb0, 0x2b, 0x8, 0x11, 0x62, 0x20, 0x58, 0x20, 0x47, 0x77, 0x5a, 0xe5, 0x98, 0x43, 0x3f, 0x2, 0xd8, 0xc1, 0xa5, 0x39, 0x40, 0x82, 0xb5, 0xd9, 0xd7, 0x5a, 0x2, 0x59, 0x80, 0x9, 0x8a, 0x0, 0x7f, 0x1, 0x8, 0x44, 0x8, 0x64, 0xe0, 0xe8, 0x6e, 0x4b, 0xb4, 0x87, 0xa6, 0xc4, 0x3d, 0x17, 0x24, 0xa3, 0xa8, 0xc0, 0x32, 0x8a, 0xea, 0x33, 0x67, 0x0, 0x6e, 0xc, 0x94, 0x5e, 0xe2, 0x46, 0x11, 0x3a, 0x0, 0x82, 0x57, 0x1, 0x98, 0xbf, 0xb, 0xa4, 0xf6, 0x55, 0xd4, 0x2a, 0xe1, 0x0, 0x40, 0xf5, 0xf3, 0xa5, 0xd3, 0x16, 0x6a, 0xb4, 0xa7, 0x19, 0xfa, 0x4f, 0x18, 0xe8, 0x2c, 0x34, 0xfb, 0x92, 0x20, 0xbb, 0xf, 0xa3, 0x1d, 0xc0, 0xcd, 0xe7, 0xb7, 0x83, 0xf9, 0xf2, 0x24, 0xd3, 0xd7, 0xaf, 0x40, 0x9a, 0x84, 0x1, 0xf0, 0xfe, 0xf6, 0xee, 0x1d, 0x80, 0x4f, 0xff, 0xc8, 0xdf, 0x63, 0xeb, 0xfd, 0x6f, 0x3, 0x74, 0x35, 0xa7, 0x2a, 0xf0, 0x17, 0xed, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; diff --git a/scene/resources/default_theme/tree_bg_disabled.png b/scene/resources/default_theme/tree_bg_disabled.png Binary files differnew file mode 100644 index 0000000000..a0fa505e4c --- /dev/null +++ b/scene/resources/default_theme/tree_bg_disabled.png diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 79f642a09b..a6f301af1e 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -215,6 +215,13 @@ bool ShaderMaterial::_can_do_next_pass() const { return shader.is_valid() && shader->get_mode() == Shader::MODE_SPATIAL; } +Shader::Mode ShaderMaterial::get_shader_mode() const { + if (shader.is_valid()) + return shader->get_mode(); + else + return Shader::MODE_SPATIAL; +} + ShaderMaterial::ShaderMaterial() { } @@ -689,6 +696,10 @@ void SpatialMaterial::_update_shader() { } } + if (flags[FLAG_ALBEDO_TEXTURE_FORCE_SRGB]) { + code += "\talbedo_tex.rgb = mix(pow((albedo_tex.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),albedo_tex.rgb.rgb * (1.0 / 12.92),lessThan(albedo_tex.rgb,vec3(0.04045)));\n"; + } + if (flags[FLAG_ALBEDO_FROM_VERTEX_COLOR]) { code += "\talbedo_tex *= COLOR;\n"; } @@ -1658,6 +1669,11 @@ RID SpatialMaterial::get_shader_rid() const { return shader_map[current_key].shader; } +Shader::Mode SpatialMaterial::get_shader_mode() const { + + return Shader::MODE_SPATIAL; +} + void SpatialMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_albedo", "albedo"), &SpatialMaterial::set_albedo); @@ -1833,6 +1849,7 @@ void SpatialMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_use_point_size"), "set_flag", "get_flag", FLAG_USE_POINT_SIZE); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_world_triplanar"), "set_flag", "get_flag", FLAG_TRIPLANAR_USE_WORLD); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_fixed_size"), "set_flag", "get_flag", FLAG_FIXED_SIZE); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_albedo_tex_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB); ADD_GROUP("Vertex Color", "vertex_color"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "vertex_color_use_as_albedo"), "set_flag", "get_flag", FLAG_ALBEDO_FROM_VERTEX_COLOR); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "vertex_color_is_srgb"), "set_flag", "get_flag", FLAG_SRGB_VERTEX_COLOR); @@ -2019,6 +2036,7 @@ void SpatialMaterial::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_AO_ON_UV2); BIND_ENUM_CONSTANT(FLAG_USE_ALPHA_SCISSOR); BIND_ENUM_CONSTANT(FLAG_TRIPLANAR_USE_WORLD); + BIND_ENUM_CONSTANT(FLAG_ALBEDO_TEXTURE_FORCE_SRGB); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(DIFFUSE_BURLEY); diff --git a/scene/resources/material.h b/scene/resources/material.h index 877d4dfd41..7cfa38fce4 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -69,6 +69,8 @@ public: int get_render_priority() const; virtual RID get_rid() const; + + virtual Shader::Mode get_shader_mode() const = 0; Material(); virtual ~Material(); }; @@ -96,6 +98,8 @@ public: void set_shader_param(const StringName &p_param, const Variant &p_value); Variant get_shader_param(const StringName &p_param) const; + virtual Shader::Mode get_shader_mode() const; + ShaderMaterial(); ~ShaderMaterial(); }; @@ -181,6 +185,7 @@ public: FLAG_TRIPLANAR_USE_WORLD, FLAG_AO_ON_UV2, FLAG_USE_ALPHA_SCISSOR, + FLAG_ALBEDO_TEXTURE_FORCE_SRGB, FLAG_MAX }; @@ -229,7 +234,7 @@ private: uint64_t blend_mode : 2; uint64_t depth_draw_mode : 2; uint64_t cull_mode : 2; - uint64_t flags : 12; + uint64_t flags : 13; uint64_t detail_blend_mode : 2; uint64_t diffuse_mode : 3; uint64_t specular_mode : 2; @@ -599,6 +604,8 @@ public: RID get_shader_rid() const; + virtual Shader::Mode get_shader_mode() const; + SpatialMaterial(); virtual ~SpatialMaterial(); }; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 5d6f44dfef..3a5cb7da2e 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -177,7 +177,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { node = Object::cast_to<Node>(obj); } else { - print_line("wtf class is disabled for: " + itos(n.type)); + print_line("Class is disabled for: " + itos(n.type)); print_line("name: " + String(snames[n.type])); } @@ -232,11 +232,11 @@ Node *SceneState::instance(GenEditState p_edit_state) const { Node *base = i == 0 ? node : ret_nodes[0]; if (p_edit_state == GEN_EDIT_STATE_MAIN) { - - res->local_scene = base; - resources_local_to_scene[res] = res; + //for the main scene, use the resource as is + res->configure_for_local_scene(base, resources_local_to_scene); } else { + //for instances, a copy must be made Node *base = i == 0 ? node : ret_nodes[0]; Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, resources_local_to_scene); resources_local_to_scene[res] = local_dupe; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 3b80db291c..2e8f9cbb33 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -164,7 +164,7 @@ void PrimitiveMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mesh_arrays"), &PrimitiveMesh::get_mesh_arrays); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); } void PrimitiveMesh::set_material(const Ref<Material> &p_material) { diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 162edd0d1c..987d6c5f6a 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1601,3 +1601,72 @@ int GradientTexture::get_width() const { Ref<Image> GradientTexture::get_data() const { return VisualServer::get_singleton()->texture_get_data(texture); } + +////////////////////////////////////// + +void ProxyTexture::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_base", "base"), &ProxyTexture::set_base); + ClassDB::bind_method(D_METHOD("get_base"), &ProxyTexture::get_base); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_base", "get_base"); +} + +void ProxyTexture::set_base(const Ref<Texture> &p_texture) { + + base = p_texture; + if (base.is_valid()) { + VS::get_singleton()->texture_set_proxy(proxy, base->get_rid()); + } else { + VS::get_singleton()->texture_set_proxy(proxy, RID()); + } +} + +Ref<Texture> ProxyTexture::get_base() const { + + return base; +} + +int ProxyTexture::get_width() const { + + if (base.is_valid()) + return base->get_width(); + return 1; +} +int ProxyTexture::get_height() const { + + if (base.is_valid()) + return base->get_height(); + return 1; +} +RID ProxyTexture::get_rid() const { + + return proxy; +} + +bool ProxyTexture::has_alpha() const { + + if (base.is_valid()) + return base->has_alpha(); + return false; +} + +void ProxyTexture::set_flags(uint32_t p_flags) { +} + +uint32_t ProxyTexture::get_flags() const { + + if (base.is_valid()) + return base->get_flags(); + return 0; +} + +ProxyTexture::ProxyTexture() { + + proxy = VS::get_singleton()->texture_create(); +} + +ProxyTexture::~ProxyTexture() { + + VS::get_singleton()->free(proxy); +} diff --git a/scene/resources/texture.h b/scene/resources/texture.h index ee54156647..76c0195ef9 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -493,4 +493,31 @@ public: virtual ~GradientTexture(); }; +class ProxyTexture : public Texture { + GDCLASS(ProxyTexture, Texture) + +private: + RID proxy; + Ref<Texture> base; + +protected: + static void _bind_methods(); + +public: + void set_base(const Ref<Texture> &p_texture); + Ref<Texture> get_base() const; + + virtual int get_width() const; + virtual int get_height() const; + virtual RID get_rid() const; + + virtual bool has_alpha() const; + + virtual void set_flags(uint32_t p_flags); + virtual uint32_t get_flags() const; + + ProxyTexture(); + ~ProxyTexture(); +}; + #endif diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 2499551607..4bb34af241 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -193,6 +193,8 @@ public: virtual void textures_keep_original(bool p_enable) = 0; + virtual void texture_set_proxy(RID p_proxy, RID p_base) = 0; + /* SKY API */ virtual RID sky_create() = 0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index f34951f452..91542625e0 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -168,6 +168,8 @@ public: BIND1(textures_keep_original, bool) + BIND2(texture_set_proxy, RID, RID) + /* SKY API */ BIND0R(RID, sky_create) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 69827b330d..72fb1df94b 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -303,6 +303,23 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { VSG::storage->instance_remove_dependency(instance->base, instance); + if (instance->base_type == VS::INSTANCE_GI_PROBE) { + //if gi probe is baking, wait until done baking, else race condition may happen when removing it + //from octree + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + + //make sure probes are done baking + while (!probe_bake_list.empty()) { + OS::get_singleton()->delay_usec(1); + } + //make sure this one is done baking + + while (gi_probe->dynamic.updating_stage == GI_UPDATE_STAGE_LIGHTING) { + //wait until bake is done if it's baking + OS::get_singleton()->delay_usec(1); + } + } + if (scenario && instance->octree_id) { scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away instance->octree_id = 0; @@ -331,10 +348,6 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); - while (gi_probe->dynamic.updating_stage == GI_UPDATE_STAGE_LIGHTING) { - //wait until bake is done if it's baking - OS::get_singleton()->delay_usec(1); - } if (gi_probe->update_element.in_list()) { gi_probe_update_list.remove(&gi_probe->update_element); } @@ -2589,7 +2602,15 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { } //send back to main thread to update un little chunks + if (probe_bake_mutex) { + probe_bake_mutex->lock(); + } + probe_data->dynamic.updating_stage = GI_UPDATE_STAGE_UPLOADING; + + if (probe_bake_mutex) { + probe_bake_mutex->unlock(); + } } bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) { @@ -2722,11 +2743,11 @@ void VisualServerScene::render_probes() { case GI_UPDATE_STAGE_CHECK: { if (_check_gi_probe(instance_probe) || force_lighting) { - //send to lighting thread - probe->dynamic.updating_stage = GI_UPDATE_STAGE_LIGHTING; +//send to lighting thread #ifndef NO_THREADS probe_bake_mutex->lock(); + probe->dynamic.updating_stage = GI_UPDATE_STAGE_LIGHTING; probe_bake_list.push_back(instance_probe); probe_bake_mutex->unlock(); probe_bake_sem->post(); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 9af5ffb74d..bc5d266113 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -438,6 +438,7 @@ public: : update_element(this) { invalid = true; base_version = 0; + dynamic.updating_stage = GI_UPDATE_STAGE_CHECK; } }; diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index d1069a410c..1c3b34d16f 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -100,6 +100,8 @@ public: FUNC1(textures_keep_original, bool) + FUNC2(texture_set_proxy, RID, RID) + /* SKY API */ FUNCRID(sky) diff --git a/servers/visual_server.h b/servers/visual_server.h index 9df389999a..350097c1b5 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -141,6 +141,8 @@ public: virtual void textures_keep_original(bool p_enable) = 0; + virtual void texture_set_proxy(RID p_proxy, RID p_base) = 0; + /* SKY API */ virtual RID sky_create() = 0; diff --git a/thirdparty/README.md b/thirdparty/README.md index 1573fab7b6..8ff64c4636 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -390,17 +390,13 @@ Files extracted from upstream source: ## tinyexr - Upstream: https://github.com/syoyo/tinyexr -- Version: 0.9.5+ (git a145d69) +- Version: 0.9.5+ (git 9f784ca - 24 October 2017) - License: BSD-3-Clause Files extracted from upstream source: - `tinyexr.{cc,h}` -Important: Some changes were made to get TinyEXR to build on the ancient -MinGW-w64 toolchain of Travis CI. -https://github.com/godotengine/godot/commit/37f5e1dcd94611dd5b670f013abf0323e8b47def - ## zlib diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h index c82768be9a..606c19756a 100644 --- a/thirdparty/tinyexr/tinyexr.h +++ b/thirdparty/tinyexr/tinyexr.h @@ -85,11 +85,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stddef.h> // for size_t #include <stdint.h> // guess stdint.h is available(C99) -// -- GODOT change for old MinGW on Travis CI -- -#if defined(__MINGW32__) -#include <_mingw.h> // for __MINGW64_VERSION_MAJOR -#endif - #ifdef __cplusplus extern "C" { #endif @@ -264,7 +259,8 @@ typedef struct _DeepImage { } DeepImage; // @deprecated { to be removed. } -// Loads single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. +// Loads single-frame OpenEXR image. Assume EXR image contains A(single channel +// alpha) or RGB(A) channels. // Application must free image data as returned by `out_rgba` // Result image format is: float x RGBA x width x hight // Returns negative value and may set error string in `err` when there's an @@ -274,9 +270,14 @@ extern int LoadEXR(float **out_rgba, int *width, int *height, // @deprecated { to be removed. } // Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. -// components must be 3(RGB) or 4(RGBA). -// Result image format is: float x RGB(A) x width x hight -extern int SaveEXR(const float *data, int width, int height, int components, +// components must be 1(Grayscale), 3(RGB) or 4(RGBA). +// Input image format is: `float x width x height`, or `float x RGB(A) x width x +// hight` +// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero +// value. +// Save image as fp32(FLOAT) format when `save_as_fp16` is 0. +extern int SaveEXR(const float *data, const int width, const int height, + const int components, const int save_as_fp16, const char *filename); // Initialize EXRHeader struct @@ -406,12 +407,11 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename, // For emscripten. // Loads single-frame OpenEXR image from memory. Assume EXR image contains // RGB(A) channels. -// `out_rgba` must have enough memory(at least sizeof(float) x 4(RGBA) x width x -// hight) // Returns negative value and may set error string in `err` when there's an // error -extern int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, - size_t size, const char **err); +extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err); #ifdef __cplusplus } @@ -444,7 +444,8 @@ extern int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, #if TINYEXR_USE_MINIZ #else -#include "zlib.h" +// Issue #46. Please include your own zlib-compatible API header before including `tinyexr.h` +//#include "zlib.h" #endif #if TINYEXR_USE_ZFP @@ -483,13 +484,11 @@ namespace miniz { #pragma clang diagnostic ignored "-Wsign-conversion" #pragma clang diagnostic ignored "-Wc++11-extensions" #pragma clang diagnostic ignored "-Wconversion" -#ifdef __APPLE__ -#if __clang_major__ >= 8 && __clang__minor__ > 1 +#pragma clang diagnostic ignored "-Wunused-function" +#if __has_warning("-Wcomma") #pragma clang diagnostic ignored "-Wcomma" #endif #endif -#pragma clang diagnostic ignored "-Wunused-function" -#endif /* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing @@ -1918,11 +1917,11 @@ static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } -static void *def_realloc_func(void *opaque, void *address, size_t items, - size_t size) { - (void)opaque, (void)address, (void)items, (void)size; - return MZ_REALLOC(address, items * size); -} +// static void *def_realloc_func(void *opaque, void *address, size_t items, +// size_t size) { +// (void)opaque, (void)address, (void)items, (void)size; +// return MZ_REALLOC(address, items * size); +//} const char *mz_version(void) { return MZ_VERSION; } @@ -2894,8 +2893,9 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, tinfl_status status = tinfl_decompress( &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, - &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { MZ_FREE(pBuf); *pOut_len = 0; @@ -3542,9 +3542,10 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = - ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && - (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + int n, + use_raw_block = + ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && + (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) @@ -3574,8 +3575,9 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) { if (!use_raw_block) comp_block_succeeded = - tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || - (d->m_total_lz_bytes < 48)); + tdefl_compress_block(d, + (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || + (d->m_total_lz_bytes < 48)); // If the block gets expanded, forget the current contents of the output // buffer and send a raw block instead. @@ -4519,10 +4521,7 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, #include <stdio.h> #include <sys/stat.h> -// -- GODOT change for old MinGW on Travis CI -- -//#if defined(_MSC_VER) || defined(__MINGW64__) -#if defined(_MSC_VER) || (defined(__MINGW32__) && __MINGW64_VERSION_MAJOR >= 3) -// -- GODOT end -- +#if defined(_MSC_VER) || defined(__MINGW64__) static FILE *mz_fopen(const char *pFilename, const char *pMode) { FILE *pFile = NULL; fopen_s(&pFile, pFilename, pMode); @@ -5223,9 +5222,10 @@ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); pStat->m_comment_size = n; - memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + - MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + - MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), + memcpy(pStat->m_comment, + p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; @@ -6883,6 +6883,12 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, #ifdef __clang__ #pragma clang diagnostic pop #endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + } #else @@ -7346,11 +7352,23 @@ static void CompressZip(unsigned char *dst, compressedSize = outSize; #endif + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } } static void DecompressZip(unsigned char *dst, unsigned long *uncompressed_size /* inout */, const unsigned char *src, unsigned long src_size) { + if ((*uncompressed_size) == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return; + } std::vector<unsigned char> tmpBuf(*uncompressed_size); #if TINYEXR_USE_MINIZ @@ -7410,6 +7428,22 @@ static void DecompressZip(unsigned char *dst, #pragma clang diagnostic ignored "-Wsign-conversion" #endif +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) +#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning( \ + disable : 4267) // 'argument': conversion from '__int64' to 'int', + // possible loss of data +#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is + // deprecated. Instead, use the ISO C and C++ + // conformant name: _strdup. +#endif + + const int MIN_RUN_LENGTH = 3; const int MAX_RUN_LENGTH = 127; @@ -7502,6 +7536,7 @@ static int rleUncompress(int inLength, int maxLength, const signed char in[], #ifdef __clang__ #pragma clang diagnostic pop #endif + // End of RLE code from OpenEXR ----------------------------------- static void CompressRle(unsigned char *dst, @@ -7562,11 +7597,24 @@ static void CompressRle(unsigned char *dst, assert(outSize > 0); compressedSize = static_cast<tinyexr::tinyexr_uint64>(outSize); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } } static void DecompressRle(unsigned char *dst, const unsigned long uncompressed_size, const unsigned char *src, unsigned long src_size) { + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return; + } + std::vector<unsigned char> tmpBuf(uncompressed_size); int ret = rleUncompress(static_cast<int>(src_size), @@ -8882,7 +8930,12 @@ static void applyLut(const unsigned short lut[USHORT_RANGE], #pragma clang diagnostic pop #endif // __clang__ -static bool CompressPiz(unsigned char *outPtr, unsigned int &outSize, +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize, const unsigned char *inPtr, size_t inSize, const std::vector<ChannelInfo> &channelInfo, int data_width, int num_lines) { @@ -8989,16 +9042,29 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int &outSize, hufCompress(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), buf); memcpy(lengthPtr, &length, sizeof(int)); - outSize = static_cast<unsigned int>( + (*outSize) = static_cast<unsigned int>( (reinterpret_cast<unsigned char *>(buf) - outPtr) + static_cast<unsigned int>(length)); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if ((*outSize) >= inSize) { + (*outSize) = static_cast<unsigned int>(inSize); + memcpy(outPtr, inPtr, inSize); + } return true; } static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, - size_t tmpBufSize, int num_channels, + size_t tmpBufSize, size_t inLen, int num_channels, const EXRChannelInfo *channels, int data_width, int num_lines) { + if (inLen == tmpBufSize) { + // Data is not compressed(Issue 40). + memcpy(outPtr, inPtr, inLen); + return true; + } + unsigned char bitmap[BITMAP_SIZE]; unsigned short minNonZero; unsigned short maxNonZero; @@ -9173,6 +9239,11 @@ static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines, const ZFPCompressionParam ¶m) { size_t uncompressed_size = dst_width * dst_num_lines * num_channels; + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + } + zfp_stream *zfp = NULL; zfp_field *field = NULL; @@ -9317,12 +9388,11 @@ static void DecodePixelData(/* out */ unsigned char **out_images, // Allocate original data size. std::vector<unsigned char> outBuf(static_cast<size_t>( static_cast<size_t>(width * num_lines) * pixel_data_size)); - size_t tmpBufLen = static_cast<size_t>( - static_cast<size_t>(width * num_lines) * pixel_data_size); + size_t tmpBufLen = outBuf.size(); bool ret = tinyexr::DecompressPiz( reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen, - static_cast<int>(num_channels), channels, width, num_lines); + data_len, static_cast<int>(num_channels), channels, width, num_lines); assert(ret); (void)ret; @@ -10047,8 +10117,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, } else if (attr_name.compare("compression") == 0) { bool ok = false; - if ((data[0] >= TINYEXR_COMPRESSIONTYPE_NONE) && - (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ)) { + if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) { ok = true; } @@ -10158,9 +10227,14 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, // Custom attribute(up to TINYEXR_MAX_ATTRIBUTES) if (info->attributes.size() < TINYEXR_MAX_ATTRIBUTES) { EXRAttribute attrib; +#ifdef _MSC_VER + strncpy_s(attrib.name, attr_name.c_str(), 255); + strncpy_s(attrib.type, attr_type.c_str(), 255); +#else strncpy(attrib.name, attr_name.c_str(), 255); - attrib.name[255] = '\0'; strncpy(attrib.type, attr_type.c_str(), 255); +#endif + attrib.name[255] = '\0'; attrib.type[255] = '\0'; attrib.size = static_cast<int>(data.size()); attrib.value = static_cast<unsigned char *>(malloc(data.size())); @@ -10254,8 +10328,12 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) { exr_header->channels = static_cast<EXRChannelInfo *>(malloc( sizeof(EXRChannelInfo) * static_cast<size_t>(exr_header->num_channels))); for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) { +#ifdef _MSC_VER + strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); +#else strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); - // manually add '\0' for safety. +#endif + // manually add '\0' for safety. exr_header->channels[c].name[255] = '\0'; exr_header->channels[c].pixel_type = info.channels[c].pixel_type; @@ -10317,6 +10395,8 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, &channel_offset, num_channels, exr_header->channels); + bool invalid_data = false; + if (exr_header->tiled) { size_t num_tiles = offsets.size(); // = # of blocks @@ -10411,18 +10491,26 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, // Adjust line_no with data_window.bmin.y line_no -= exr_header->data_window[1]; - tinyexr::DecodePixelData( - exr_image->images, exr_header->requested_pixel_types, data_ptr, - static_cast<size_t>(data_len), exr_header->compression_type, - exr_header->line_order, data_width, data_height, data_width, y, - line_no, num_lines, static_cast<size_t>(pixel_data_size), - static_cast<size_t>(exr_header->num_custom_attributes), - exr_header->custom_attributes, - static_cast<size_t>(exr_header->num_channels), exr_header->channels, - channel_offset_list); + if (line_no < 0) { + invalid_data = true; + } else { + tinyexr::DecodePixelData( + exr_image->images, exr_header->requested_pixel_types, data_ptr, + static_cast<size_t>(data_len), exr_header->compression_type, + exr_header->line_order, data_width, data_height, data_width, y, + line_no, num_lines, static_cast<size_t>(pixel_data_size), + static_cast<size_t>(exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast<size_t>(exr_header->num_channels), exr_header->channels, + channel_offset_list); + } } // omp parallel } + if (invalid_data) { + return TINYEXR_ERROR_INVALID_DATA; + } + // Overwrite `pixel_type` with `requested_pixel_type`. { for (int c = 0; c < exr_header->num_channels; c++) { @@ -10641,46 +10729,63 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, } } - if (idxR == -1) { - if (err) { - (*err) = "R channel not found\n"; + if ((idxA == 0) && (idxR == -1) && (idxG == -1) && (idxB == -1)) { + // Alpha channel only. + + (*out_rgba) = reinterpret_cast<float *>( + malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * + static_cast<size_t>(exr_image.height))); + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + const float val = reinterpret_cast<float **>(exr_image.images)[0][i]; + (*out_rgba)[4 * i + 0] = val; + (*out_rgba)[4 * i + 1] = val; + (*out_rgba)[4 * i + 2] = val; + (*out_rgba)[4 * i + 3] = val; } + } else { + // Assume RGB(A) - // @todo { free exr_image } - return TINYEXR_ERROR_INVALID_DATA; - } + if (idxR == -1) { + if (err) { + (*err) = "R channel not found\n"; + } - if (idxG == -1) { - if (err) { - (*err) = "G channel not found\n"; + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; } - // @todo { free exr_image } - return TINYEXR_ERROR_INVALID_DATA; - } - if (idxB == -1) { - if (err) { - (*err) = "B channel not found\n"; + if (idxG == -1) { + if (err) { + (*err) = "G channel not found\n"; + } + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; } - // @todo { free exr_image } - return TINYEXR_ERROR_INVALID_DATA; - } - (*out_rgba) = reinterpret_cast<float *>( - malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * - static_cast<size_t>(exr_image.height))); - for (int i = 0; i < exr_image.width * exr_image.height; i++) { - (*out_rgba)[4 * i + 0] = - reinterpret_cast<float **>(exr_image.images)[idxR][i]; - (*out_rgba)[4 * i + 1] = - reinterpret_cast<float **>(exr_image.images)[idxG][i]; - (*out_rgba)[4 * i + 2] = - reinterpret_cast<float **>(exr_image.images)[idxB][i]; - if (idxA != -1) { - (*out_rgba)[4 * i + 3] = - reinterpret_cast<float **>(exr_image.images)[idxA][i]; - } else { - (*out_rgba)[4 * i + 3] = 1.0; + if (idxB == -1) { + if (err) { + (*err) = "B channel not found\n"; + } + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + (*out_rgba) = reinterpret_cast<float *>( + malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * + static_cast<size_t>(exr_image.height))); + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast<float **>(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast<float **>(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast<float **>(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast<float **>(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } } } @@ -10720,7 +10825,11 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, if (ret != TINYEXR_SUCCESS) { if (err && !err_str.empty()) { +#ifdef _WIN32 + (*err) = _strdup(err_str.c_str()); // May leak +#else (*err) = strdup(err_str.c_str()); // May leak +#endif } } @@ -10732,8 +10841,9 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, return ret; } -int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size, - const char **err) { +int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err) { if (out_rgba == NULL || memory == NULL) { if (err) { (*err) = "Invalid argument.\n"; @@ -10756,6 +10866,13 @@ int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size, if (ret != TINYEXR_SUCCESS) { return ret; } + + // Read HALF channel as FLOAT. + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } InitEXRImage(&exr_image); ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err); @@ -10805,19 +10922,32 @@ int LoadEXRFromMemory(float *out_rgba, const unsigned char *memory, size_t size, return TINYEXR_ERROR_INVALID_DATA; } - // Assume `out_rgba` have enough memory allocated. + (*out_rgba) = reinterpret_cast<float *>( + malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * + static_cast<size_t>(exr_image.height))); + for (int i = 0; i < exr_image.width * exr_image.height; i++) { - out_rgba[4 * i + 0] = reinterpret_cast<float **>(exr_image.images)[idxR][i]; - out_rgba[4 * i + 1] = reinterpret_cast<float **>(exr_image.images)[idxG][i]; - out_rgba[4 * i + 2] = reinterpret_cast<float **>(exr_image.images)[idxB][i]; - if (idxA > 0) { - out_rgba[4 * i + 3] = - reinterpret_cast<float **>(exr_image.images)[idxA][i]; - } else { - out_rgba[4 * i + 3] = 1.0; - } + (*out_rgba)[4 * i + 0] = + reinterpret_cast<float **>(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast<float **>(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast<float **>(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast<float **>(exr_image.images)[idxA][i]; + } + else { + (*out_rgba)[4 * i + 3] = 1.0; + } } + (*width) = exr_image.width; + (*height) = exr_image.height; + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_SUCCESS; } @@ -10830,10 +10960,7 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header, return TINYEXR_ERROR_INVALID_ARGUMENT; } -// -- GODOT change for old MinGW on Travis CI -- -//#ifdef _WIN32 -#if defined(_MSC_VER) || (defined(__MINGW32__) && __MINGW64_VERSION_MAJOR >= 3) -// -- GODOT end -- +#ifdef _WIN32 FILE *fp = NULL; fopen_s(&fp, filename, "rb"); #else @@ -11315,7 +11442,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image, std::vector<unsigned char> block(bufLen); unsigned int outSize = static_cast<unsigned int>(block.size()); - CompressPiz(&block.at(0), outSize, + CompressPiz(&block.at(0), &outSize, reinterpret_cast<const unsigned char *>(&buf.at(0)), buf.size(), channels, exr_image->width, h); @@ -11422,10 +11549,7 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header, } #endif -// -- GODOT change for old MinGW on Travis CI -- -//#ifdef _WIN32 -#if defined(_MSC_VER) || (defined(__MINGW32__) && __MINGW64_VERSION_MAJOR >= 3) -// -- GODOT end -- +#ifdef _WIN32 FILE *fp = NULL; fopen_s(&fp, filename, "wb"); #else @@ -11459,6 +11583,16 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { return TINYEXR_ERROR_INVALID_ARGUMENT; } +#ifdef _MSC_VER + FILE *fp = NULL; + errno_t errcode = fopen_s(&fp, filename, "rb"); + if ((!errcode) || (!fp)) { + if (err) { + (*err) = "Cannot read file."; + } + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else FILE *fp = fopen(filename, "rb"); if (!fp) { if (err) { @@ -11466,6 +11600,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { } return TINYEXR_ERROR_CANT_OPEN_FILE; } +#endif size_t filesize; // Compute size @@ -11535,6 +11670,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { if (0 == size) { return TINYEXR_ERROR_INVALID_DATA; } else if (marker[0] == '\0') { + marker++; size--; break; } @@ -11724,11 +11860,13 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { // decode sample data. { unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize); - tinyexr::DecompressZip( - reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen, - data_ptr + 28 + packedOffsetTableSize, - static_cast<unsigned long>(packedSampleDataSize)); - assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize)); + if (dstLen) { + tinyexr::DecompressZip( + reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen, + data_ptr + 28 + packedOffsetTableSize, + static_cast<unsigned long>(packedSampleDataSize)); + assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize)); + } } // decode sample @@ -11774,7 +11912,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { if (channels[c].pixel_type == 0) { // UINT for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { unsigned int ui = *reinterpret_cast<unsigned int *>( - &sample_data.at(data_offset + x * sizeof(int))); + &sample_data.at(size_t(data_offset) + x * sizeof(int))); deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme } data_offset += @@ -11783,7 +11921,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { tinyexr::FP16 f16; f16.u = *reinterpret_cast<unsigned short *>( - &sample_data.at(data_offset + x * sizeof(short))); + &sample_data.at(size_t(data_offset) + x * sizeof(short))); tinyexr::FP32 f32 = half_to_float(f16); deep_image->image[c][y][x] = f32.f; } @@ -11791,7 +11929,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { } else { // float for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { float f = *reinterpret_cast<float *>( - &sample_data.at(data_offset + x * sizeof(float))); + &sample_data.at(size_t(data_offset) + x * sizeof(float))); deep_image->image[c][y][x] = f; } data_offset += sizeof(float) * static_cast<size_t>(samples_per_line); @@ -11906,10 +12044,7 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version, return TINYEXR_ERROR_INVALID_ARGUMENT; } -// -- GODOT change for old MinGW on Travis CI -- -//#ifdef _WIN32 -#if defined(_MSC_VER) || (defined(__MINGW32__) && __MINGW64_VERSION_MAJOR >= 3) -// -- GODOT end -- +#ifdef _WIN32 FILE *fp = NULL; fopen_s(&fp, filename, "rb"); #else @@ -11978,7 +12113,11 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, if (ret != TINYEXR_SUCCESS) { if (err) { +#ifdef _WIN32 + (*err) = _strdup(err_str.c_str()); // may leak +#else (*err) = strdup(err_str.c_str()); // may leak +#endif } return ret; } @@ -12033,10 +12172,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers, return TINYEXR_ERROR_INVALID_ARGUMENT; } -// -- GODOT change for old MinGW on Travis CI -- -//#ifdef _WIN32 -#if defined(_MSC_VER) || (defined(__MINGW32__) && __MINGW64_VERSION_MAJOR >= 3) -// -- GODOT end -- +#ifdef _WIN32 FILE *fp = NULL; fopen_s(&fp, filename, "rb"); #else @@ -12136,10 +12272,7 @@ int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) { return TINYEXR_ERROR_INVALID_ARGUMENT; } -// -- GODOT change for old MinGW on Travis CI -- -//#ifdef _WIN32 -#if defined(_MSC_VER) || (defined(__MINGW32__) && __MINGW64_VERSION_MAJOR >= 3) -// -- GODOT end -- +#ifdef _WIN32 FILE *fp = NULL; fopen_s(&fp, filename, "rb"); #else @@ -12277,10 +12410,7 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images, return TINYEXR_ERROR_INVALID_ARGUMENT; } -// -- GODOT change for old MinGW on Travis CI -- -//#ifdef _WIN32 -#if defined(_MSC_VER) || (defined(__MINGW32__) && __MINGW64_VERSION_MAJOR >= 3) -// -- GODOT end -- +#ifdef _WIN32 FILE *fp = NULL; fopen_s(&fp, filename, "rb"); #else @@ -12313,8 +12443,8 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images, } int SaveEXR(const float *data, int width, int height, int components, - const char *outfilename) { - if (components == 3 || components == 4) { + const int save_as_fp16, const char *outfilename) { + if ((components == 1) || components == 3 || components == 4) { // OK } else { return TINYEXR_ERROR_INVALID_ARGUMENT; @@ -12333,18 +12463,24 @@ int SaveEXR(const float *data, int width, int height, int components, image.num_channels = components; std::vector<float> images[4]; - images[0].resize(static_cast<size_t>(width * height)); - images[1].resize(static_cast<size_t>(width * height)); - images[2].resize(static_cast<size_t>(width * height)); - images[3].resize(static_cast<size_t>(width * height)); - // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers - for (size_t i = 0; i < static_cast<size_t>(width * height); i++) { - images[0][i] = data[static_cast<size_t>(components) * i + 0]; - images[1][i] = data[static_cast<size_t>(components) * i + 1]; - images[2][i] = data[static_cast<size_t>(components) * i + 2]; - if (components == 4) { - images[3][i] = data[static_cast<size_t>(components) * i + 3]; + if (components == 1) { + images[0].resize(static_cast<size_t>(width * height)); + memcpy(images[0].data(), data, sizeof(float) * size_t(width * height)); + } else { + images[0].resize(static_cast<size_t>(width * height)); + images[1].resize(static_cast<size_t>(width * height)); + images[2].resize(static_cast<size_t>(width * height)); + images[3].resize(static_cast<size_t>(width * height)); + + // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers + for (size_t i = 0; i < static_cast<size_t>(width * height); i++) { + images[0][i] = data[static_cast<size_t>(components) * i + 0]; + images[1][i] = data[static_cast<size_t>(components) * i + 1]; + images[2][i] = data[static_cast<size_t>(components) * i + 2]; + if (components == 4) { + images[3][i] = data[static_cast<size_t>(components) * i + 3]; + } } } @@ -12354,10 +12490,12 @@ int SaveEXR(const float *data, int width, int height, int components, image_ptr[1] = &(images[2].at(0)); // B image_ptr[2] = &(images[1].at(0)); // G image_ptr[3] = &(images[0].at(0)); // R - } else { + } else if (components == 3) { image_ptr[0] = &(images[2].at(0)); // B image_ptr[1] = &(images[1].at(0)); // G image_ptr[2] = &(images[0].at(0)); // R + } else if (components == 1) { + image_ptr[0] = &(images[0].at(0)); // A } image.images = reinterpret_cast<unsigned char **>(image_ptr); @@ -12369,21 +12507,41 @@ int SaveEXR(const float *data, int width, int height, int components, sizeof(EXRChannelInfo) * static_cast<size_t>(header.num_channels))); // Must be (A)BGR order, since most of EXR viewers expect this channel order. if (components == 4) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); + strncpy_s(header.channels[1].name, "B", 255); + strncpy_s(header.channels[2].name, "G", 255); + strncpy_s(header.channels[3].name, "R", 255); +#else strncpy(header.channels[0].name, "A", 255); - header.channels[0].name[strlen("A")] = '\0'; strncpy(header.channels[1].name, "B", 255); - header.channels[1].name[strlen("B")] = '\0'; strncpy(header.channels[2].name, "G", 255); - header.channels[2].name[strlen("G")] = '\0'; strncpy(header.channels[3].name, "R", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; + header.channels[1].name[strlen("B")] = '\0'; + header.channels[2].name[strlen("G")] = '\0'; header.channels[3].name[strlen("R")] = '\0'; - } else { + } else if (components == 3) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "B", 255); + strncpy_s(header.channels[1].name, "G", 255); + strncpy_s(header.channels[2].name, "R", 255); +#else strncpy(header.channels[0].name, "B", 255); - header.channels[0].name[strlen("B")] = '\0'; strncpy(header.channels[1].name, "G", 255); - header.channels[1].name[strlen("G")] = '\0'; strncpy(header.channels[2].name, "R", 255); +#endif + header.channels[0].name[strlen("B")] = '\0'; + header.channels[1].name[strlen("G")] = '\0'; header.channels[2].name[strlen("R")] = '\0'; + } else { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); +#else + strncpy(header.channels[0].name, "A", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; } header.pixel_types = static_cast<int *>( @@ -12393,9 +12551,15 @@ int SaveEXR(const float *data, int width, int height, int components, for (int i = 0; i < header.num_channels; i++) { header.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image - header.requested_pixel_types[i] = - TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in - // .EXR + + if (save_as_fp16 > 0) { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format + } else { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e. + // no precision reduction) + } } const char *err; @@ -12411,9 +12575,5 @@ int SaveEXR(const float *data, int width, int height, int components, return ret; } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - #endif // TINYEXR_IMPLEMENTATION_DEIFNED #endif // TINYEXR_IMPLEMENTATION |