diff options
113 files changed, 1234 insertions, 1005 deletions
diff --git a/.travis.yml b/.travis.yml index 587e57c741..09d8cad07e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ env: global: - SCONS_CACHE=$HOME/.scons_cache - SCONS_CACHE_LIMIT=1024 - - OPTIONS="debug_symbols=no verbose=yes progress=no" + - OPTIONS="debug_symbols=no verbose=yes progress=no builtin_libpng=yes" - secure: "uch9QszCgsl1qVbuzY41P7S2hWL2IiNFV4SbAYRCdi0oJ9MIu+pVyrQdpf3+jG4rH6j4Rffl+sN17Zz4dIDDioFL1JwqyCqyCyswR8uACC0Rr8gr4Mi3+HIRbv+2s2P4cIQq41JM8FJe84k9jLEMGCGh69w+ibCWoWs74CokYVA=" cache: @@ -39,7 +39,7 @@ matrix: - ubuntu-toolchain-r-test packages: - &gcc8_deps [gcc-8, g++-8] - - &linux_deps [libasound2-dev, libfreetype6-dev, libgl1-mesa-dev, libglu1-mesa-dev, libx11-dev, libxcursor-dev, libxi-dev, libxinerama-dev, libxrandr-dev] + - &linux_deps [libasound2-dev, libgl1-mesa-dev, libglu1-mesa-dev, libx11-dev, libxcursor-dev, libxi-dev, libxinerama-dev, libxrandr-dev] - &linux_mono_deps [mono-devel, msbuild, nuget] coverity_scan: diff --git a/SConstruct b/SConstruct index 7358494123..a619ea0797 100644 --- a/SConstruct +++ b/SConstruct @@ -339,14 +339,13 @@ if selected_platform in platform_list: shadow_local_warning = ['-Wshadow-local'] if (env["warnings"] == 'extra'): - # FIXME: enable -Wclobbered once #26351 is fixed # Note: enable -Wimplicit-fallthrough for Clang (already part of -Wextra for GCC) # once we switch to C++11 or later (necessary for our FALLTHROUGH macro). env.Append(CCFLAGS=['-Wall', '-Wextra', '-Wno-unused-parameter'] + all_plus_warnings + shadow_local_warning) env.Append(CXXFLAGS=['-Wctor-dtor-privacy', '-Wnon-virtual-dtor']) if methods.using_gcc(env): - env.Append(CCFLAGS=['-Wno-clobbered', '-Walloc-zero', + env.Append(CCFLAGS=['-Walloc-zero', '-Wduplicated-branches', '-Wduplicated-cond', '-Wstringop-overflow=4', '-Wlogical-op']) env.Append(CXXFLAGS=['-Wnoexcept', '-Wplacement-new=1']) diff --git a/core/class_db.cpp b/core/class_db.cpp index 0c844657a4..ec07ee98e2 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -666,10 +666,8 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName OBJTYPE_WLOCK; ClassInfo *type = classes.getptr(p_class); - if (!type) { - ERR_FAIL_COND(!type); - } + ERR_FAIL_COND(!type); if (type->constant_map.has(p_name)) { diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp index 83ff532aa4..93eaeb08c5 100644 --- a/core/io/file_access_buffered.cpp +++ b/core/io/file_access_buffered.cpp @@ -141,9 +141,7 @@ int FileAccessBuffered::get_buffer(uint8_t *p_dest, int p_length) const { int left = cache_data_left(); if (left == 0) { - if (to_read > 0) { - file.offset += to_read; - }; + file.offset += to_read; return total_read; }; if (left < 0) { diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 420e48f839..3d87131b51 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -234,6 +234,41 @@ Array IP::_get_local_addresses() const { return addresses; } +Array IP::_get_local_interfaces() const { + + Array results; + Map<String, Interface_Info> interfaces; + get_local_interfaces(&interfaces); + for (Map<String, Interface_Info>::Element *E = interfaces.front(); E; E = E->next()) { + Interface_Info &c = E->get(); + Dictionary rc; + rc["name"] = c.name; + rc["friendly"] = c.name_friendly; + rc["index"] = c.index; + + Array ips; + for (const List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) { + ips.push_front(F->get()); + } + rc["addresses"] = ips; + + results.push_front(rc); + } + + return results; +} + +void IP::get_local_addresses(List<IP_Address> *r_addresses) const { + + Map<String, Interface_Info> interfaces; + get_local_interfaces(&interfaces); + for (Map<String, Interface_Info>::Element *E = interfaces.front(); E; E = E->next()) { + for (const List<IP_Address>::Element *F = E->get().ip_addresses.front(); F; F = F->next()) { + r_addresses->push_front(F->get()); + } + } +} + void IP::_bind_methods() { ClassDB::bind_method(D_METHOD("resolve_hostname", "host", "ip_type"), &IP::resolve_hostname, DEFVAL(IP::TYPE_ANY)); @@ -242,6 +277,7 @@ void IP::_bind_methods() { ClassDB::bind_method(D_METHOD("get_resolve_item_address", "id"), &IP::get_resolve_item_address); ClassDB::bind_method(D_METHOD("erase_resolve_item", "id"), &IP::erase_resolve_item); ClassDB::bind_method(D_METHOD("get_local_addresses"), &IP::_get_local_addresses); + ClassDB::bind_method(D_METHOD("get_local_interfaces"), &IP::_get_local_interfaces); ClassDB::bind_method(D_METHOD("clear_cache", "hostname"), &IP::clear_cache, DEFVAL("")); BIND_ENUM_CONSTANT(RESOLVER_STATUS_NONE); diff --git a/core/io/ip.h b/core/io/ip.h index ead71ebb54..59b18ef986 100644 --- a/core/io/ip.h +++ b/core/io/ip.h @@ -73,16 +73,25 @@ protected: virtual IP_Address _resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY) = 0; Array _get_local_addresses() const; + Array _get_local_interfaces() const; static IP *(*_create)(); public: + struct Interface_Info { + String name; + String name_friendly; + String index; + List<IP_Address> ip_addresses; + }; + IP_Address resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY); // async resolver hostname ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY); ResolverStatus get_resolve_item_status(ResolverID p_id) const; IP_Address get_resolve_item_address(ResolverID p_id) const; - virtual void get_local_addresses(List<IP_Address> *r_addresses) const = 0; + virtual void get_local_addresses(List<IP_Address> *r_addresses) const; + virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const = 0; void erase_resolve_item(ResolverID p_id); void clear_cache(const String &p_hostname = ""); diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 763a5fbb9a..9305afac5f 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -40,6 +40,9 @@ IP_Address::operator Variant() const { IP_Address::operator String() const { + if (wildcard) + return "*"; + if (!valid) return ""; diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index d1b6b82cf0..7494603462 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -103,10 +103,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int const uint8_t *buf = p_buffer; int len = p_len; - if (len < 4) { - - ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); - } + ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); uint32_t type = decode_uint32(buf); diff --git a/core/io/net_socket.h b/core/io/net_socket.h index 94e7ef6f75..3bc1369487 100644 --- a/core/io/net_socket.h +++ b/core/io/net_socket.h @@ -74,6 +74,8 @@ public: virtual void set_ipv6_only_enabled(bool p_enabled) = 0; virtual void set_tcp_no_delay_enabled(bool p_enabled) = 0; virtual void set_reuse_address_enabled(bool p_enabled) = 0; + virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name) = 0; + virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) = 0; }; #endif // NET_SOCKET_H diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index 5912b8df94..7e9471c053 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -37,6 +37,27 @@ void PacketPeerUDP::set_blocking_mode(bool p_enable) { blocking = p_enable; } +Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_if_name) { + + ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); + ERR_FAIL_COND_V(!p_multi_address.is_valid(), ERR_INVALID_PARAMETER); + + if (!_sock->is_open()) { + IP::Type ip_type = p_multi_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; + Error err = _sock->open(NetSocket::TYPE_UDP, ip_type); + ERR_FAIL_COND_V(err != OK, err); + _sock->set_blocking_enabled(false); + } + return _sock->join_multicast_group(p_multi_address, p_if_name); +} + +Error PacketPeerUDP::leave_multicast_group(IP_Address p_multi_address, String p_if_name) { + + ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); + ERR_FAIL_COND_V(!_sock->is_open(), ERR_UNCONFIGURED); + return _sock->leave_multicast_group(p_multi_address, p_if_name); +} + String PacketPeerUDP::_get_packet_ip() const { return get_packet_address(); @@ -237,6 +258,8 @@ void PacketPeerUDP::_bind_methods() { ClassDB::bind_method(D_METHOD("get_packet_ip"), &PacketPeerUDP::_get_packet_ip); ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port); ClassDB::bind_method(D_METHOD("set_dest_address", "host", "port"), &PacketPeerUDP::_set_dest_address); + ClassDB::bind_method(D_METHOD("join_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::join_multicast_group); + ClassDB::bind_method(D_METHOD("leave_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::leave_multicast_group); } PacketPeerUDP::PacketPeerUDP() : diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h index 0593137604..068bd5cd5a 100644 --- a/core/io/packet_peer_udp.h +++ b/core/io/packet_peer_udp.h @@ -77,6 +77,8 @@ public: Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); int get_available_packet_count() const; int get_max_packet_size() const; + Error join_multicast_group(IP_Address p_multi_address, String p_if_name); + Error leave_multicast_group(IP_Address p_multi_address, String p_if_name); PacketPeerUDP(); ~PacketPeerUDP(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index f25abc4aab..aef2dcfff3 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -991,10 +991,7 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(cons Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (err != OK) { - - ERR_FAIL_COND_V(err != OK, Ref<ResourceInteractiveLoader>()); - } + ERR_FAIL_COND_V(err != OK, Ref<ResourceInteractiveLoader>()); Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); String path = p_original_path != "" ? p_original_path : p_path; @@ -1129,9 +1126,8 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons Error err; f = FileAccess::open(p_path, FileAccess::READ, &err); - if (err != OK) { - ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); - } + + ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); Ref<ResourceInteractiveLoaderBinary> ria = memnew(ResourceInteractiveLoaderBinary); ria->local_path = ProjectSettings::get_singleton()->localize_path(p_path); diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index f55af5a96a..82527d3f38 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -486,9 +486,7 @@ Error XMLParser::open(const String &p_path) { Error err; FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &err); - if (err) { - ERR_FAIL_COND_V(err != OK, err); - } + ERR_FAIL_COND_V(err != OK, err); length = file->get_len(); ERR_FAIL_COND_V(length < 1, ERR_FILE_CORRUPT); diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 079f51bada..913caf6584 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -600,9 +600,8 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err if (!f) { if (r_error) { // if error requested, do not throw error return Vector<uint8_t>(); - } else { - ERR_FAIL_COND_V(!f, Vector<uint8_t>()); } + ERR_FAIL_COND_V(!f, Vector<uint8_t>()); } Vector<uint8_t> data; data.resize(f->get_len()); @@ -621,9 +620,8 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { if (err != OK) { if (r_error) { return String(); - } else { - ERR_FAIL_COND_V(err != OK, String()); } + ERR_FAIL_COND_V(err != OK, String()); } String ret; diff --git a/core/os/os.h b/core/os/os.h index 514e1e2ad3..1b19ddff26 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -222,6 +222,8 @@ public: virtual bool is_window_maximized() const { return true; } virtual void set_window_always_on_top(bool p_enabled) {} virtual bool is_window_always_on_top() const { return false; } + virtual void set_console_visible(bool p_enabled) {} + virtual bool is_console_visible() const { return false; } virtual void request_attention() {} virtual void center_window(); diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp index a283d8db1d..11a3be89bd 100644 --- a/core/pool_allocator.cpp +++ b/core/pool_allocator.cpp @@ -500,9 +500,7 @@ void *PoolAllocator::get(ID p_mem) { if (!needs_locking) { Entry *e = get_entry(p_mem); - if (!e) { - ERR_FAIL_COND_V(!e, NULL); - }; + ERR_FAIL_COND_V(!e, NULL); return &pool[e->pos]; } diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index 5ea993f83d..ff91db2e28 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -238,6 +238,9 @@ <member name="current_animation_position" type="float" setter="" getter="get_current_animation_position"> The position (in seconds) of the currently playing animation. </member> + <member name="method_call_mode" type="int" setter="set_method_call_mode" getter="get_method_call_mode" enum="AnimationPlayer.AnimationMethodCallMode"> + The call mode to use for Call Method tracks. Default value: [code]ANIMATION_METHOD_CALL_DEFERRED[/code]. + </member> <member name="playback_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> @@ -293,5 +296,11 @@ <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessMode"> Do not process animation. Use the 'advance' method to process the animation manually. </constant> + <constant name="ANIMATION_METHOD_CALL_DEFERRED" value="0" enum="AnimationMethodCallMode"> + Batch method calls during the animation process, then do the calls after events are processed. This avoids bugs involving deleting nodes or modifying the AnimationPlayer while playing. + </constant> + <constant name="ANIMATION_METHOD_CALL_IMMEDIATE" value="1" enum="AnimationMethodCallMode"> + Make method calls immediately when reached in the animation. + </constant> </constants> </class> diff --git a/doc/classes/AudioEffectPitchShift.xml b/doc/classes/AudioEffectPitchShift.xml index 7d6c5f2b20..8c22afb40f 100644 --- a/doc/classes/AudioEffectPitchShift.xml +++ b/doc/classes/AudioEffectPitchShift.xml @@ -12,10 +12,26 @@ <methods> </methods> <members> + <member name="fft_size" type="int" setter="set_fft_size" getter="get_fft_size" enum="AudioEffectPitchShift.FFT_Size"> + </member> + <member name="oversampling" type="int" setter="set_oversampling" getter="get_oversampling"> + </member> <member name="pitch_scale" type="float" setter="set_pitch_scale" getter="get_pitch_scale"> Pitch value. Can range from 0 (-1 octave) to 16 (+16 octaves). </member> </members> <constants> + <constant name="FFT_SIZE_256" value="0" enum="FFT_Size"> + </constant> + <constant name="FFT_SIZE_512" value="1" enum="FFT_Size"> + </constant> + <constant name="FFT_SIZE_1024" value="2" enum="FFT_Size"> + </constant> + <constant name="FFT_SIZE_2048" value="3" enum="FFT_Size"> + </constant> + <constant name="FFT_SIZE_4096" value="4" enum="FFT_Size"> + </constant> + <constant name="FFT_SIZE_MAX" value="5" enum="FFT_Size"> + </constant> </constants> </class> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 1fefc719b7..0ab91e9621 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -45,14 +45,14 @@ <member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha"> If [code]true[/code], shows an alpha channel slider (transparency). </member> - <member name="presets_enabled" type="bool" setter="set_presets_enabled" getter="are_presets_enabled"> - </member> - <member name="presets_visible" type="bool" setter="set_presets_visible" getter="are_presets_visible"> - </member> <member name="hsv_mode" type="bool" setter="set_hsv_mode" getter="is_hsv_mode"> If [code]true[/code], allows to edit color with Hue/Saturation/Value sliders. [b]Note:[/b] Cannot be enabled if raw mode is on. </member> + <member name="presets_enabled" type="bool" setter="set_presets_enabled" getter="are_presets_enabled"> + </member> + <member name="presets_visible" type="bool" setter="set_presets_visible" getter="are_presets_visible"> + </member> <member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode"> If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). [b]Note:[/b] Cannot be enabled if hsv mode is on. diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index ac46d34198..d446363a83 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -85,14 +85,16 @@ </return> <description> Returns the current engine version information in a Dictionary. - "major" - Holds the major version number as an int - "minor" - Holds the minor version number as an int - "patch" - Holds the patch version number as an int - "hex" - Holds the full version number encoded as an hexadecimal int with one byte (2 places) per number (see example below) - "status" - Holds the status (e.g. "beta", "rc1", "rc2", ... "stable") as a String - "build" - Holds the build name (e.g. "custom-build") as a String - "string" - major + minor + patch + status + build in a single String - The "hex" value is encoded as follows, from left to right: one byte for the major, one byte for the minor, one byte for the patch version. For example, "3.1.12" would be [code]0x03010C[/code]. Note that it's still an int internally, and printing it will give you its decimal representation, which is not particularly meaningful. Use hexadecimal literals for easy version comparisons from code: + [code]major[/code] - Holds the major version number as an int + [code]minor[/code] - Holds the minor version number as an int + [code]patch[/code] - Holds the patch version number as an int + [code]hex[/code] - Holds the full version number encoded as an hexadecimal int with one byte (2 places) per number (see example below) + [code]status[/code] - Holds the status (e.g. "beta", "rc1", "rc2", ... "stable") as a String + [code]build[/code] - Holds the build name (e.g. "custom_build") as a String + [code]hash[/code] - Holds the full Git commit hash as a String + [code]year[/code] - Holds the year the version was released in as an int + [code]string[/code] - [code]major[/code] + [code]minor[/code] + [code]patch[/code] + [code]status[/code] + [code]build[/code] in a single String + The [code]hex[/code] value is encoded as follows, from left to right: one byte for the major, one byte for the minor, one byte for the patch version. For example, "3.1.12" would be [code]0x03010C[/code]. Note that it's still an int internally, and printing it will give you its decimal representation, which is not particularly meaningful. Use hexadecimal literals for easy version comparisons from code: [codeblock] if Engine.get_version_info().hex >= 0x030200: # do things specific to version 3.2 or later diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml index 3616a9ec50..65b1700333 100644 --- a/doc/classes/IP.xml +++ b/doc/classes/IP.xml @@ -34,6 +34,22 @@ Returns all of the user's current IPv4 and IPv6 addresses as an array. </description> </method> + <method name="get_local_interfaces" qualifiers="const"> + <return type="Array"> + </return> + <description> + Returns all network adapters as an array. + Each adapter is a dictionary of the form: + [codeblock] + { + "index": "1", # Interface index. + "name": "eth0", # Interface name. + "friendly": "Ethernet One", # A friendly name (might be empty). + "addresses": ["192.168.1.101"], # An array of IP addresses associated to this interface. + } + [/codeblock] + </description> + </method> <method name="get_resolve_item_address" qualifiers="const"> <return type="String"> </return> diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml index 9843c16108..376818fb86 100644 --- a/doc/classes/PacketPeerUDP.xml +++ b/doc/classes/PacketPeerUDP.xml @@ -37,6 +37,29 @@ Returns whether this [PacketPeerUDP] is listening. </description> </method> + <method name="join_multicast_group"> + <return type="int" enum="Error"> + </return> + <argument index="0" name="multicast_address" type="String"> + </argument> + <argument index="1" name="interface_name" type="String"> + </argument> + <description> + Join the multicast group specified by [code]multicast_address[/code] using the interface identified by [code]interface_name[/code]. + You can join the same multicast group with multiple interfaces. Use [method IP.get_local_interfaces] to know which are available. + </description> + </method> + <method name="leave_multicast_group"> + <return type="int" enum="Error"> + </return> + <argument index="0" name="multicast_address" type="String"> + </argument> + <argument index="1" name="interface_name" type="String"> + </argument> + <description> + Remove the interface identified by [code]interface_name[/code] from the multicast group specified by [code]multicast_address[/code]. + </description> + </method> <method name="listen"> <return type="int" enum="Error"> </return> diff --git a/doc/classes/ReferenceRect.xml b/doc/classes/ReferenceRect.xml index 0e19e35e58..f6025fe2f9 100644 --- a/doc/classes/ReferenceRect.xml +++ b/doc/classes/ReferenceRect.xml @@ -4,7 +4,7 @@ Reference frame for GUI. </brief_description> <description> - Reference frame for GUI. It's just like an empty control, except a red box is displayed while editing around its size at all times. + Reference frame for GUI. It's just like an empty control, except an outline border [member border_color] is displayed while editing around its size at all times. </description> <tutorials> </tutorials> @@ -12,6 +12,7 @@ </methods> <members> <member name="border_color" type="Color" setter="set_border_color" getter="get_border_color"> + Determines the border [Color] of the [ReferenceRect]. </member> </members> <constants> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index ff0572f384..6395fe2ce8 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -388,6 +388,18 @@ Converts a string containing a hexadecimal number into an integer. </description> </method> + <method name="http_escape"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="http_unescape"> + <return type="String"> + </return> + <description> + </description> + </method> <method name="insert"> <return type="String"> </return> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 8139da3a4c..e818d753d8 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -44,6 +44,12 @@ Returns if the given line is foldable, that is, it has indented lines right below it. </description> </method> + <method name="center_viewport_to_cursor"> + <return type="void"> + </return> + <description> + </description> + </method> <method name="clear_colors"> <return type="void"> </return> diff --git a/doc/classes/VisualShaderNodeGroupBase.xml b/doc/classes/VisualShaderNodeGroupBase.xml index 37d48956f6..c2e9b9503b 100644 --- a/doc/classes/VisualShaderNodeGroupBase.xml +++ b/doc/classes/VisualShaderNodeGroupBase.xml @@ -109,6 +109,14 @@ <description> </description> </method> + <method name="is_valid_port_name" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> <method name="remove_input_port"> <return type="void"> </return> diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 418be136b8..9fe7e43b43 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -4526,9 +4526,7 @@ void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene ERR_FAIL_COND(!inst); } break; default: { - if (!inst) { - ERR_FAIL(); - } + ERR_FAIL(); } } @@ -4573,15 +4571,10 @@ void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerSc ERR_FAIL_COND(!inst); } break; default: { - - if (!inst) { - ERR_FAIL(); - } + ERR_FAIL(); } } - ERR_FAIL_COND(!inst); - inst->instance_list.remove(&p_instance->dependency_item); } diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 30aa22732c..1f3af2f885 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -327,9 +327,6 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun uint32_t buffer_ofs = 0; //vertex -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index c7ef5cded4..b3a1d32bf4 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -4297,7 +4297,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS]; use_mrt = use_mrt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW; - use_mrt = use_mrt && env && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS); + use_mrt = use_mrt && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS); glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 352e3b7356..96094dd0ad 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -6709,9 +6709,7 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene ERR_FAIL_COND(!inst); } break; default: { - if (!inst) { - ERR_FAIL(); - } + ERR_FAIL(); } } @@ -6756,15 +6754,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base, RasterizerSc ERR_FAIL_COND(!inst); } break; default: { - - if (!inst) { - ERR_FAIL(); - } + ERR_FAIL(); } } - ERR_FAIL_COND(!inst); - inst->instance_list.remove(&p_instance->dependency_item); } diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 0bf432c78a..f257fafd93 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -32,186 +32,26 @@ #include "core/os/os.h" #include "core/print_string.h" +#include "drivers/png/png_driver_common.h" #include <string.h> -void ImageLoaderPNG::_read_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) { - - FileAccess *f = (FileAccess *)png_get_io_ptr(png_ptr); - f->get_buffer((uint8_t *)data, p_length); -} - -/* -png_structp png_ptr = png_create_read_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); -*/ -static png_voidp _png_malloc_fn(png_structp png_ptr, png_size_t size) { - - return memalloc(size); -} - -static void _png_free_fn(png_structp png_ptr, png_voidp ptr) { - - memfree(ptr); -} - -static void _png_error_function(png_structp, png_const_charp text) { - - ERR_PRINT(text); -} - -static void _png_warn_function(png_structp, png_const_charp text) { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - if (String(text).begins_with("iCCP")) return; // silences annoying spam emitted to output every time the user opened assetlib - } -#endif - WARN_PRINT(text); -} - -typedef void(PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); - -Error ImageLoaderPNG::_load_image(void *rf_up, png_rw_ptr p_func, Ref<Image> p_image) { - - png_structp png; - png_infop info; - - //png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); - - png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, _png_error_function, _png_warn_function, (png_voidp)NULL, - _png_malloc_fn, _png_free_fn); - - ERR_FAIL_COND_V(!png, ERR_OUT_OF_MEMORY); - - info = png_create_info_struct(png); - if (!info) { - png_destroy_read_struct(&png, NULL, NULL); - ERR_PRINT("Out of Memory"); - return ERR_OUT_OF_MEMORY; - } - - if (setjmp(png_jmpbuf(png))) { - - png_destroy_read_struct(&png, NULL, NULL); - ERR_PRINT("PNG Corrupted"); - return ERR_FILE_CORRUPT; - } - - png_set_read_fn(png, (void *)rf_up, p_func); - - png_uint_32 width, height; - int depth, color; - - png_read_info(png, info); - png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); - - //https://svn.gov.pt/projects/ccidadao/repository/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImage/PluginPNG.cpp - //png_get_text(png,info,) - /* - printf("Image width:%i\n", width); - printf("Image Height:%i\n", height); - printf("Bit depth:%i\n", depth); - printf("Color type:%i\n", color); - */ - - bool update_info = false; - - if (depth < 8) { //only bit dept 8 per channel is handled - - png_set_packing(png); - update_info = true; - }; - - if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png); - update_info = true; - } - - if (depth > 8) { - png_set_strip_16(png); - update_info = true; - } - - if (png_get_valid(png, info, PNG_INFO_tRNS)) { - //png_set_expand_gray_1_2_4_to_8(png); - png_set_tRNS_to_alpha(png); - update_info = true; - } - - if (update_info) { - png_read_update_info(png, info); - png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); - } - - int components = 0; - - Image::Format fmt; - switch (color) { - - case PNG_COLOR_TYPE_GRAY: { - - fmt = Image::FORMAT_L8; - components = 1; - } break; - case PNG_COLOR_TYPE_GRAY_ALPHA: { - - fmt = Image::FORMAT_LA8; - components = 2; - } break; - case PNG_COLOR_TYPE_RGB: { - - fmt = Image::FORMAT_RGB8; - components = 3; - } break; - case PNG_COLOR_TYPE_RGB_ALPHA: { - - fmt = Image::FORMAT_RGBA8; - components = 4; - } break; - default: { +Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { - ERR_PRINT("INVALID PNG TYPE"); - png_destroy_read_struct(&png, &info, NULL); - return ERR_UNAVAILABLE; - } break; + const size_t buffer_size = f->get_len(); + PoolVector<uint8_t> file_buffer; + Error err = file_buffer.resize(buffer_size); + if (err) { + f->close(); + return err; } - - //int rowsize = png_get_rowbytes(png, info); - int rowsize = components * width; - - PoolVector<uint8_t> dstbuff; - - dstbuff.resize(rowsize * height); - - PoolVector<uint8_t>::Write dstbuff_write = dstbuff.write(); - - uint8_t *data = dstbuff_write.ptr(); - - uint8_t **row_p = memnew_arr(uint8_t *, height); - - for (unsigned int i = 0; i < height; i++) { - row_p[i] = &data[components * width * i]; + { + PoolVector<uint8_t>::Write writer = file_buffer.write(); + f->get_buffer(writer.ptr(), buffer_size); + f->close(); } - - png_read_image(png, (png_bytep *)row_p); - - memdelete_arr(row_p); - - p_image->create(width, height, 0, fmt, dstbuff); - - png_destroy_read_struct(&png, &info, NULL); - - return OK; -} - -Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { - - Error err = _load_image(f, _read_png_data, p_image); - f->close(); - - return err; + PoolVector<uint8_t>::Read reader = file_buffer.read(); + return PNGDriverCommon::png_to_image(reader.ptr(), buffer_size, p_image); } void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const { @@ -219,178 +59,53 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const p_extensions->push_back("png"); } -struct PNGReadStatus { - - uint32_t offset; - uint32_t size; - const unsigned char *image; -}; - -static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t p_length) { - - PNGReadStatus *rstatus; - rstatus = (PNGReadStatus *)png_get_io_ptr(png_ptr); - - png_size_t to_read = MIN(p_length, rstatus->size - rstatus->offset); - memcpy(data, &rstatus->image[rstatus->offset], to_read); - rstatus->offset += to_read; - - if (to_read < p_length) { - memset(&data[to_read], 0, p_length - to_read); - } -} - -static Ref<Image> _load_mem_png(const uint8_t *p_png, int p_size) { - - PNGReadStatus prs; - prs.image = p_png; - prs.offset = 0; - prs.size = p_size; +Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) { Ref<Image> img; img.instance(); - Error err = ImageLoaderPNG::_load_image(&prs, user_read_data, img); + + Error err = PNGDriverCommon::png_to_image(p_png, p_size, img); ERR_FAIL_COND_V(err, Ref<Image>()); return img; } -static Ref<Image> _lossless_unpack_png(const PoolVector<uint8_t> &p_data) { +Ref<Image> ImageLoaderPNG::lossless_unpack_png(const PoolVector<uint8_t> &p_data) { - int len = p_data.size(); + const int len = p_data.size(); ERR_FAIL_COND_V(len < 4, Ref<Image>()); PoolVector<uint8_t>::Read r = p_data.read(); ERR_FAIL_COND_V(r[0] != 'P' || r[1] != 'N' || r[2] != 'G' || r[3] != ' ', Ref<Image>()); - return _load_mem_png(&r[4], len - 4); -} - -static void _write_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) { - - PoolVector<uint8_t> &v = *(PoolVector<uint8_t> *)png_get_io_ptr(png_ptr); - int vs = v.size(); - - v.resize(vs + p_length); - PoolVector<uint8_t>::Write w = v.write(); - copymem(&w[vs], data, p_length); + return load_mem_png(&r[4], len - 4); } -static PoolVector<uint8_t> _lossless_pack_png(const Ref<Image> &p_image) { - - Ref<Image> img = p_image->duplicate(); - - if (img->is_compressed()) - img->decompress(); - - ERR_FAIL_COND_V(img->is_compressed(), PoolVector<uint8_t>()); - - png_structp png_ptr; - png_infop info_ptr; - png_bytep *row_pointers; - - /* initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); +PoolVector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) { - ERR_FAIL_COND_V(!png_ptr, PoolVector<uint8_t>()); + PoolVector<uint8_t> out_buffer; - info_ptr = png_create_info_struct(png_ptr); - - ERR_FAIL_COND_V(!info_ptr, PoolVector<uint8_t>()); - - if (setjmp(png_jmpbuf(png_ptr))) { + // add Godot's own "PNG " prefix + if (out_buffer.resize(4) != OK) { ERR_FAIL_V(PoolVector<uint8_t>()); } - PoolVector<uint8_t> ret; - ret.push_back('P'); - ret.push_back('N'); - ret.push_back('G'); - ret.push_back(' '); - png_set_write_fn(png_ptr, &ret, _write_png_data, NULL); - - /* write header */ - if (setjmp(png_jmpbuf(png_ptr))) { - ERR_FAIL_V(PoolVector<uint8_t>()); + // scope for writer lifetime + { + // must be closed before call to image_to_png + PoolVector<uint8_t>::Write writer = out_buffer.write(); + copymem(writer.ptr(), "PNG ", 4); } - int pngf = 0; - int cs = 0; - - switch (img->get_format()) { - - case Image::FORMAT_L8: { - - pngf = PNG_COLOR_TYPE_GRAY; - cs = 1; - } break; - case Image::FORMAT_LA8: { - - pngf = PNG_COLOR_TYPE_GRAY_ALPHA; - cs = 2; - } break; - case Image::FORMAT_RGB8: { - - pngf = PNG_COLOR_TYPE_RGB; - cs = 3; - } break; - case Image::FORMAT_RGBA8: { - - pngf = PNG_COLOR_TYPE_RGB_ALPHA; - cs = 4; - } break; - default: { - - if (img->detect_alpha()) { - - img->convert(Image::FORMAT_RGBA8); - pngf = PNG_COLOR_TYPE_RGB_ALPHA; - cs = 4; - } else { - - img->convert(Image::FORMAT_RGB8); - pngf = PNG_COLOR_TYPE_RGB; - cs = 3; - } - } - } - - int w = img->get_width(); - int h = img->get_height(); - png_set_IHDR(png_ptr, info_ptr, w, h, - 8, pngf, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_write_info(png_ptr, info_ptr); - - /* write bytes */ - if (setjmp(png_jmpbuf(png_ptr))) { + Error err = PNGDriverCommon::image_to_png(p_image, out_buffer); + if (err) { ERR_FAIL_V(PoolVector<uint8_t>()); } - PoolVector<uint8_t>::Read r = img->get_data().read(); - - row_pointers = (png_bytep *)memalloc(sizeof(png_bytep) * h); - for (int i = 0; i < h; i++) { - - row_pointers[i] = (png_bytep)&r[i * w * cs]; - } - png_write_image(png_ptr, row_pointers); - - memfree(row_pointers); - - /* end write */ - if (setjmp(png_jmpbuf(png_ptr))) { - - ERR_FAIL_V(PoolVector<uint8_t>()); - } - - png_write_end(png_ptr, NULL); - - return ret; + return out_buffer; } ImageLoaderPNG::ImageLoaderPNG() { - Image::_png_mem_loader_func = _load_mem_png; - Image::lossless_unpacker = _lossless_unpack_png; - Image::lossless_packer = _lossless_pack_png; + Image::_png_mem_loader_func = load_mem_png; + Image::lossless_unpacker = lossless_unpack_png; + Image::lossless_packer = lossless_pack_png; } diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index c3951979c3..cc789f95d6 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.h @@ -33,17 +33,16 @@ #include "core/io/image_loader.h" -#include <png.h> - /** @author Juan Linietsky <reduzio@gmail.com> */ class ImageLoaderPNG : public ImageFormatLoader { - - static void _read_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length); +private: + static PoolVector<uint8_t> lossless_pack_png(const Ref<Image> &p_image); + static Ref<Image> lossless_unpack_png(const PoolVector<uint8_t> &p_data); + static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size); public: - static Error _load_image(void *rf_up, png_rw_ptr p_func, Ref<Image> p_image); virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderPNG(); diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp new file mode 100644 index 0000000000..0e849bf2fe --- /dev/null +++ b/drivers/png/png_driver_common.cpp @@ -0,0 +1,205 @@ +/*************************************************************************/ +/* png_driver_common.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "png_driver_common.h" + +#include "core/os/os.h" + +#include <png.h> +#include <string.h> + +namespace PNGDriverCommon { + +// Print any warnings. +// On error, set explain and return true. +// Call should be wrapped in ERR_FAIL_COND +static bool check_error(const png_image &image) { + const png_uint_32 failed = PNG_IMAGE_FAILED(image); + if (failed & PNG_IMAGE_ERROR) { + ERR_EXPLAINC(image.message); + return true; + } else if (failed) { +#ifdef TOOLS_ENABLED + // suppress this warning, to avoid log spam when opening assetlib + const static char *const noisy = "iCCP: known incorrect sRGB profile"; + const Engine *const eng = Engine::get_singleton(); + if (eng && eng->is_editor_hint() && !strcmp(image.message, noisy)) { + return false; + } +#endif + WARN_PRINT(image.message); + } + return false; +} + +Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { + + png_image png_img; + zeromem(&png_img, sizeof(png_img)); + png_img.version = PNG_IMAGE_VERSION; + + // fetch image properties + int success = png_image_begin_read_from_memory(&png_img, p_source, p_size); + ERR_FAIL_COND_V(check_error(png_img), ERR_FILE_CORRUPT); + ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT); + + // flags to be masked out of input format to give target format + const png_uint_32 format_mask = ~( + // convert component order to RGBA + PNG_FORMAT_FLAG_BGR | PNG_FORMAT_FLAG_AFIRST + // convert 16 bit components to 8 bit + | PNG_FORMAT_FLAG_LINEAR + // convert indexed image to direct color + | PNG_FORMAT_FLAG_COLORMAP); + + png_img.format &= format_mask; + + Image::Format dest_format; + switch (png_img.format) { + case PNG_FORMAT_GRAY: + dest_format = Image::FORMAT_L8; + break; + case PNG_FORMAT_GA: + dest_format = Image::FORMAT_LA8; + break; + case PNG_FORMAT_RGB: + dest_format = Image::FORMAT_RGB8; + break; + case PNG_FORMAT_RGBA: + dest_format = Image::FORMAT_RGBA8; + break; + default: + png_image_free(&png_img); // only required when we return before finish_read + ERR_PRINT("Unsupported png format"); + return ERR_UNAVAILABLE; + } + + const png_uint_32 stride = PNG_IMAGE_ROW_STRIDE(png_img); + PoolVector<uint8_t> buffer; + Error err = buffer.resize(PNG_IMAGE_BUFFER_SIZE(png_img, stride)); + if (err) { + png_image_free(&png_img); // only required when we return before finish_read + return err; + } + PoolVector<uint8_t>::Write writer = buffer.write(); + + // read image data to buffer and release libpng resources + success = png_image_finish_read(&png_img, NULL, writer.ptr(), stride, NULL); + ERR_FAIL_COND_V(check_error(png_img), ERR_FILE_CORRUPT); + ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT); + + p_image->create(png_img.width, png_img.height, 0, dest_format, buffer); + + return OK; +} + +Error image_to_png(const Ref<Image> &p_image, PoolVector<uint8_t> &p_buffer) { + + Ref<Image> source_image = p_image->duplicate(); + + if (source_image->is_compressed()) + source_image->decompress(); + + ERR_FAIL_COND_V(source_image->is_compressed(), FAILED); + + png_image png_img; + zeromem(&png_img, sizeof(png_img)); + png_img.version = PNG_IMAGE_VERSION; + png_img.width = source_image->get_width(); + png_img.height = source_image->get_height(); + + switch (source_image->get_format()) { + case Image::FORMAT_L8: + png_img.format = PNG_FORMAT_GRAY; + break; + case Image::FORMAT_LA8: + png_img.format = PNG_FORMAT_GA; + break; + case Image::FORMAT_RGB8: + png_img.format = PNG_FORMAT_RGB; + break; + case Image::FORMAT_RGBA8: + png_img.format = PNG_FORMAT_RGBA; + break; + default: + if (source_image->detect_alpha()) { + source_image->convert(Image::FORMAT_RGBA8); + png_img.format = PNG_FORMAT_RGBA; + } else { + source_image->convert(Image::FORMAT_RGB8); + png_img.format = PNG_FORMAT_RGB; + } + } + + const PoolVector<uint8_t> image_data = source_image->get_data(); + const PoolVector<uint8_t>::Read reader = image_data.read(); + + // we may be passed a buffer with existing content we're expected to append to + const int buffer_offset = p_buffer.size(); + + const size_t png_size_estimate = PNG_IMAGE_PNG_SIZE_MAX(png_img); + + // try with estimated size + size_t compressed_size = png_size_estimate; + int success = 0; + { // scope writer lifetime + Error err = p_buffer.resize(buffer_offset + png_size_estimate); + ERR_FAIL_COND_V(err, err); + + PoolVector<uint8_t>::Write writer = p_buffer.write(); + success = png_image_write_to_memory(&png_img, &writer[buffer_offset], + &compressed_size, 0, reader.ptr(), 0, NULL); + ERR_FAIL_COND_V(check_error(png_img), FAILED); + } + if (!success) { + if (compressed_size <= png_size_estimate) { + // buffer was big enough, must be some other error + ERR_FAIL_V(FAILED); + } + + // write failed due to buffer size, resize and retry + Error err = p_buffer.resize(buffer_offset + compressed_size); + ERR_FAIL_COND_V(err, err); + + PoolVector<uint8_t>::Write writer = p_buffer.write(); + success = png_image_write_to_memory(&png_img, &writer[buffer_offset], + &compressed_size, 0, reader.ptr(), 0, NULL); + ERR_FAIL_COND_V(check_error(png_img), FAILED); + ERR_FAIL_COND_V(!success, FAILED); + } + + // trim buffer size to content + Error err = p_buffer.resize(buffer_offset + compressed_size); + ERR_FAIL_COND_V(err, err); + + return OK; +} + +} // namespace PNGDriverCommon diff --git a/editor/editor_name_dialog.cpp b/drivers/png/png_driver_common.h index 63a91a594c..3ff87759fb 100644 --- a/editor/editor_name_dialog.cpp +++ b/drivers/png/png_driver_common.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* editor_name_dialog.cpp */ +/* png_driver_common.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,66 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "editor_name_dialog.h" +#ifndef PNG_DRIVER_COMMON_H +#define PNG_DRIVER_COMMON_H -#include "core/class_db.h" -#include "core/os/keyboard.h" +#include "core/image.h" +#include "core/pool_vector.h" -void EditorNameDialog::_line_gui_input(const Ref<InputEvent> &p_event) { +namespace PNGDriverCommon { - Ref<InputEventKey> k = p_event; +// Attempt to load png from buffer (p_source, p_size) into p_image +Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image); - if (k.is_valid()) { +// Append p_image, as a png, to p_buffer. +// Contents of p_buffer is unspecified if error returned. +Error image_to_png(const Ref<Image> &p_image, PoolVector<uint8_t> &p_buffer); - if (!k->is_pressed()) - return; +} // namespace PNGDriverCommon - switch (k->get_scancode()) { - case KEY_KP_ENTER: - case KEY_ENTER: { - - if (get_hide_on_ok()) - hide(); - ok_pressed(); - accept_event(); - } break; - case KEY_ESCAPE: { - - hide(); - accept_event(); - } break; - } - } -} - -void EditorNameDialog::_post_popup() { - - ConfirmationDialog::_post_popup(); - name->clear(); - name->grab_focus(); -} - -void EditorNameDialog::ok_pressed() { - - if (name->get_text() != "") { - emit_signal("name_confirmed", name->get_text()); - } -} - -void EditorNameDialog::_bind_methods() { - - ClassDB::bind_method("_line_gui_input", &EditorNameDialog::_line_gui_input); - - ADD_SIGNAL(MethodInfo("name_confirmed", PropertyInfo(Variant::STRING, "name"))); -} - -EditorNameDialog::EditorNameDialog() { - makevb = memnew(VBoxContainer); - add_child(makevb); - name = memnew(LineEdit); - makevb->add_child(name); - name->set_margin(MARGIN_TOP, 5); - name->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5); - name->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5); - name->connect("gui_input", this, "_line_gui_input"); -} +#endif diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index 9e8043cbea..89e8ee32cc 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -32,17 +32,9 @@ #include "core/image.h" #include "core/os/file_access.h" -#include "core/project_settings.h" +#include "drivers/png/png_driver_common.h" #include "scene/resources/texture.h" -#include <png.h> - -static void _write_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) { - - FileAccess *f = (FileAccess *)png_get_io_ptr(png_ptr); - f->store_buffer((const uint8_t *)data, p_length); -} - Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { Ref<ImageTexture> texture = p_resource; @@ -55,129 +47,27 @@ Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32 Error err = save_image(p_path, img); - if (err == OK) { - } - return err; }; Error ResourceSaverPNG::save_image(const String &p_path, const Ref<Image> &p_img) { - Ref<Image> img = p_img->duplicate(); - - if (img->is_compressed()) - img->decompress(); - - ERR_FAIL_COND_V(img->is_compressed(), ERR_INVALID_PARAMETER); - - png_structp png_ptr; - png_infop info_ptr; - png_bytep *row_pointers; - - /* initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - ERR_FAIL_COND_V(!png_ptr, ERR_CANT_CREATE); + PoolVector<uint8_t> buffer; + Error err = PNGDriverCommon::image_to_png(p_img, buffer); + ERR_FAIL_COND_V(err, err); + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(err, err); - info_ptr = png_create_info_struct(png_ptr); + PoolVector<uint8_t>::Read reader = buffer.read(); - ERR_FAIL_COND_V(!info_ptr, ERR_CANT_CREATE); - - if (setjmp(png_jmpbuf(png_ptr))) { - ERR_FAIL_V(ERR_CANT_OPEN); - } - //change this - Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE, &err); - if (err) { - ERR_FAIL_V(err); - } - - png_set_write_fn(png_ptr, f, _write_png_data, NULL); - - /* write header */ - if (setjmp(png_jmpbuf(png_ptr))) { - ERR_FAIL_V(ERR_CANT_OPEN); + file->store_buffer(reader.ptr(), buffer.size()); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; } - int pngf = 0; - int cs = 0; - - switch (img->get_format()) { - - case Image::FORMAT_L8: { - - pngf = PNG_COLOR_TYPE_GRAY; - cs = 1; - } break; - case Image::FORMAT_LA8: { - - pngf = PNG_COLOR_TYPE_GRAY_ALPHA; - cs = 2; - } break; - case Image::FORMAT_RGB8: { - - pngf = PNG_COLOR_TYPE_RGB; - cs = 3; - } break; - case Image::FORMAT_RGBA8: { - - pngf = PNG_COLOR_TYPE_RGB_ALPHA; - cs = 4; - } break; - default: { - - if (img->detect_alpha()) { - - img->convert(Image::FORMAT_RGBA8); - pngf = PNG_COLOR_TYPE_RGB_ALPHA; - cs = 4; - } else { - - img->convert(Image::FORMAT_RGB8); - pngf = PNG_COLOR_TYPE_RGB; - cs = 3; - } - } - } - - int w = img->get_width(); - int h = img->get_height(); - png_set_IHDR(png_ptr, info_ptr, w, h, - 8, pngf, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_write_info(png_ptr, info_ptr); - - /* write bytes */ - if (setjmp(png_jmpbuf(png_ptr))) { - memdelete(f); - ERR_FAIL_V(ERR_CANT_OPEN); - } - - PoolVector<uint8_t>::Read r = img->get_data().read(); - - row_pointers = (png_bytep *)memalloc(sizeof(png_bytep) * h); - for (int i = 0; i < h; i++) { - - row_pointers[i] = (png_bytep)&r[i * w * cs]; - } - png_write_image(png_ptr, row_pointers); - - memfree(row_pointers); - - /* end write */ - if (setjmp(png_jmpbuf(png_ptr))) { - - memdelete(f); - ERR_FAIL_V(ERR_CANT_OPEN); - } - - png_write_end(png_ptr, NULL); - memdelete(f); - - /* cleanup heap allocation */ - png_destroy_write_struct(&png_ptr, &info_ptr); + file->close(); + memdelete(file); return OK; } @@ -186,6 +76,7 @@ bool ResourceSaverPNG::recognize(const RES &p_resource) const { return (p_resource.is_valid() && p_resource->is_class("ImageTexture")); } + void ResourceSaverPNG::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { if (Object::cast_to<Texture>(*p_resource)) { diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index b5feaabc32..39ca9a823e 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -56,6 +56,7 @@ #endif // MINGW hack #endif #else // UNIX +#include <net/if.h> #include <netdb.h> #ifdef ANDROID_ENABLED // We could drop this file once we up our API level to 24, @@ -77,6 +78,7 @@ static IP_Address _sockaddr2ip(struct sockaddr *p_addr) { IP_Address ip; + if (p_addr->sa_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)p_addr; ip.set_ipv4((uint8_t *)&(addr->sin_addr)); @@ -129,24 +131,42 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) { #if defined(UWP_ENABLED) -void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { +void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { using namespace Windows::Networking; using namespace Windows::Networking::Connectivity; + // Returns addresses, not interfaces. auto hostnames = NetworkInformation::GetHostNames(); for (int i = 0; i < hostnames->Size; i++) { - if (hostnames->GetAt(i)->Type == HostNameType::Ipv4 || hostnames->GetAt(i)->Type == HostNameType::Ipv6 && hostnames->GetAt(i)->IPInformation != nullptr) { + auto hostname = hostnames->GetAt(i); + + if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6) + continue; - r_addresses->push_back(IP_Address(String(hostnames->GetAt(i)->CanonicalName->Data()))); + String name = hostname->RawName->Data(); + Map<String, Interface_Info>::Element *E = r_interfaces->find(name); + if (!E) { + Interface_Info info; + info.name = name; + info.name_friendly = hostname->DisplayName->Data(); + info.index = 0; + E = r_interfaces->insert(name, info); + ERR_CONTINUE(!E); } + + Interface_Info &info = E->get(); + + IP_Address ip = IP_Address(hostname->CanonicalName->Data()); + info.ip_addresses.push_front(ip); } -}; +} + #else -void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { +void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { ULONG buf_size = 1024; IP_ADAPTER_ADDRESSES *addrs; @@ -173,29 +193,23 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { while (adapter != NULL) { + Interface_Info info; + info.name = adapter->AdapterName; + info.name_friendly = adapter->FriendlyName; + info.index = String::num_uint64(adapter->IfIndex); + IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress; while (address != NULL) { - - IP_Address ip; - - if (address->Address.lpSockaddr->sa_family == AF_INET) { - - SOCKADDR_IN *ipv4 = reinterpret_cast<SOCKADDR_IN *>(address->Address.lpSockaddr); - - ip.set_ipv4((uint8_t *)&(ipv4->sin_addr)); - r_addresses->push_back(ip); - - } else if (address->Address.lpSockaddr->sa_family == AF_INET6) { // ipv6 - - SOCKADDR_IN6 *ipv6 = reinterpret_cast<SOCKADDR_IN6 *>(address->Address.lpSockaddr); - - ip.set_ipv6(ipv6->sin6_addr.s6_addr); - r_addresses->push_back(ip); - }; - + int family = address->Address.lpSockaddr->sa_family; + if (family != AF_INET && family != AF_INET6) + continue; + info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr)); address = address->Next; - }; + } adapter = adapter->Next; + // Only add interface if it has at least one IP + if (info.ip_addresses.size() > 0) + r_interfaces->insert(info.name, info); }; memfree(addrs); @@ -205,7 +219,7 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { #else // UNIX -void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { +void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { struct ifaddrs *ifAddrStruct = NULL; struct ifaddrs *ifa = NULL; @@ -222,8 +236,18 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { if (family != AF_INET && family != AF_INET6) continue; - IP_Address ip = _sockaddr2ip(ifa->ifa_addr); - r_addresses->push_back(ip); + Map<String, Interface_Info>::Element *E = r_interfaces->find(ifa->ifa_name); + if (!E) { + Interface_Info info; + info.name = ifa->ifa_name; + info.name_friendly = ifa->ifa_name; + info.index = String::num_uint64(if_nametoindex(ifa->ifa_name)); + E = r_interfaces->insert(ifa->ifa_name, info); + ERR_CONTINUE(!E); + } + + Interface_Info &info = E->get(); + info.ip_addresses.push_front(_sockaddr2ip(ifa->ifa_addr)); } if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct); diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index e36535146e..f9bb626cc4 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.h @@ -43,7 +43,7 @@ class IP_Unix : public IP { static IP *_create_unix(); public: - virtual void get_local_addresses(List<IP_Address> *r_addresses) const; + virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const; static void make_default(); IP_Unix(); diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 75d51c8503..4bde7789e2 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -59,6 +59,14 @@ #define MSG_NOSIGNAL SO_NOSIGPIPE #endif +// BSD calls this flag IPV6_JOIN_GROUP +#if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP) +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif +#if !defined(IPV6_DROP_MEMBERSHIP) && defined(IPV6_LEAVE_GROUP) +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif + // Some custom defines to minimize ifdefs #define SOCK_EMPTY -1 #define SOCK_BUF(x) x @@ -227,6 +235,58 @@ bool NetSocketPosix::_can_use_ip(const IP_Address p_ip, const bool p_for_bind) c return true; } +_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) { + + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER); + + // Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4 + IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type; + // This needs to be the proper level for the multicast group, no matter if the socket is dual stacking. + int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; + int ret = -1; + + IP_Address if_ip; + uint32_t if_v6id = 0; + Map<String, IP::Interface_Info> if_info; + IP::get_singleton()->get_local_interfaces(&if_info); + for (Map<String, IP::Interface_Info>::Element *E = if_info.front(); E; E = E->next()) { + IP::Interface_Info &c = E->get(); + if (c.name != p_if_name) + continue; + + if_v6id = (uint32_t)c.index.to_int64(); + if (type == IP::TYPE_IPV6) + break; // IPv6 uses index. + + for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) { + if (!F->get().is_ipv4()) + continue; // Wrong IP type + if_ip = F->get(); + break; + } + break; + } + + if (level == IPPROTO_IP) { + ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER); + struct ip_mreq greq; + int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; + copymem(&greq.imr_multiaddr, p_ip.get_ipv4(), 4); + copymem(&greq.imr_interface, if_ip.get_ipv4(), 4); + ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq)); + } else { + struct ipv6_mreq greq; + int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; + copymem(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16); + greq.ipv6mr_interface = if_v6id; + ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq)); + } + ERR_FAIL_COND_V(ret != 0, FAILED); + + return OK; +} + void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) { _sock = p_sock; _ip_type = p_ip_type; @@ -421,7 +481,7 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { pfd.events = POLLOUT; break; case POLL_TYPE_IN_OUT: - pfd.events = POLLOUT || POLLIN; + pfd.events = POLLOUT | POLLIN; } int ret = ::poll(&pfd, 1, p_timeout); @@ -625,3 +685,11 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { ns->set_blocking_enabled(false); return Ref<NetSocket>(ns); } + +Error NetSocketPosix::join_multicast_group(const IP_Address &p_ip, String p_if_name) { + return _change_multicast_group(p_ip, p_if_name, true); +} + +Error NetSocketPosix::leave_multicast_group(const IP_Address &p_ip, String p_if_name) { + return _change_multicast_group(p_ip, p_if_name, false); +} diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index b7fb3fdc94..cf0412311d 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -60,6 +60,7 @@ private: NetError _get_socket_error(); void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream); + _FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add); protected: static NetSocket *_create_func(); @@ -93,6 +94,8 @@ public: virtual void set_tcp_no_delay_enabled(bool p_enabled); virtual void set_reuse_address_enabled(bool p_enabled); virtual void set_reuse_port_enabled(bool p_enabled); + virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name); + virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name); NetSocketPosix(); ~NetSocketPosix(); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 6e47fadb20..1bed5a9524 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1203,7 +1203,9 @@ AnimationTimelineEdit::AnimationTimelineEdit() { //////////////////////////////////// void AnimationTrackEdit::_notification(int p_what) { + if (p_what == NOTIFICATION_DRAW) { + if (animation.is_null()) return; ERR_FAIL_INDEX(track, animation->get_track_count()); @@ -1240,20 +1242,15 @@ void AnimationTrackEdit::_notification(int p_what) { int ofs = in_group ? check->get_width() : 0; //not the best reference for margin but.. check_rect = Rect2(Point2(ofs, int(get_size().height - check->get_height()) / 2), check->get_size()); - draw_texture(check, check_rect.position); - ofs += check->get_width() + hsep; Ref<Texture> type_icon = type_icons[animation->track_get_type(track)]; - draw_texture(type_icon, Point2(ofs, int(get_size().height - type_icon->get_height()) / 2)); ofs += type_icon->get_width() + hsep; NodePath path = animation->track_get_path(track); - Node *node = NULL; - if (root && root->has_node(path)) { node = root->get_node(path); } @@ -1308,12 +1305,11 @@ void AnimationTrackEdit::_notification(int p_what) { draw_line(Point2(limit, 0), Point2(limit, get_size().height), linecolor, Math::round(EDSCALE)); } - // KEYFAMES // + // KEYFRAMES // draw_bg(limit, get_size().width - timeline->get_buttons_width()); { - float scale = timeline->get_zoom_scale(); int limit_end = get_size().width - timeline->get_buttons_width(); @@ -1342,6 +1338,7 @@ void AnimationTrackEdit::_notification(int p_what) { draw_fg(limit, get_size().width - timeline->get_buttons_width()); // BUTTONS // + { Ref<Texture> wrap_icon[2] = { @@ -1566,7 +1563,18 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool if (p_x < p_clip_left || p_x > p_clip_right) return; - Vector2 ofs(p_x - type_icon->get_width() / 2, int(get_size().height - type_icon->get_height()) / 2); + Ref<Texture> icon_to_draw = p_selected ? selected_icon : type_icon; + + // Override type icon for invalid value keys, unless selected. + if (!p_selected && animation->track_get_type(track) == Animation::TYPE_VALUE) { + const Variant &v = animation->track_get_key_value(track, p_index); + Variant::Type valid_type = Variant::NIL; + if (!_is_value_key_valid(v, valid_type)) { + icon_to_draw = get_icon("KeyInvalid", "EditorIcons"); + } + } + + Vector2 ofs(p_x - icon_to_draw->get_width() / 2, int(get_size().height - icon_to_draw->get_height()) / 2); if (animation->track_get_type(track) == Animation::TYPE_METHOD) { Ref<Font> font = get_font("font", "Label"); @@ -1590,16 +1598,13 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool } text += ")"; - int limit = MAX(0, p_clip_right - p_x - type_icon->get_width()); + int limit = MAX(0, p_clip_right - p_x - icon_to_draw->get_width()); if (limit > 0) { - draw_string(font, Vector2(p_x + type_icon->get_width(), int(get_size().height - font->get_height()) / 2 + font->get_ascent()), text, color, limit); + draw_string(font, Vector2(p_x + icon_to_draw->get_width(), int(get_size().height - font->get_height()) / 2 + font->get_ascent()), text, color, limit); } } - if (p_selected) { - draw_texture(selected_icon, ofs); - } else { - draw_texture(type_icon, ofs); - } + + draw_texture(icon_to_draw, ofs); } //helper @@ -1764,6 +1769,27 @@ void AnimationTrackEdit::_path_entered(const String &p_text) { undo_redo->commit_action(); } +bool AnimationTrackEdit::_is_value_key_valid(const Variant &p_key_value, Variant::Type &r_valid_type) const { + + RES res; + Vector<StringName> leftover_path; + Node *node = root->get_node_and_resource(animation->track_get_path(track), res, leftover_path); + + Object *obj = NULL; + if (res.is_valid()) { + obj = res.ptr(); + } else if (node) { + obj = node; + } + + bool prop_exists = false; + if (obj) { + r_valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists); + } + + return (!prop_exists || Variant::can_convert(p_key_value.get_type(), r_valid_type)); +} + String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { if (check_rect.has_point(p_pos)) { @@ -1834,29 +1860,10 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { } break; case Animation::TYPE_VALUE: { - Variant v = animation->track_get_key_value(track, key_idx); - //text+="value: "+String(v)+"\n"; - - bool prop_exists = false; - Variant::Type valid_type = Variant::NIL; - Object *obj = NULL; - - RES res; - Vector<StringName> leftover_path; - Node *node = root->get_node_and_resource(animation->track_get_path(track), res, leftover_path); - - if (res.is_valid()) { - obj = res.ptr(); - } else if (node) { - obj = node; - } - - if (obj) { - valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists); - } - + const Variant &v = animation->track_get_key_value(track, key_idx); text += "Type: " + Variant::get_type_name(v.get_type()) + "\n"; - if (prop_exists && !Variant::can_convert(v.get_type(), valid_type)) { + Variant::Type valid_type = Variant::NIL; + if (!_is_value_key_valid(v, valid_type)) { text += "Value: " + String(v) + " (Invalid, expected type: " + Variant::get_type_name(valid_type) + ")\n"; } else { text += "Value: " + String(v) + "\n"; diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 1452d5519c..5f05c1de8c 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -31,6 +31,11 @@ #ifndef ANIMATION_TRACK_EDITOR_H #define ANIMATION_TRACK_EDITOR_H +#include "editor/editor_data.h" +#include "editor/editor_spin_slider.h" +#include "editor/property_editor.h" +#include "editor/property_selector.h" +#include "scene/animation/animation_cache.h" #include "scene/gui/control.h" #include "scene/gui/file_dialog.h" #include "scene/gui/menu_button.h" @@ -40,12 +45,6 @@ #include "scene/gui/tab_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" - -#include "editor/property_selector.h" -#include "editor_data.h" -#include "editor_spin_slider.h" -#include "property_editor.h" -#include "scene/animation/animation_cache.h" #include "scene/resources/animation.h" #include "scene_tree_editor.h" @@ -175,8 +174,9 @@ class AnimationTrackEdit : public Control { void _path_entered(const String &p_text); void _play_position_draw(); - mutable int dropping_at; + bool _is_value_key_valid(const Variant &p_key_value, Variant::Type &r_valid_type) const; + mutable int dropping_at; float insert_at_pos; bool moving_selection_attempt; int select_single_attempt; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 8b3c537fe3..848921d870 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1217,6 +1217,11 @@ void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { text_editor->select(p_line, p_begin, p_line, p_end); } +void CodeTextEditor::goto_line_centered(int p_line) { + goto_line(p_line); + text_editor->call_deferred("center_viewport_to_cursor"); +} + void CodeTextEditor::set_executing_line(int p_line) { text_editor->set_executing_line(p_line); } diff --git a/editor/code_editor.h b/editor/code_editor.h index ce219f340c..c0989f9704 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -219,6 +219,7 @@ public: void goto_line(int p_line); void goto_line_selection(int p_line, int p_begin, int p_end); + void goto_line_centered(int p_line); void set_executing_line(int p_line); void clear_executing_line(); diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp new file mode 100644 index 0000000000..01e4762196 --- /dev/null +++ b/editor/editor_layouts_dialog.cpp @@ -0,0 +1,138 @@ +/*************************************************************************/ +/* editor_layouts_dialog.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_layouts_dialog.h" +#include "core/class_db.h" +#include "core/io/config_file.h" +#include "core/os/keyboard.h" +#include "editor/editor_settings.h" +#include "scene/gui/item_list.h" +#include "scene/gui/line_edit.h" + +void EditorLayoutsDialog::_line_gui_input(const Ref<InputEvent> &p_event) { + Ref<InputEventKey> k = p_event; + + if (k.is_valid()) { + + if (!k->is_pressed()) + return; + + switch (k->get_scancode()) { + case KEY_KP_ENTER: + case KEY_ENTER: { + + if (get_hide_on_ok()) + hide(); + ok_pressed(); + accept_event(); + } break; + case KEY_ESCAPE: { + + hide(); + accept_event(); + } break; + } + } +} + +void EditorLayoutsDialog::_bind_methods() { + ClassDB::bind_method("_line_gui_input", &EditorLayoutsDialog::_line_gui_input); + + ADD_SIGNAL(MethodInfo("name_confirmed", PropertyInfo(Variant::STRING, "name"))); +} + +void EditorLayoutsDialog::ok_pressed() { + + if (layout_names->is_anything_selected()) { + + Vector<int> const selected_items = layout_names->get_selected_items(); + for (int i = 0; i < selected_items.size(); ++i) { + + emit_signal("name_confirmed", layout_names->get_item_text(selected_items[i])); + } + } else if (name->is_visible() && name->get_text() != "") { + + emit_signal("name_confirmed", name->get_text()); + } +} + +void EditorLayoutsDialog::_post_popup() { + + ConfirmationDialog::_post_popup(); + name->clear(); + layout_names->clear(); + + Ref<ConfigFile> config; + config.instance(); + Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); + if (err != OK) { + + return; + } + + List<String> layouts; + config.ptr()->get_sections(&layouts); + + for (List<String>::Element *E = layouts.front(); E; E = E->next()) { + + layout_names->add_item(**E); + } +} + +EditorLayoutsDialog::EditorLayoutsDialog() { + + makevb = memnew(VBoxContainer); + add_child(makevb); + makevb->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5); + makevb->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5); + + layout_names = memnew(ItemList); + makevb->add_child(layout_names); + layout_names->set_visible(true); + layout_names->set_margin(MARGIN_TOP, 5); + layout_names->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5); + layout_names->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5); + layout_names->set_v_size_flags(Control::SIZE_EXPAND_FILL); + layout_names->set_select_mode(ItemList::SelectMode::SELECT_MULTI); + layout_names->set_allow_rmb_select(true); + + name = memnew(LineEdit); + makevb->add_child(name); + name->set_margin(MARGIN_TOP, 5); + name->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5); + name->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5); + name->connect("gui_input", this, "_line_gui_input"); + name->connect("focus_entered", layout_names, "unselect_all"); +} + +void EditorLayoutsDialog::set_name_line_enabled(bool p_enabled) { + + name->set_visible(p_enabled); +} diff --git a/editor/editor_name_dialog.h b/editor/editor_layouts_dialog.h index 314fc27124..5e3a1d5a46 100644 --- a/editor/editor_name_dialog.h +++ b/editor/editor_layouts_dialog.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* editor_name_dialog.h */ +/* editor_layouts_dialog.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,18 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef EDITOR_NAME_DIALOG_H -#define EDITOR_NAME_DIALOG_H +#ifndef EDITOR_LAYOUTS_DIALOG_H +#define EDITOR_LAYOUTS_DIALOG_H #include "scene/gui/dialogs.h" -#include "scene/gui/line_edit.h" -class EditorNameDialog : public ConfirmationDialog { +class LineEdit; +class ItemList; - GDCLASS(EditorNameDialog, ConfirmationDialog); +class EditorLayoutsDialog : public ConfirmationDialog { + + GDCLASS(EditorLayoutsDialog, ConfirmationDialog); - VBoxContainer *makevb; LineEdit *name; + ItemList *layout_names; + VBoxContainer *makevb; void _line_gui_input(const Ref<InputEvent> &p_event); @@ -49,9 +52,9 @@ protected: virtual void _post_popup(); public: - LineEdit *get_line_edit() { return name; } + EditorLayoutsDialog(); - EditorNameDialog(); + void set_name_line_enabled(bool p_enabled); }; -#endif // EDITOR_NAME_DIALOG_H +#endif // EDITOR_LAYOUTS_DIALOG_H diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 2d2f67314d..1f08f3d787 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2475,6 +2475,13 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { OS::get_singleton()->set_window_fullscreen(!OS::get_singleton()->is_window_fullscreen()); } break; + case SETTINGS_TOGGLE_CONSOLE: { + + bool was_visible = OS::get_singleton()->is_console_visible(); + OS::get_singleton()->set_console_visible(!was_visible); + EditorSettings::get_singleton()->set_setting("interface/editor/hide_console_window", !was_visible); + + } break; case SETTINGS_PICK_MAIN_SCENE: { file->set_mode(EditorFileDialog::MODE_OPEN_FILE); @@ -4249,6 +4256,7 @@ void EditorNode::_layout_menu_option(int p_id) { layout_dialog->set_title(TTR("Save Layout")); layout_dialog->get_ok()->set_text(TTR("Save")); layout_dialog->popup_centered(); + layout_dialog->set_name_line_enabled(true); } break; case SETTINGS_LAYOUT_DELETE: { @@ -4256,6 +4264,7 @@ void EditorNode::_layout_menu_option(int p_id) { layout_dialog->set_title(TTR("Delete Layout")); layout_dialog->get_ok()->set_text(TTR("Delete")); layout_dialog->popup_centered(); + layout_dialog->set_name_line_enabled(false); } break; case SETTINGS_LAYOUT_DEFAULT: { @@ -5874,6 +5883,9 @@ EditorNode::EditorNode() { #else p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_SHIFT | KEY_F11), SETTINGS_TOGGLE_FULLSCREEN); #endif +#ifdef WINDOWS_ENABLED + p->add_item(TTR("Toggle System Console"), SETTINGS_TOGGLE_CONSOLE); +#endif p->add_separator(); if (OS::get_singleton()->get_data_path() == OS::get_singleton()->get_config_path()) { @@ -6019,10 +6031,10 @@ EditorNode::EditorNode() { progress_hb = memnew(BackgroundProgress); - layout_dialog = memnew(EditorNameDialog); + layout_dialog = memnew(EditorLayoutsDialog); gui_base->add_child(layout_dialog); layout_dialog->set_hide_on_ok(false); - layout_dialog->set_size(Size2(175, 70) * EDSCALE); + layout_dialog->set_size(Size2(225, 270) * EDSCALE); layout_dialog->connect("name_confirmed", this, "_dialog_action"); update_menu = memnew(MenuButton); diff --git a/editor/editor_node.h b/editor/editor_node.h index f3bc95c409..46b9befcd6 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -41,8 +41,8 @@ #include "editor/editor_feature_profile.h" #include "editor/editor_folding.h" #include "editor/editor_inspector.h" +#include "editor/editor_layouts_dialog.h" #include "editor/editor_log.h" -#include "editor/editor_name_dialog.h" #include "editor/editor_plugin.h" #include "editor/editor_resource_preview.h" #include "editor/editor_run.h" @@ -85,6 +85,7 @@ #include "scene/gui/tool_button.h" #include "scene/gui/tree.h" #include "scene/gui/viewport_container.h" + /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -193,6 +194,7 @@ private: SETTINGS_MANAGE_EXPORT_TEMPLATES, SETTINGS_MANAGE_FEATURE_PROFILES, SETTINGS_PICK_MAIN_SCENE, + SETTINGS_TOGGLE_CONSOLE, SETTINGS_TOGGLE_FULLSCREEN, SETTINGS_HELP, SCENE_TAB_CLOSE, @@ -307,7 +309,7 @@ private: int overridden_default_layout; Ref<ConfigFile> default_layout; PopupMenu *editor_layouts; - EditorNameDialog *layout_dialog; + EditorLayoutsDialog *layout_dialog; ConfirmationDialog *custom_build_manage_templates; ConfirmationDialog *install_android_build_template; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 58e3cc6fc1..5e04bf4953 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -345,6 +345,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 50000); // 20 FPS hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/separate_distraction_mode", false); + _initial_set("interface/editor/hide_console_window", false); _initial_set("interface/editor/save_each_scene_on_quit", true); // Regression _initial_set("interface/editor/quit_confirmation", true); diff --git a/editor/icons/icon_GUI_toggle_off.svg b/editor/icons/icon_GUI_toggle_off.svg index aea0f85f96..928b55b201 100644 --- a/editor/icons/icon_GUI_toggle_off.svg +++ b/editor/icons/icon_GUI_toggle_off.svg @@ -1,5 +1 @@ -<svg width="42" height="26" version="1.1" viewBox="0 0 42 25.999998" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1026.4)"> -<path d="m13 1027.4c-6.6307 0-12 5.3663-12 11.998 0 6.6318 5.3693 12.002 12 12.002h16c6.6307 0 12-5.3702 12-12.002 0-6.6317-5.3693-11.998-12-11.998zm0 2.0003h16c5.5573 0 10 4.4395 10 9.9977 0 5.5583-4.4427 10.002-10 10.002h-16c-5.5573 0-10-4.4434-10-10.002 0-5.5582 4.4427-9.9977 10-9.9977zm7 4.9969a1.0001 1.0003 0 0 0 -1 1.0002v8.0013a1 1.0002 0 0 0 1 1.0002 1 1.0002 0 0 0 1 -1.0002v-3.0005h2a1 1.0002 0 0 0 1 -1.0002 1 1.0002 0 0 0 -1 -1.0001h-2v-2.0003h4a1 1.0002 0 0 0 1 -1.0002 1 1.0002 0 0 0 -1 -1.0002zm9 0a1.0001 1.0003 0 0 0 -1 1.0002v8.0013a1 1.0002 0 0 0 1 1.0002 1 1.0002 0 0 0 1 -1.0002v-3.0005h2a1 1.0002 0 0 0 1 -1.0002 1 1.0002 0 0 0 -1 -1.0001h-2v-2.0003h4a1 1.0002 0 0 0 1 -1.0002 1 1.0002 0 0 0 -1 -1.0002zm-17 0c-2.7496 0-5 2.2508-5 5.0008 0 2.7501 2.2504 5.0009 5 5.0009s5-2.2508 5-5.0009c0-2.75-2.2504-5.0008-5-5.0008zm0 2.0004c1.6687 0 3 1.3315 3 3.0004 0 1.669-1.3313 3.0005-3 3.0005s-3-1.3315-3-3.0005c0-1.6689 1.3313-3.0004 3-3.0004z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#e0e0e0" fill-opacity=".78431" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> -</g> -</svg> +<svg height="26" viewBox="0 0 42 25.999998" width="42" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><rect fill-opacity=".188235" height="16" rx="9" stroke-width="55.8958" width="38" x="2" y="5"/><circle cx="10" cy="13" r="5" stroke-width="97.3613"/></g></svg> diff --git a/editor/icons/icon_GUI_toggle_on.svg b/editor/icons/icon_GUI_toggle_on.svg index c0a11810d4..a79a8290b1 100644 --- a/editor/icons/icon_GUI_toggle_on.svg +++ b/editor/icons/icon_GUI_toggle_on.svg @@ -1,5 +1 @@ -<svg width="42" height="26" version="1.1" viewBox="0 0 42 25.999998" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1026.4)"> -<path d="m13 1027.4c-6.6307 0-12 5.3662-12 11.998s5.3693 12.002 12 12.002h16c6.6307 0 12-5.3702 12-12.002s-5.3693-11.998-12-11.998zm17 6.9972a1 1.0002 0 0 1 1 1.0001v8.0014a1.0001 1.0003 0 0 1 -1.752 0.6623l-5.248-6.001v5.3387a1 1.0002 0 0 1 -1 1.0001 1 1.0002 0 0 1 -1 -1.0001v-8.0014a1.0001 1.0003 0 0 1 1.752 -0.6583l5.248 6.001v-5.3427a1 1.0002 0 0 1 1 -1.0001zm-15 0c2.7496 0 5 2.2507 5 5.0008s-2.2504 5.0008-5 5.0008-5-2.2507-5-5.0008 2.2504-5.0008 5-5.0008zm0 2.0003c-1.6687 0-3 1.3315-3 3.0005s1.3313 3.0005 3 3.0005 3-1.3315 3-3.0005-1.3313-3.0005-3-3.0005z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#e0e0e0" fill-opacity=".78431" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> -</g> -</svg> +<svg height="26" viewBox="0 0 42 25.999998" width="42" xmlns="http://www.w3.org/2000/svg"><path d="m11 5c-4.986 0-9 3.568-9 8s4.014 8 9 8h20c4.986 0 9-3.568 9-8s-4.014-8-9-8zm21 3a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5z" fill="#e0e0e0" stroke-width="55.8958"/></svg> diff --git a/editor/icons/icon_key_valid.svg b/editor/icons/icon_key_valid.svg deleted file mode 100644 index 4a3fab4754..0000000000 --- a/editor/icons/icon_key_valid.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1044.4)"> -<rect transform="rotate(-45)" x="-741.53" y="741.08" width="6.1027" height="6.1027" ry=".76286" fill="#fff"/> -</g> -</svg> diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index c97021433b..2bfc77325f 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -1326,9 +1326,7 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) { if (bct.has("index")) { Ref<Texture> t = _get_texture(state, bct["index"]); material->set_texture(SpatialMaterial::TEXTURE_METALLIC, t); - material->set_metallic_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_BLUE); material->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, t); - material->set_roughness_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GREEN); if (!mr.has("metallicFactor")) { material->set_metallic(1); } @@ -1353,7 +1351,6 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) { Dictionary bct = d["occlusionTexture"]; if (bct.has("index")) { material->set_texture(SpatialMaterial::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"])); - material->set_ao_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_RED); material->set_feature(SpatialMaterial::FEATURE_AMBIENT_OCCLUSION, true); } } diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp index 1259e81be7..ed8ea5497a 100644 --- a/editor/import/resource_importer_image.cpp +++ b/editor/import/resource_importer_image.cpp @@ -77,9 +77,8 @@ void ResourceImporterImage::get_import_options(List<ImportOption> *r_options, in Error ResourceImporterImage::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - if (!f) { - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); - } + + ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); size_t len = f->get_len(); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index e950421476..868f67fd77 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -215,7 +215,6 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p bool generate_tangents = p_generate_tangents; Vector3 scale_mesh = p_scale_mesh; - bool flip_faces = false; int mesh_flags = p_optimize ? Mesh::ARRAY_COMPRESS_DEFAULT : 0; Vector<Vector3> vertices; @@ -293,7 +292,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p int idx = j; - if (!flip_faces && idx < 2) { + if (idx < 2) { idx = 1 ^ idx; } diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 5204565c06..a8866a1a87 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -58,6 +58,7 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) { } void AnimationPlayerEditor::_notification(int p_what) { + switch (p_what) { case NOTIFICATION_PROCESS: { @@ -84,17 +85,13 @@ void AnimationPlayerEditor::_notification(int p_what) { EditorNode::get_singleton()->get_inspector()->refresh(); } else if (last_active) { - //need the last frame after it stopped - + // Need the last frame after it stopped. frame->set_value(player->get_current_animation_position()); } last_active = player->is_playing(); - //seek->set_val(player->get_position()); updating = false; - } break; - case NOTIFICATION_ENTER_TREE: { tool_anim->get_popup()->connect("id_pressed", this, "_animation_tool_menu"); @@ -107,12 +104,10 @@ void AnimationPlayerEditor::_notification(int p_what) { add_style_override("panel", editor->get_gui_base()->get_stylebox("panel", "Panel")); } break; - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { add_style_override("panel", editor->get_gui_base()->get_stylebox("panel", "Panel")); } break; - case NOTIFICATION_THEME_CHANGED: { autoplay->set_icon(get_icon("AutoPlay", "EditorIcons")); @@ -144,9 +139,6 @@ void AnimationPlayerEditor::_notification(int p_what) { ITEM_ICON(TOOL_EDIT_TRANSITIONS, "Blend"); ITEM_ICON(TOOL_EDIT_RESOURCE, "Edit"); ITEM_ICON(TOOL_REMOVE_ANIM, "Remove"); - //ITEM_ICON(TOOL_COPY_ANIM, "Copy"); - //ITEM_ICON(TOOL_PASTE_ANIM, "Paste"); - } break; } } @@ -197,8 +189,6 @@ void AnimationPlayerEditor::_play_pressed() { //unstop stop->set_pressed(false); - //unpause - //pause->set_pressed(false); } void AnimationPlayerEditor::_play_from_pressed() { @@ -224,8 +214,6 @@ void AnimationPlayerEditor::_play_from_pressed() { //unstop stop->set_pressed(false); - //unpause - //pause->set_pressed(false); } void AnimationPlayerEditor::_play_bw_pressed() { @@ -245,8 +233,6 @@ void AnimationPlayerEditor::_play_bw_pressed() { //unstop stop->set_pressed(false); - //unpause - //pause->set_pressed(false); } void AnimationPlayerEditor::_play_bw_from_pressed() { @@ -269,8 +255,6 @@ void AnimationPlayerEditor::_play_bw_from_pressed() { //unstop stop->set_pressed(false); - //unpause - //pause->set_pressed(false); } void AnimationPlayerEditor::_stop_pressed() { @@ -281,14 +265,8 @@ void AnimationPlayerEditor::_stop_pressed() { player->stop(false); play->set_pressed(false); stop->set_pressed(true); - //pause->set_pressed(false); - //player->set_pause(false); } -void AnimationPlayerEditor::_pause_pressed() { - - //player->set_pause( pause->is_pressed() ); -} void AnimationPlayerEditor::_animation_selected(int p_which) { if (updating) @@ -469,13 +447,17 @@ void AnimationPlayerEditor::_animation_remove_confirmed() { if (player->get_autoplay() == current) { undo_redo->add_do_method(player, "set_autoplay", ""); undo_redo->add_undo_method(player, "set_autoplay", current); - // Avoid having the autoplay icon linger around if there is only one animation in the player + // Avoid having the autoplay icon linger around if there is only one animation in the player. undo_redo->add_do_method(this, "_animation_player_changed", player); } undo_redo->add_do_method(player, "remove_animation", current); undo_redo->add_undo_method(player, "add_animation", current, anim); undo_redo->add_do_method(this, "_animation_player_changed", player); undo_redo->add_undo_method(this, "_animation_player_changed", player); + if (animation->get_item_count() == 1) { + undo_redo->add_do_method(this, "_stop_onion_skinning"); + undo_redo->add_undo_method(this, "_start_onion_skinning"); + } undo_redo->commit_action(); } @@ -545,6 +527,10 @@ void AnimationPlayerEditor::_animation_name_edited() { undo_redo->add_undo_method(player, "remove_animation", new_name); undo_redo->add_do_method(this, "_animation_player_changed", player); undo_redo->add_undo_method(this, "_animation_player_changed", player); + if (animation->get_item_count() == 0) { + undo_redo->add_do_method(this, "_start_onion_skinning"); + undo_redo->add_undo_method(this, "_stop_onion_skinning"); + } undo_redo->commit_action(); _select_anim_by_name(new_name); @@ -844,7 +830,8 @@ void AnimationPlayerEditor::_update_player() { animation->set_disabled(animlist.size() == 0); autoplay->set_disabled(animlist.size() == 0); tool_anim->set_disabled(player == NULL); - onion_skinning->set_disabled(player == NULL); + onion_toggle->set_disabled(animlist.size() == 0); + onion_skinning->set_disabled(animlist.size() == 0); pin->set_disabled(player == NULL); if (!player) { @@ -895,17 +882,25 @@ void AnimationPlayerEditor::_update_player() { void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { - if (onion.enabled) - _start_onion_skinning(); - if (player && pin->is_pressed()) - return; //ignore, pinned + return; // Ignore, pinned. player = p_player; if (player) { _update_player(); + + if (onion.enabled) { + if (animation->get_item_count() > 0) + _start_onion_skinning(); + else + _stop_onion_skinning(); + } + track_editor->show_select_node_warning(false); } else { + if (onion.enabled) + _stop_onion_skinning(); + track_editor->show_select_node_warning(true); } } @@ -915,13 +910,13 @@ void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_o if (!onion.can_overlay) return; - // Can happen on viewport resize, at least + // Can happen on viewport resize, at least. if (!_are_onion_layers_valid()) return; RID ci = p_overlay->get_canvas_item(); Rect2 src_rect = p_overlay->get_global_rect(); - // Re-flip since captures are already flipped + // Re-flip since captures are already flipped. src_rect.position.y = onion.capture_size.y - (src_rect.position.y + src_rect.size.y); src_rect.size.y *= -1; @@ -955,7 +950,7 @@ void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_o } cidx++; - } while (cidx < base_cidx + onion.steps); // In case there's the present capture at the end, skip it + } while (cidx < base_cidx + onion.steps); // In case there's the present capture at the end, skip it. } } @@ -1053,7 +1048,7 @@ void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) { _update_player(); if (blend_editor.dialog->is_visible_in_tree()) - _animation_blend(); //update + _animation_blend(); // Update. } } @@ -1092,8 +1087,6 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) _seek_value_changed(p_pos, !p_drag); EditorNode::get_singleton()->get_inspector()->refresh(); - - //seekit } void AnimationPlayerEditor::_hide_anim_editors() { @@ -1113,8 +1106,9 @@ void AnimationPlayerEditor::_animation_about_to_show_menu() { void AnimationPlayerEditor::_animation_tool_menu(int p_option) { String current; - if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) + if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { current = animation->get_item_text(animation->get_selected()); + } Ref<Animation> anim; if (current != String()) { @@ -1124,33 +1118,39 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { switch (p_option) { case TOOL_NEW_ANIM: { + _animation_new(); } break; - case TOOL_LOAD_ANIM: { + _animation_load(); - break; } break; case TOOL_SAVE_ANIM: { + if (anim.is_valid()) { _animation_save(anim); } } break; case TOOL_SAVE_AS_ANIM: { + if (anim.is_valid()) { _animation_save_as(anim); } } break; case TOOL_DUPLICATE_ANIM: { + _animation_duplicate(); } break; case TOOL_RENAME_ANIM: { + _animation_rename(); } break; case TOOL_EDIT_TRANSITIONS: { + _animation_blend(); } break; case TOOL_REMOVE_ANIM: { + _animation_remove(); } break; case TOOL_COPY_ANIM: { @@ -1163,9 +1163,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { String current2 = animation->get_item_text(animation->get_selected()); Ref<Animation> anim2 = player->get_animation(current2); - //editor->edit_resource(anim2); EditorSettings::get_singleton()->set_resource_clipboard(anim2); - } break; case TOOL_PASTE_ANIM: { @@ -1197,7 +1195,6 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { undo_redo->commit_action(); _select_anim_by_name(name); - } break; case TOOL_EDIT_RESOURCE: { @@ -1210,7 +1207,6 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { String current2 = animation->get_item_text(animation->get_selected()); Ref<Animation> anim2 = player->get_animation(current2); editor->edit_resource(anim2); - } break; } } @@ -1232,22 +1228,19 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) { _stop_onion_skinning(); } break; - case ONION_SKINNING_PAST: { - // Ensure at least one of past/future is checjed + // Ensure at least one of past/future is checked. onion.past = onion.future ? !onion.past : true; menu->set_item_checked(idx, onion.past); } break; - case ONION_SKINNING_FUTURE: { - // Ensure at least one of past/future is checjed + // Ensure at least one of past/future is checked. onion.future = onion.past ? !onion.future : true; menu->set_item_checked(idx, onion.future); } break; - - case ONION_SKINNING_1_STEP: // Fall-through + case ONION_SKINNING_1_STEP: // Fall-through. case ONION_SKINNING_2_STEPS: case ONION_SKINNING_3_STEPS: { @@ -1257,19 +1250,16 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) { menu->set_item_checked(one_frame_idx + i, onion.steps == i + 1); } } break; - case ONION_SKINNING_DIFFERENCES_ONLY: { onion.differences_only = !onion.differences_only; menu->set_item_checked(idx, onion.differences_only); } break; - case ONION_SKINNING_FORCE_WHITE_MODULATE: { onion.force_white_modulate = !onion.force_white_modulate; menu->set_item_checked(idx, onion.force_white_modulate); } break; - case ONION_SKINNING_INCLUDE_GIZMOS: { onion.include_gizmos = !onion.include_gizmos; @@ -1306,7 +1296,7 @@ void AnimationPlayerEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) { void AnimationPlayerEditor::_editor_visibility_changed() { - if (is_visible()) { + if (is_visible() && animation->get_item_count() > 0) { _start_onion_skinning(); } } @@ -1332,7 +1322,7 @@ void AnimationPlayerEditor::_allocate_onion_layers() { for (int i = 0; i < captures; i++) { bool is_present = onion.differences_only && i == captures - 1; - // Each capture is a viewport with a canvas item attached that renders a full-size rect with the contents of the main viewport + // Each capture is a viewport with a canvas item attached that renders a full-size rect with the contents of the main viewport. onion.captures.write[i] = VS::get_singleton()->viewport_create(); VS::get_singleton()->viewport_set_usage(onion.captures[i], VS::VIEWPORT_USAGE_2D); VS::get_singleton()->viewport_set_size(onion.captures[i], capture_size.width, capture_size.height); @@ -1342,7 +1332,7 @@ void AnimationPlayerEditor::_allocate_onion_layers() { VS::get_singleton()->viewport_attach_canvas(onion.captures[i], onion.capture.canvas); } - // Reset the capture canvas item to the current root viewport texture (defensive) + // Reset the capture canvas item to the current root viewport texture (defensive). VS::get_singleton()->canvas_item_clear(onion.capture.canvas_item); VS::get_singleton()->canvas_item_add_texture_rect(onion.capture.canvas_item, Rect2(Point2(), capture_size), get_tree()->get_root()->get_texture()->get_rid()); @@ -1362,7 +1352,7 @@ void AnimationPlayerEditor::_free_onion_layers() { void AnimationPlayerEditor::_prepare_onion_layers_1() { - // This would be called per viewport and we want to act once only + // This would be called per viewport and we want to act once only. int64_t frame = get_tree()->get_frame(); if (frame == onion.last_frame) return; @@ -1374,14 +1364,14 @@ void AnimationPlayerEditor::_prepare_onion_layers_1() { onion.last_frame = frame; - // Refresh viewports with no onion layers overlaid + // Refresh viewports with no onion layers overlaid. onion.can_overlay = false; plugin->update_overlays(); if (player->is_playing()) return; - // And go to next step afterwards + // And go to next step afterwards. call_deferred("_prepare_onion_layers_2"); } @@ -1394,7 +1384,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { if (!_are_onion_layers_valid()) _allocate_onion_layers(); - // Hide superfluous elements that would make the overlay unnecessary cluttered + // Hide superfluous elements that would make the overlay unnecessary cluttered. Dictionary canvas_edit_state; Dictionary spatial_edit_state; if (SpatialEditor::get_singleton()->is_visible()) { @@ -1415,7 +1405,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { vp[i] = d; } new_state["viewports"] = vp; - // TODO: Save/restore only affected entries + // TODO: Save/restore only affected entries. SpatialEditor::get_singleton()->set_state(new_state); } else { // CanvasItemEditor // 2D @@ -1426,11 +1416,11 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { new_state["show_guides"] = false; new_state["show_helpers"] = false; new_state["show_zoom_control"] = false; - // TODO: Save/restore only affected entries + // TODO: Save/restore only affected entries. CanvasItemEditor::get_singleton()->set_state(new_state); } - // Tweak the root viewport to ensure it's rendered before our target + // Tweak the root viewport to ensure it's rendered before our target. RID root_vp = get_tree()->get_root()->get_viewport_rid(); Rect2 root_vp_screen_rect = get_tree()->get_root()->get_attach_to_screen_rect(); VS::get_singleton()->viewport_attach_to_screen(root_vp, Rect2()); @@ -1438,7 +1428,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { RID present_rid; if (onion.differences_only) { - // Capture present scene as it is + // Capture present scene as it is. VS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, RID()); present_rid = onion.captures[onion.captures.size() - 1]; VS::get_singleton()->viewport_set_active(present_rid, true); @@ -1447,11 +1437,11 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { VS::get_singleton()->viewport_set_active(present_rid, false); } - // Backup current animation state + // Backup current animation state. AnimatedValuesBackup values_backup = player->backup_animated_values(); float cpos = player->get_current_animation_position(); - // Render every past/future step with the capture shader + // Render every past/future step with the capture shader. VS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, onion.capture.material->get_rid()); onion.capture.material->set_shader_param("bkg_color", GLOBAL_GET("rendering/environment/default_clear_color")); @@ -1465,7 +1455,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { for (int step_off = step_off_a; step_off <= step_off_b; step_off++) { if (step_off == 0) { - // Skip present step and switch to the color of future + // Skip present step and switch to the color of future. if (!onion.force_white_modulate) onion.capture.material->set_shader_param("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color")); continue; @@ -1477,8 +1467,8 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { onion.captures_valid.write[cidx] = valid; if (valid) { player->seek(pos, true); - get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials - values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D) + get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials. + values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D). VS::get_singleton()->viewport_set_active(onion.captures[cidx], true); VS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); @@ -1489,18 +1479,18 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { cidx++; } - // Restore root viewport + // Restore root viewport. VS::get_singleton()->viewport_set_parent_viewport(root_vp, RID()); VS::get_singleton()->viewport_attach_to_screen(root_vp, root_vp_screen_rect); VS::get_singleton()->viewport_set_update_mode(root_vp, VS::VIEWPORT_UPDATE_WHEN_VISIBLE); // Restore animation state // (Seeking with update=true wouldn't do the trick because the current value of the properties - // may not match their value for the current point in the animation) + // may not match their value for the current point in the animation). player->seek(cpos, false); player->restore_animated_values(values_backup); - // Restor state of main editors + // Restor state of main editors. if (SpatialEditor::get_singleton()->is_visible()) { // 3D SpatialEditor::get_singleton()->set_state(spatial_edit_state); @@ -1509,14 +1499,14 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { CanvasItemEditor::get_singleton()->set_state(canvas_edit_state); } - // Update viewports with skin layers overlaid for the actual engine loop render + // Update viewports with skin layers overlaid for the actual engine loop render. onion.can_overlay = true; plugin->update_overlays(); } void AnimationPlayerEditor::_start_onion_skinning() { - // FIXME: Using "idle_frame" makes onion layers update one frame behind the current + // FIXME: Using "idle_frame" makes onion layers update one frame behind the current. if (!get_tree()->is_connected("idle_frame", this, "call_deferred")) { get_tree()->connect("idle_frame", this, "call_deferred", varray("_prepare_onion_layers_1")); } @@ -1537,6 +1527,7 @@ void AnimationPlayerEditor::_stop_onion_skinning() { } void AnimationPlayerEditor::_pin_pressed() { + EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->update_tree(); } @@ -1549,7 +1540,6 @@ void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_play_bw_from_pressed"), &AnimationPlayerEditor::_play_bw_from_pressed); ClassDB::bind_method(D_METHOD("_stop_pressed"), &AnimationPlayerEditor::_stop_pressed); ClassDB::bind_method(D_METHOD("_autoplay_pressed"), &AnimationPlayerEditor::_autoplay_pressed); - ClassDB::bind_method(D_METHOD("_pause_pressed"), &AnimationPlayerEditor::_pause_pressed); ClassDB::bind_method(D_METHOD("_animation_selected"), &AnimationPlayerEditor::_animation_selected); ClassDB::bind_method(D_METHOD("_animation_name_edited"), &AnimationPlayerEditor::_animation_name_edited); ClassDB::bind_method(D_METHOD("_animation_new"), &AnimationPlayerEditor::_animation_new); @@ -1564,10 +1554,7 @@ void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_seek_value_changed"), &AnimationPlayerEditor::_seek_value_changed, DEFVAL(true)); ClassDB::bind_method(D_METHOD("_animation_player_changed"), &AnimationPlayerEditor::_animation_player_changed); ClassDB::bind_method(D_METHOD("_blend_edited"), &AnimationPlayerEditor::_blend_edited); - //ClassDB::bind_method(D_METHOD("_seek_frame_changed"),&AnimationPlayerEditor::_seek_frame_changed); ClassDB::bind_method(D_METHOD("_scale_changed"), &AnimationPlayerEditor::_scale_changed); - //ClassDB::bind_method(D_METHOD("_editor_store_all"),&AnimationPlayerEditor::_editor_store_all); - //ClassDB::bind_method(D_METHOD("_editor_load_all"),&AnimationPlayerEditor::_editor_load_all); ClassDB::bind_method(D_METHOD("_list_changed"), &AnimationPlayerEditor::_list_changed); ClassDB::bind_method(D_METHOD("_animation_key_editor_seek"), &AnimationPlayerEditor::_animation_key_editor_seek); ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_len_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_len_changed); @@ -1582,6 +1569,8 @@ void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_editor_visibility_changed"), &AnimationPlayerEditor::_editor_visibility_changed); ClassDB::bind_method(D_METHOD("_prepare_onion_layers_1"), &AnimationPlayerEditor::_prepare_onion_layers_1); ClassDB::bind_method(D_METHOD("_prepare_onion_layers_2"), &AnimationPlayerEditor::_prepare_onion_layers_2); + ClassDB::bind_method(D_METHOD("_start_onion_skinning"), &AnimationPlayerEditor::_start_onion_skinning); + ClassDB::bind_method(D_METHOD("_stop_onion_skinning"), &AnimationPlayerEditor::_stop_onion_skinning); ClassDB::bind_method(D_METHOD("_pin_pressed"), &AnimationPlayerEditor::_pin_pressed); } diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index dedce16bbc..398ef6ff14 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -170,7 +170,6 @@ class AnimationPlayerEditor : public VBoxContainer { void _play_bw_from_pressed(); void _autoplay_pressed(); void _stop_pressed(); - void _pause_pressed(); void _animation_selected(int p_which); void _animation_new(); void _animation_rename(); diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index f75d4f03b7..e68bca55cb 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -96,9 +96,9 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) { UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Convert to CPUParticles")); ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", particles, cpu_particles, true, false); - ur->add_do_reference(particles); + ur->add_do_reference(cpu_particles); ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, particles, false, false); - ur->add_undo_reference(this); + ur->add_undo_reference(particles); ur->commit_action(); } break; diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index 887930c377..f05e7d65d3 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -315,9 +315,9 @@ void ParticlesEditor::_menu_option(int p_option) { UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Convert to CPUParticles")); ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, cpu_particles, true, false); - ur->add_do_reference(node); + ur->add_do_reference(cpu_particles); ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, node, false, false); - ur->add_undo_reference(this); + ur->add_undo_reference(node); ur->commit_action(); } break; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index b4719b2e6d..1b00889e9a 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -306,8 +306,11 @@ void ScriptEditor::_goto_script_line(REF p_script, int p_line) { editor->push_item(p_script.ptr()); ScriptEditorBase *current = _get_current_editor(); - if (current) + if (ScriptTextEditor *script_text_editor = Object::cast_to<ScriptTextEditor>(current)) { + script_text_editor->goto_line_centered(p_line); + } else if (current) { current->goto_line(p_line, true); + } } } } @@ -1915,9 +1918,7 @@ Ref<TextFile> ScriptEditor::_load_text_file(const String &p_path, Error *r_error Ref<TextFile> text_res(text_file); Error err = text_file->load_text(path); - if (err != OK) { - ERR_FAIL_COND_V(err != OK, RES()); - } + ERR_FAIL_COND_V(err != OK, RES()); text_file->set_file_path(local_path); text_file->set_path(local_path, true); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index ce0859a1f6..9bf3a9f0eb 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -237,7 +237,7 @@ void ScriptTextEditor::_load_theme_settings() { text_edit->add_color_override("safe_line_number_color", safe_line_number_color); text_edit->add_color_override("caret_color", caret_color); text_edit->add_color_override("caret_background_color", caret_background_color); - text_edit->add_color_override("font_selected_color", text_selected_color); + text_edit->add_color_override("font_color_selected", text_selected_color); text_edit->add_color_override("selection_color", selection_color); text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color); text_edit->add_color_override("current_line_color", current_line_color); @@ -487,6 +487,11 @@ void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { code_editor->goto_line_selection(p_line, p_begin, p_end); } +void ScriptTextEditor::goto_line_centered(int p_line) { + + code_editor->goto_line_centered(p_line); +} + void ScriptTextEditor::set_executing_line(int p_line) { code_editor->set_executing_line(p_line); } diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 24d40a5eec..89975e061e 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -201,6 +201,7 @@ public: virtual void goto_line(int p_line, bool p_with_error = false); void goto_line_selection(int p_line, int p_begin, int p_end); + void goto_line_centered(int p_line); virtual void set_executing_line(int p_line); virtual void clear_executing_line(); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index f9ca38b919..d02817f6e8 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -124,7 +124,7 @@ void ShaderTextEditor::_load_theme_settings() { get_text_edit()->add_color_override("line_number_color", line_number_color); get_text_edit()->add_color_override("caret_color", caret_color); get_text_edit()->add_color_override("caret_background_color", caret_background_color); - get_text_edit()->add_color_override("font_selected_color", text_selected_color); + get_text_edit()->add_color_override("font_color_selected", text_selected_color); get_text_edit()->add_color_override("selection_color", selection_color); get_text_edit()->add_color_override("brace_mismatch_color", brace_mismatch_color); get_text_edit()->add_color_override("current_line_color", current_line_color); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index a1c0b732fa..7f7ae8f273 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -1275,13 +1275,13 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { _edit.mode = TRANSFORM_TRANSLATE; } - if (cursor.region_select && nav_mode == NAVIGATION_NONE) { + if (cursor.region_select) { cursor.region_end = m->get_position(); surface->update(); return; } - if (_edit.mode == TRANSFORM_NONE && nav_mode == NAVIGATION_NONE) + if (_edit.mode == TRANSFORM_NONE) return; Vector3 ray_pos = _get_ray_pos(m->get_position()); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index eeef3397d2..787813336d 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -116,7 +116,7 @@ void TextEditor::_load_theme_settings() { text_edit->add_color_override("line_number_color", line_number_color); text_edit->add_color_override("caret_color", caret_color); text_edit->add_color_override("caret_background_color", caret_background_color); - text_edit->add_color_override("font_selected_color", text_selected_color); + text_edit->add_color_override("font_color_selected", text_selected_color); text_edit->add_color_override("selection_color", selection_color); text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color); text_edit->add_color_override("current_line_color", current_line_color); diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index b417414ae0..04e8d65155 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -31,7 +31,6 @@ #ifndef TILE_SET_EDITOR_PLUGIN_H #define TILE_SET_EDITOR_PLUGIN_H -#include "editor/editor_name_dialog.h" #include "editor/editor_node.h" #include "scene/2d/sprite.h" #include "scene/resources/concave_polygon_shape_2d.h" diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 7d0c67b5ed..bfb005cd0b 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -573,13 +573,11 @@ void VisualShaderEditor::_update_graph() { name_box->connect("text_entered", this, "_change_input_port_name", varray(name_box, nodes[n_i], i)); name_box->connect("focus_exited", this, "_port_name_focus_out", varray(name_box, nodes[n_i], i, false)); - if (is_group) { - Button *remove_btn = memnew(Button); - remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons")); - remove_btn->set_tooltip(TTR("Remove") + " " + name_left); - remove_btn->connect("pressed", this, "_remove_input_port", varray(nodes[n_i], i), CONNECT_DEFERRED); - hb->add_child(remove_btn); - } + Button *remove_btn = memnew(Button); + remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons")); + remove_btn->set_tooltip(TTR("Remove") + " " + name_left); + remove_btn->connect("pressed", this, "_remove_input_port", varray(nodes[n_i], i), CONNECT_DEFERRED); + hb->add_child(remove_btn); } else { Label *label = memnew(Label); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 3167abb745..00c8ed6ad3 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -305,49 +305,51 @@ void ScriptEditorDebugger::_scene_tree_rmb_selected(const Vector2 &p_position) { } void ScriptEditorDebugger::_file_selected(const String &p_file) { - if (file_dialog_mode == SAVE_NODE) { - - Array msg; - msg.push_back("save_node"); - msg.push_back(inspected_object_id); - msg.push_back(p_file); - ppeer->put_var(msg); - } else if (file_dialog_mode == SAVE_CSV) { + switch (file_dialog_mode) { + case SAVE_NODE: { + Array msg; + msg.push_back("save_node"); + msg.push_back(inspected_object_id); + msg.push_back(p_file); + ppeer->put_var(msg); + } break; + case SAVE_CSV: { + Error err; + FileAccessRef file = FileAccess::open(p_file, FileAccess::WRITE, &err); - Error err; - FileAccessRef file = FileAccess::open(p_file, FileAccess::WRITE, &err); + if (err != OK) { + ERR_PRINTS("Failed to open " + p_file); + return; + } + Vector<String> line; + line.resize(Performance::MONITOR_MAX); - if (err != OK) { - ERR_PRINTS("Failed to open " + p_file); - return; - } - Vector<String> line; - line.resize(Performance::MONITOR_MAX); + // signatures + for (int i = 0; i < Performance::MONITOR_MAX; i++) { + line.write[i] = Performance::get_singleton()->get_monitor_name(Performance::Monitor(i)); + } + file->store_csv_line(line); - // signatures - for (int i = 0; i < Performance::MONITOR_MAX; i++) { - line.write[i] = Performance::get_singleton()->get_monitor_name(Performance::Monitor(i)); - } - file->store_csv_line(line); + // values + List<Vector<float> >::Element *E = perf_history.back(); + while (E) { - // values - List<Vector<float> >::Element *E = perf_history.back(); - while (E) { + Vector<float> &perf_data = E->get(); + for (int i = 0; i < perf_data.size(); i++) { - Vector<float> &perf_data = E->get(); - for (int i = 0; i < perf_data.size(); i++) { + line.write[i] = String::num_real(perf_data[i]); + } + file->store_csv_line(line); + E = E->prev(); + } + file->store_string("\n"); - line.write[i] = String::num_real(perf_data[i]); + Vector<Vector<String> > profiler_data = profiler->get_data_as_csv(); + for (int i = 0; i < profiler_data.size(); i++) { + file->store_csv_line(profiler_data[i]); } - file->store_csv_line(line); - E = E->prev(); - } - file->store_string("\n"); - Vector<Vector<String> > profiler_data = profiler->get_data_as_csv(); - for (int i = 0; i < profiler_data.size(); i++) { - file->store_csv_line(profiler_data[i]); - } + } break; } } diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 67cbcf5de4..c4b8999401 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -1835,12 +1835,12 @@ void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { JointSpatialGizmoPlugin::CreateConeTwistJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), - pb ? pb->get_global_transform() : Transform(), - pbp ? pbp->get_global_transform() : Transform(), + pb->get_global_transform(), + pbp->get_global_transform(), cjd->swing_span, cjd->twist_span, - pb ? &points : NULL, - pbp ? &points : NULL); + &points, + &points); } break; case PhysicalBone::JOINT_TYPE_HINGE: { @@ -1848,14 +1848,14 @@ void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { JointSpatialGizmoPlugin::CreateHingeJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), - pb ? pb->get_global_transform() : Transform(), - pbp ? pbp->get_global_transform() : Transform(), + pb->get_global_transform(), + pbp->get_global_transform(), hjd->angular_limit_lower, hjd->angular_limit_upper, hjd->angular_limit_enabled, points, - pb ? &points : NULL, - pbp ? &points : NULL); + &points, + &points); } break; case PhysicalBone::JOINT_TYPE_SLIDER: { @@ -1863,15 +1863,15 @@ void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { JointSpatialGizmoPlugin::CreateSliderJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), - pb ? pb->get_global_transform() : Transform(), - pbp ? pbp->get_global_transform() : Transform(), + pb->get_global_transform(), + pbp->get_global_transform(), sjd->angular_limit_lower, sjd->angular_limit_upper, sjd->linear_limit_lower, sjd->linear_limit_upper, points, - pb ? &points : NULL, - pbp ? &points : NULL); + &points, + &points); } break; case PhysicalBone::JOINT_TYPE_6DOF: { @@ -1880,8 +1880,8 @@ void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), - pb ? pb->get_global_transform() : Transform(), - pbp ? pbp->get_global_transform() : Transform(), + pb->get_global_transform(), + pbp->get_global_transform(), sdofjd->axis_data[0].angular_limit_lower, sdofjd->axis_data[0].angular_limit_upper, @@ -1905,8 +1905,8 @@ void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { sdofjd->axis_data[2].linear_limit_enabled, points, - pb ? &points : NULL, - pbp ? &points : NULL); + &points, + &points); } break; default: return; diff --git a/main/main.cpp b/main/main.cpp index c51ffd9124..c765ff9700 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1797,6 +1797,7 @@ bool Main::start() { pmanager->add_child(progress_dialog); sml->get_root()->add_child(pmanager); OS::get_singleton()->set_context(OS::CONTEXT_PROJECTMAN); + project_manager = true; } if (project_manager || editor) { @@ -1806,6 +1807,10 @@ bool Main::start() { StreamPeerSSL::load_certs_from_file(certs); else StreamPeerSSL::load_certs_from_memory(StreamPeerSSL::get_project_cert_array()); + + // Hide console window if requested (Windows-only) + bool hide_console = EditorSettings::get_singleton()->get_setting("interface/editor/hide_console_window"); + OS::get_singleton()->set_console_visible(!hide_console); } #endif } diff --git a/misc/ide/jetbrains/build.gradle b/misc/ide/jetbrains/build.gradle index ffcd12cd15..eb2fbc0e69 100644 --- a/misc/ide/jetbrains/build.gradle +++ b/misc/ide/jetbrains/build.gradle @@ -23,7 +23,7 @@ dependencies { def pathToRootDir = "../../../" // Note: Only keep the abis you support to speed up the gradle 'assemble' task. -def supportedAbis = ["armv6", "armv7", "arm64v8", "x86", "x86_64"] +def supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"] android { diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index bcc992db24..b4530c2df1 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -261,12 +261,10 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, ERR_FAIL_COND_V(color_table_size == 0, ERR_BUG); PoolVector<uint8_t> bmp_color_table; - if (color_table_size > 0) { - // Color table is usually 4 bytes per color -> [B][G][R][0] - err = bmp_color_table.resize(color_table_size * 4); - PoolVector<uint8_t>::Write bmp_color_table_w = bmp_color_table.write(); - f->get_buffer(bmp_color_table_w.ptr(), color_table_size * 4); - } + // Color table is usually 4 bytes per color -> [B][G][R][0] + err = bmp_color_table.resize(color_table_size * 4); + PoolVector<uint8_t>::Write bmp_color_table_w = bmp_color_table.write(); + f->get_buffer(bmp_color_table_w.ptr(), color_table_size * 4); f->seek(bmp_header.bmp_file_header.bmp_file_offset); diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index aa4d7d7d32..fd0d36eddf 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -1018,15 +1018,15 @@ int CSGBrushOperation::MeshMerge::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from max_depth = p_depth; } - if (p_size <= BVH_LIMIT) { + if (p_size == 0) { + + return -1; + } else if (p_size <= BVH_LIMIT) { for (int i = 0; i < p_size - 1; i++) { p_bb[p_from + i]->next = p_bb[p_from + i + 1] - p_bvh; } return p_bb[p_from] - p_bvh; - } else if (p_size == 0) { - - return -1; } AABB aabb; diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 1d27b9b6f4..a496a214fd 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -1816,11 +1816,9 @@ CSGBrush *CSGPolygon::_build_brush() { path_cache = path; - if (path_cache) { - path_cache->connect("tree_exited", this, "_path_exited"); - path_cache->connect("curve_changed", this, "_path_changed"); - path_cache = NULL; - } + path_cache->connect("tree_exited", this, "_path_exited"); + path_cache->connect("curve_changed", this, "_path_changed"); + path_cache = NULL; } curve = path->get_curve(); if (curve.is_null()) diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 3caa7b1d12..994a84fbc4 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -241,6 +241,7 @@ Vector3 GridMap::get_cell_size() const { void GridMap::set_octant_size(int p_size) { + ERR_FAIL_COND(p_size == 0); octant_size = p_size; _recreate_octant_data(); } diff --git a/modules/mbedtls/stream_peer_mbed_tls.cpp b/modules/mbedtls/stream_peer_mbed_tls.cpp index 45d3b86919..3541eff25a 100755 --- a/modules/mbedtls/stream_peer_mbed_tls.cpp +++ b/modules/mbedtls/stream_peer_mbed_tls.cpp @@ -122,6 +122,8 @@ Error StreamPeerMbedTLS::_do_handshake() { Error StreamPeerMbedTLS::connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs, const String &p_for_hostname) { + ERR_FAIL_COND_V(p_base.is_null(), ERR_INVALID_PARAMETER); + base = p_base; int ret = 0; int authmode = p_validate_certs ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE; diff --git a/modules/opus/SCsub b/modules/opus/SCsub index f3c981dd45..a4a431bab7 100644 --- a/modules/opus/SCsub +++ b/modules/opus/SCsub @@ -221,7 +221,7 @@ if env['builtin_opus']: env_opus.Prepend(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths]) if env["platform"] == "android": - if ("android_arch" in env and env["android_arch"] in ["armv6", "armv7"]): + if ("android_arch" in env and env["android_arch"] == "armv7"): env_opus.Append(CPPFLAGS=["-DOPUS_ARM_OPT"]) elif ("android_arch" in env and env["android_arch"] == "arm64v8"): env_opus.Append(CPPFLAGS=["-DOPUS_ARM64_OPT"]) diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp index 7254f57672..e10f29e310 100644 --- a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp @@ -82,9 +82,8 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin float loop_offset = p_options["loop_offset"]; FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - if (!f) { - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); - } + + ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); size_t len = f->get_len(); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 85fc867901..df5bb9ca2e 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -1692,7 +1692,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p if ((ret == output || ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) && node->sequence_output_count) { //if no exit bit was set, and has sequence outputs, guess next node - if (output < 0 || output >= node->sequence_output_count) { + if (output >= node->sequence_output_count) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; error_str = RTR("Node returned an invalid sequence output: ") + itos(output); error = true; diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp index ceec79c0d5..1e7ed3019c 100644 --- a/modules/visual_script/visual_script_property_selector.cpp +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -188,7 +188,6 @@ void VisualScriptPropertySelector::_update_search() { } } } - bool script_methods = false; { if (type != Variant::NIL) { Variant v; @@ -211,7 +210,7 @@ void VisualScriptPropertySelector::_update_search() { for (List<MethodInfo>::Element *M = methods.front(); M; M = M->next()) { String name = M->get().name.get_slice(":", 0); - if (!script_methods && name.begins_with("_") && !(M->get().flags & METHOD_FLAG_VIRTUAL)) + if (name.begins_with("_") && !(M->get().flags & METHOD_FLAG_VIRTUAL)) continue; if (virtuals_only && !(M->get().flags & METHOD_FLAG_VIRTUAL)) diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub index a6be1380a6..c76585013c 100644 --- a/modules/webm/libvpx/SCsub +++ b/modules/webm/libvpx/SCsub @@ -384,8 +384,6 @@ elif webm_cpu_arm: env_libvpx.add_source_files(env.modules_sources, [libvpx_dir + "third_party/android/cpu-features.c"]) env_libvpx_neon = env_libvpx.Clone() - if env["platform"] == 'android' and env["android_arch"] == 'armv6': - env_libvpx_neon.Append(CCFLAGS=['-mfpu=neon']) env_libvpx_neon.add_source_files(env.modules_sources, libvpx_sources_arm_neon) if env["platform"] == 'uwp': diff --git a/platform/android/SCsub b/platform/android/SCsub index 22ed476c6f..1562714d76 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -37,9 +37,7 @@ android_objects.append(env_thirdparty.SharedObject('#thirdparty/misc/ifaddrs-and lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"]) lib_arch_dir = '' -if env['android_arch'] == 'armv6': - lib_arch_dir = 'armeabi' -elif env['android_arch'] == 'armv7': +if env['android_arch'] == 'armv7': lib_arch_dir = 'armeabi-v7a' elif env['android_arch'] == 'arm64v8': lib_arch_dir = 'arm64-v8a' diff --git a/platform/android/detect.py b/platform/android/detect.py index b7641172e4..eed51c4d30 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -26,7 +26,7 @@ def get_opts(): return [ ('ANDROID_NDK_ROOT', 'Path to the Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)), ('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"), - EnumVariable('android_arch', 'Target architecture', "armv7", ('armv7', 'armv6', 'arm64v8', 'x86', 'x86_64')), + EnumVariable('android_arch', 'Target architecture', "armv7", ('armv7', 'arm64v8', 'x86', 'x86_64')), BoolVariable('android_neon', 'Enable NEON support (armv7 only)', True), BoolVariable('android_stl', 'Enable Android STL support (for modules)', True) ] @@ -93,7 +93,7 @@ def configure(env): ## Architecture - if env['android_arch'] not in ['armv7', 'armv6', 'arm64v8', 'x86', 'x86_64']: + if env['android_arch'] not in ['armv7', 'arm64v8', 'x86', 'x86_64']: env['android_arch'] = 'armv7' neon_text = "" @@ -119,13 +119,6 @@ def configure(env): abi_subpath = "x86_64-linux-android" arch_subpath = "x86_64" env["x86_libtheora_opt_gcc"] = True - elif env['android_arch'] == 'armv6': - env['ARCH'] = 'arch-arm' - env.extra_suffix = ".armv6" + env.extra_suffix - target_subpath = "arm-linux-androideabi-4.9" - abi_subpath = "arm-linux-androideabi" - arch_subpath = "armeabi" - can_vectorize = False elif env["android_arch"] == "armv7": env['ARCH'] = 'arch-arm' target_subpath = "arm-linux-androideabi-4.9" @@ -249,11 +242,6 @@ def configure(env): elif env['android_arch'] == 'x86_64': target_opts = ['-target', 'x86_64-none-linux-android'] - elif env["android_arch"] == "armv6": - target_opts = ['-target', 'armv6-none-linux-androideabi'] - env.Append(CCFLAGS='-march=armv6 -mfpu=vfp -mfloat-abi=softfp'.split()) - env.Append(CPPFLAGS=['-D__ARM_ARCH_6__']) - elif env["android_arch"] == "armv7": target_opts = ['-target', 'armv7-none-linux-androideabi'] env.Append(CCFLAGS='-march=armv7-a -mfloat-abi=softfp'.split()) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 30bbceb498..0bd82b769f 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -553,9 +553,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { static Vector<String> get_abis() { Vector<String> abis; - // We can still build armv6 in theory, but it doesn't make much - // sense for games, so disabling for now. - //abis.push_back("armeabi"); abis.push_back("armeabi-v7a"); abis.push_back("arm64-v8a"); abis.push_back("x86"); diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py index f33c77a407..5a708cdaca 100644 --- a/platform/haiku/detect.py +++ b/platform/haiku/detect.py @@ -80,7 +80,7 @@ def configure(env): env.ParseConfig('pkg-config freetype2 --cflags --libs') if not env['builtin_libpng']: - env.ParseConfig('pkg-config libpng --cflags --libs') + env.ParseConfig('pkg-config libpng16 --cflags --libs') if not env['builtin_bullet']: # We need at least version 2.88 diff --git a/platform/server/detect.py b/platform/server/detect.py index a5648d8d9d..a325395d6d 100644 --- a/platform/server/detect.py +++ b/platform/server/detect.py @@ -142,7 +142,7 @@ def configure(env): env.ParseConfig('pkg-config freetype2 --cflags --libs') if not env['builtin_libpng']: - env.ParseConfig('pkg-config libpng --cflags --libs') + env.ParseConfig('pkg-config libpng16 --cflags --libs') if not env['builtin_bullet']: # We need at least version 2.89 diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 6e6df08f02..5876a385c6 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1979,6 +1979,17 @@ bool OS_Windows::is_window_always_on_top() const { return video_mode.always_on_top; } +void OS_Windows::set_console_visible(bool p_enabled) { + if (console_visible == p_enabled) + return; + ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE); + console_visible = p_enabled; +} + +bool OS_Windows::is_console_visible() const { + return console_visible; +} + bool OS_Windows::get_window_per_pixel_transparency_enabled() const { if (!is_layered_allowed()) return false; @@ -3231,6 +3242,7 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { control_mem = false; meta_mem = false; minimized = false; + console_visible = IsWindowVisible(GetConsoleWindow()); hInstance = _hInstance; pressrc = 0; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 4660c16b97..fc8ad1b188 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -210,6 +210,7 @@ protected: bool maximized; bool minimized; bool borderless; + bool console_visible; public: LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -256,6 +257,8 @@ public: virtual bool is_window_maximized() const; virtual void set_window_always_on_top(bool p_enabled); virtual bool is_window_always_on_top() const; + virtual void set_console_visible(bool p_enabled); + virtual bool is_console_visible() const; virtual void request_attention(); virtual void set_borderless_window(bool p_borderless); diff --git a/platform/x11/detect.py b/platform/x11/detect.py index a502308eee..9614104750 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -75,11 +75,7 @@ def get_opts(): def get_flags(): - return [ - ('builtin_freetype', False), - ('builtin_libpng', False), - ('builtin_zlib', False), - ] + return [] def configure(env): @@ -216,7 +212,7 @@ def configure(env): env.ParseConfig('pkg-config freetype2 --cflags --libs') if not env['builtin_libpng']: - env.ParseConfig('pkg-config libpng --cflags --libs') + env.ParseConfig('pkg-config libpng16 --cflags --libs') if not env['builtin_bullet']: # We need at least version 2.89 diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 8726a9b3e7..fba1c26d1c 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -1393,10 +1393,10 @@ CPUParticles2D::CPUParticles2D() { set_spread(45); set_flatness(0); - set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); + set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0); + set_param(PARAM_ANGULAR_VELOCITY, 0); set_param(PARAM_ORBIT_VELOCITY, 0); set_param(PARAM_LINEAR_ACCEL, 0); - set_param(PARAM_ANGULAR_VELOCITY, 0); set_param(PARAM_RADIAL_ACCEL, 0); set_param(PARAM_TANGENTIAL_ACCEL, 0); set_param(PARAM_DAMPING, 0); diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 5b14b3e8e1..d8156a0afe 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -61,9 +61,7 @@ void Joint2D::_update_joint(bool p_only_free) { if (!body_a || !body_b) return; - if (!body_a) { - SWAP(body_a, body_b); - } + SWAP(body_a, body_b); joint = _configure_joint(body_a, body_b); diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index 383f02ca35..ee5d416930 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -1461,7 +1461,8 @@ CPUParticles::CPUParticles() { set_spread(45); set_flatness(0); - set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); + set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0); + set_param(PARAM_ANGULAR_VELOCITY, 0); set_param(PARAM_ORBIT_VELOCITY, 0); set_param(PARAM_LINEAR_ACCEL, 0); set_param(PARAM_RADIAL_ACCEL, 0); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 75088c79fe..54df346374 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -561,14 +561,24 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float #endif if (can_call) { - MessageQueue::get_singleton()->push_call( - nc->node, - method, - s >= 1 ? params[0] : Variant(), - s >= 2 ? params[1] : Variant(), - s >= 3 ? params[2] : Variant(), - s >= 4 ? params[3] : Variant(), - s >= 5 ? params[4] : Variant()); + if (method_call_mode == ANIMATION_METHOD_CALL_DEFERRED) { + MessageQueue::get_singleton()->push_call( + nc->node, + method, + s >= 1 ? params[0] : Variant(), + s >= 2 ? params[1] : Variant(), + s >= 3 ? params[2] : Variant(), + s >= 4 ? params[3] : Variant(), + s >= 5 ? params[4] : Variant()); + } else { + nc->node->call( + method, + s >= 1 ? params[0] : Variant(), + s >= 2 ? params[1] : Variant(), + s >= 3 ? params[2] : Variant(), + s >= 4 ? params[3] : Variant(), + s >= 5 ? params[4] : Variant()); + } } } @@ -1470,6 +1480,16 @@ AnimationPlayer::AnimationProcessMode AnimationPlayer::get_animation_process_mod return animation_process_mode; } +void AnimationPlayer::set_method_call_mode(AnimationMethodCallMode p_mode) { + + method_call_mode = p_mode; +} + +AnimationPlayer::AnimationMethodCallMode AnimationPlayer::get_method_call_mode() const { + + return method_call_mode; +} + void AnimationPlayer::_set_process(bool p_process, bool p_force) { if (processing == p_process && !p_force) @@ -1657,6 +1677,9 @@ 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("set_method_call_mode", "mode"), &AnimationPlayer::set_method_call_mode); + ClassDB::bind_method(D_METHOD("get_method_call_mode"), &AnimationPlayer::get_method_call_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); @@ -1675,6 +1698,7 @@ void AnimationPlayer::_bind_methods() { 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::BOOL, "playback_active", PROPERTY_HINT_NONE, "", 0), "set_active", "is_active"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "method_call_mode", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_method_call_mode", "get_method_call_mode"); ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "anim_name"))); ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); @@ -1684,6 +1708,9 @@ void AnimationPlayer::_bind_methods() { BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL); + + BIND_ENUM_CONSTANT(ANIMATION_METHOD_CALL_DEFERRED); + BIND_ENUM_CONSTANT(ANIMATION_METHOD_CALL_IMMEDIATE); } AnimationPlayer::AnimationPlayer() { @@ -1696,6 +1723,7 @@ AnimationPlayer::AnimationPlayer() { end_reached = false; end_notify = false; animation_process_mode = ANIMATION_PROCESS_IDLE; + method_call_mode = ANIMATION_METHOD_CALL_DEFERRED; processing = false; default_blend_time = 0; root = SceneStringNames::get_singleton()->path_pp; diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index fea4819821..f3d38110c6 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -68,6 +68,11 @@ public: ANIMATION_PROCESS_MANUAL, }; + enum AnimationMethodCallMode { + ANIMATION_METHOD_CALL_DEFERRED, + ANIMATION_METHOD_CALL_IMMEDIATE, + }; + private: enum { @@ -246,6 +251,7 @@ private: String autoplay; AnimationProcessMode animation_process_mode; + AnimationMethodCallMode method_call_mode; bool processing; bool active; @@ -338,6 +344,9 @@ public: void set_animation_process_mode(AnimationProcessMode p_mode); AnimationProcessMode get_animation_process_mode() const; + void set_method_call_mode(AnimationMethodCallMode p_mode); + AnimationMethodCallMode get_method_call_mode() const; + void seek(float p_time, bool p_update = false); void seek_delta(float p_time, float p_delta); float get_current_animation_position() const; @@ -363,5 +372,6 @@ public: }; VARIANT_ENUM_CAST(AnimationPlayer::AnimationProcessMode); +VARIANT_ENUM_CAST(AnimationPlayer::AnimationMethodCallMode); #endif diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index fadf5e432c..52fcea2a71 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -61,37 +61,7 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) { bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) > 0; if (button_masked || ui_accept) { - if (p_event->is_pressed()) { - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - } - - if (status.press_attempt && status.pressing_inside) { - if (toggle_mode) { - if ((p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_PRESS) || (!p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_RELEASE)) { - if (action_mode == ACTION_MODE_BUTTON_PRESS) { - status.press_attempt = false; - status.pressing_inside = false; - } - status.pressed = !status.pressed; - _unpress_group(); - _toggled(status.pressed); - _pressed(); - } - } else { - if (!p_event->is_pressed()) { - _pressed(); - } - } - } - - if (!p_event->is_pressed()) { // pressed state should be correct with button_up signal - emit_signal("button_up"); - status.press_attempt = false; - } - - update(); + on_action_event(p_event); return; } @@ -177,6 +147,41 @@ void BaseButton::_toggled(bool p_pressed) { emit_signal("toggled", p_pressed); } +void BaseButton::on_action_event(Ref<InputEvent> p_event) { + + if (p_event->is_pressed()) { + status.press_attempt = true; + status.pressing_inside = true; + emit_signal("button_down"); + } + + if (status.press_attempt && status.pressing_inside) { + if (toggle_mode) { + if ((p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_PRESS) || (!p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_RELEASE)) { + if (action_mode == ACTION_MODE_BUTTON_PRESS) { + status.press_attempt = false; + status.pressing_inside = false; + } + status.pressed = !status.pressed; + _unpress_group(); + _toggled(status.pressed); + _pressed(); + } + } else { + if (!p_event->is_pressed()) { + _pressed(); + } + } + } + + if (!p_event->is_pressed()) { // pressed state should be correct with button_up signal + emit_signal("button_up"); + status.press_attempt = false; + } + + update(); +} + void BaseButton::pressed() { } @@ -345,16 +350,12 @@ Ref<ShortCut> BaseButton::get_shortcut() const { void BaseButton::_unhandled_input(Ref<InputEvent> p_event) { - if (!is_disabled() && is_visible_in_tree() && p_event->is_pressed() && !p_event->is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) { + if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) { if (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this)) return; //ignore because of modal window - if (is_toggle_mode()) { - set_pressed(!is_pressed()); // Also calls _toggled() internally. - } - - _pressed(); + on_action_event(p_event); } } diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index ef278d7406..ffccdd69d6 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -74,6 +74,8 @@ private: void _pressed(); void _toggled(bool p_pressed); + void on_action_event(Ref<InputEvent> p_event); + protected: virtual void pressed(); virtual void toggled(bool p_pressed); diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 686d1c96cc..a7c15151ae 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -439,27 +439,26 @@ double ScrollBar::get_grabber_size() const { } double ScrollBar::get_area_size() const { - - if (orientation == VERTICAL) { - - double area = get_size().height; - area -= get_stylebox("scroll")->get_minimum_size().height; - area -= get_icon("increment")->get_height(); - area -= get_icon("decrement")->get_height(); - area -= get_grabber_min_size(); - return area; - - } else if (orientation == HORIZONTAL) { - - double area = get_size().width; - area -= get_stylebox("scroll")->get_minimum_size().width; - area -= get_icon("increment")->get_width(); - area -= get_icon("decrement")->get_width(); - area -= get_grabber_min_size(); - return area; - } else { - - return 0; + switch (orientation) { + case VERTICAL: { + double area = get_size().height; + area -= get_stylebox("scroll")->get_minimum_size().height; + area -= get_icon("increment")->get_height(); + area -= get_icon("decrement")->get_height(); + area -= get_grabber_min_size(); + return area; + } break; + case HORIZONTAL: { + double area = get_size().width; + area -= get_stylebox("scroll")->get_minimum_size().width; + area -= get_icon("increment")->get_width(); + area -= get_icon("decrement")->get_width(); + area -= get_grabber_min_size(); + return area; + } break; + default: { + return 0.0; + } } } diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 36571cc878..7b0836cd28 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -892,6 +892,8 @@ void Tabs::ensure_tab_visible(int p_idx) { } Rect2 Tabs::get_tab_rect(int p_tab) const { + + ERR_FAIL_INDEX_V(p_tab, tabs.size(), Rect2()); return Rect2(tabs[p_tab].ofs_cache, 0, tabs[p_tab].size_cache, get_size().height); } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 36d7dad1d3..4e86e4bb1e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1178,7 +1178,7 @@ void TextEdit::_notification(int p_what) { if (brace_open_mismatch) color = cache.brace_mismatch_color; - drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_color_selected : color); } if ((brace_close_match_line == line && brace_close_match_column == last_wrap_column + j) || @@ -1186,7 +1186,7 @@ void TextEdit::_notification(int p_what) { if (brace_close_mismatch) color = cache.brace_mismatch_color; - drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_color_selected : color); } } @@ -1258,23 +1258,23 @@ void TextEdit::_notification(int p_what) { if (str[j] >= 32) { int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2; - int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_color_selected : color); if (underlined) { float line_width = 1.0; #ifdef TOOLS_ENABLED line_width *= EDSCALE; #endif - draw_rect(Rect2(char_ofs + char_margin + ofs_x, yofs + ascent + 2, w, line_width), in_selection && override_selected_font_color ? cache.font_selected_color : color); + draw_rect(Rect2(char_ofs + char_margin + ofs_x, yofs + ascent + 2, w, line_width), in_selection && override_selected_font_color ? cache.font_color_selected : 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_x, 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_color_selected : color); } if (draw_spaces && str[j] == ' ') { int yofs = (get_row_height() - cache.space_icon->get_height()) / 2; - cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color); + cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_color_selected : color); } char_ofs += char_w; @@ -4554,7 +4554,7 @@ void TextEdit::_update_caches() { cache.line_number_color = get_color("line_number_color"); cache.safe_line_number_color = get_color("safe_line_number_color"); cache.font_color = get_color("font_color"); - cache.font_selected_color = get_color("font_selected_color"); + cache.font_color_selected = get_color("font_color_selected"); cache.keyword_color = get_color("keyword_color"); cache.function_color = get_color("function_color"); cache.member_variable_color = get_color("member_variable_color"); @@ -6452,6 +6452,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text"), &TextEdit::get_text); ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line); + ClassDB::bind_method(D_METHOD("center_viewport_to_cursor"), &TextEdit::center_viewport_to_cursor); ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true)); ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden", "wrap_index"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true), DEFVAL(0)); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 3e852deda6..c721cf992e 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -184,7 +184,7 @@ private: Color line_number_color; Color safe_line_number_color; Color font_color; - Color font_selected_color; + Color font_color_selected; Color keyword_color; Color number_color; Color function_color; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 522c1ecb6a..54370d02ba 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3163,10 +3163,7 @@ bool Tree::is_anything_selected() { void Tree::clear() { - if (blocked > 0) { - - ERR_FAIL_COND(blocked > 0); - } + ERR_FAIL_COND(blocked > 0); if (pressing_for_editor) { if (range_drag_enabled) { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index f8a0db18b1..10e5ad78e2 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1444,9 +1444,7 @@ void Viewport::_gui_show_tooltip() { return; } - Control *rp = which; //->get_root_parent_control(); - if (!rp) - return; + Control *rp = which; gui.tooltip_popup = which->make_custom_tooltip(tooltip); diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 950518aa6e..cb710dde43 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -51,6 +51,7 @@ Curve::Curve() { _baked_cache_dirty = false; _min_value = 0; _max_value = 1; + _minmax_set_once = 0b00; } int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent, TangentMode left_mode, TangentMode right_mode) { @@ -282,20 +283,24 @@ void Curve::update_auto_tangents(int i) { #define MIN_Y_RANGE 0.01 void Curve::set_min_value(float p_min) { - if (p_min > _max_value - MIN_Y_RANGE) + if (_minmax_set_once & 0b11 && p_min > _max_value - MIN_Y_RANGE) { _min_value = _max_value - MIN_Y_RANGE; - else + } else { + _minmax_set_once |= 0b10; // first bit is "min set" _min_value = p_min; + } // Note: min and max are indicative values, // it's still possible that existing points are out of range at this point. emit_signal(SIGNAL_RANGE_CHANGED); } void Curve::set_max_value(float p_max) { - if (p_max < _min_value + MIN_Y_RANGE) + if (_minmax_set_once & 0b11 && p_max < _min_value + MIN_Y_RANGE) { _max_value = _min_value + MIN_Y_RANGE; - else + } else { + _minmax_set_once |= 0b01; // second bit is "max set" _max_value = p_max; + } emit_signal(SIGNAL_RANGE_CHANGED); } diff --git a/scene/resources/curve.h b/scene/resources/curve.h index bb12baca48..b677097e86 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -143,6 +143,7 @@ private: int _bake_resolution; float _min_value; float _max_value; + int _minmax_set_once; // Encodes whether min and max have been set a first time, first bit for min and second for max. }; VARIANT_ENUM_CAST(Curve::TangentMode) diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp index 99ce8ef821..1ff02c2f82 100644 --- a/scene/resources/gradient.cpp +++ b/scene/resources/gradient.cpp @@ -143,6 +143,8 @@ void Gradient::set_points(Vector<Gradient::Point> &p_points) { } void Gradient::set_offset(int pos, const float offset) { + + ERR_FAIL_COND(pos < 0); if (points.size() <= pos) points.resize(pos + 1); points.write[pos].offset = offset; @@ -151,12 +153,12 @@ void Gradient::set_offset(int pos, const float offset) { } float Gradient::get_offset(int pos) const { - if (points.size() && points.size() > pos) - return points[pos].offset; - return 0; //TODO: Maybe throw some error instead? + ERR_FAIL_INDEX_V(pos, points.size(), 0.0); + return points[pos].offset; } void Gradient::set_color(int pos, const Color &color) { + ERR_FAIL_COND(pos < 0); if (points.size() <= pos) { points.resize(pos + 1); is_sorted = false; @@ -166,9 +168,8 @@ void Gradient::set_color(int pos, const Color &color) { } Color Gradient::get_color(int pos) const { - if (points.size() && points.size() > pos) - return points[pos].color; - return Color(0, 0, 0, 1); //TODO: Maybe throw some error instead? + ERR_FAIL_INDEX_V(pos, points.size(), Color()); + return points[pos].color; } int Gradient::get_points_count() const { diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 6dec4a0c49..197ff14b38 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -2353,8 +2353,8 @@ SpatialMaterial::SpatialMaterial() : set_ao_light_affect(0.0); - set_metallic_texture_channel(TEXTURE_CHANNEL_RED); - set_roughness_texture_channel(TEXTURE_CHANNEL_RED); + set_metallic_texture_channel(TEXTURE_CHANNEL_BLUE); + set_roughness_texture_channel(TEXTURE_CHANNEL_GREEN); set_ao_texture_channel(TEXTURE_CHANNEL_RED); set_refraction_texture_channel(TEXTURE_CHANNEL_RED); diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 758475b75e..a80a57a09c 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -1202,6 +1202,7 @@ ParticlesMaterial::ParticlesMaterial() : set_spread(45); set_flatness(0); set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0); + set_param(PARAM_ANGULAR_VELOCITY, 0); set_param(PARAM_ORBIT_VELOCITY, 0); set_param(PARAM_LINEAR_ACCEL, 0); set_param(PARAM_RADIAL_ACCEL, 0); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 0921c0dae9..efc1082a6b 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1225,10 +1225,7 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoaderText::load_interactive(const Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (err != OK) { - - ERR_FAIL_COND_V(err != OK, Ref<ResourceInteractiveLoader>()); - } + ERR_FAIL_COND_V(err != OK, Ref<ResourceInteractiveLoader>()); Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); String path = p_original_path != "" ? p_original_path : p_path; @@ -1324,10 +1321,7 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, Error err; FileAccess *f = FileAccess::open(p_src_path, FileAccess::READ, &err); - if (err != OK) { - - ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN); - } + ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN); Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); String path = p_src_path; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index d09fac47f0..899abfc9f9 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -692,6 +692,8 @@ String TileSet::tile_get_name(int p_id) const { } void TileSet::tile_clear_shapes(int p_id) { + + ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].shapes_data.clear(); } @@ -711,14 +713,15 @@ void TileSet::tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Transf int TileSet::tile_get_shape_count(int p_id) const { ERR_FAIL_COND_V(!tile_map.has(p_id), 0); - return tile_map[p_id].shapes_data.size(); } void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape) { ERR_FAIL_COND(!tile_map.has(p_id)); - if (tile_map[p_id].shapes_data.size() <= p_shape_id) + ERR_FAIL_COND(p_shape_id < 0); + + if (p_shape_id >= tile_map[p_id].shapes_data.size()) tile_map[p_id].shapes_data.resize(p_shape_id + 1); tile_map[p_id].shapes_data.write[p_shape_id].shape = p_shape; _decompose_convex_shape(p_shape); @@ -728,7 +731,7 @@ void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_sha Ref<Shape2D> TileSet::tile_get_shape(int p_id, int p_shape_id) const { ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<Shape2D>()); - if (tile_map[p_id].shapes_data.size() > p_shape_id) + if (p_shape_id < tile_map[p_id].shapes_data.size()) return tile_map[p_id].shapes_data[p_shape_id].shape; return Ref<Shape2D>(); @@ -737,7 +740,8 @@ Ref<Shape2D> TileSet::tile_get_shape(int p_id, int p_shape_id) const { void TileSet::tile_set_shape_transform(int p_id, int p_shape_id, const Transform2D &p_offset) { ERR_FAIL_COND(!tile_map.has(p_id)); - if (tile_map[p_id].shapes_data.size() <= p_shape_id) + + if (p_shape_id >= tile_map[p_id].shapes_data.size()) tile_map[p_id].shapes_data.resize(p_shape_id + 1); tile_map[p_id].shapes_data.write[p_shape_id].shape_transform = p_offset; emit_changed(); @@ -746,7 +750,7 @@ void TileSet::tile_set_shape_transform(int p_id, int p_shape_id, const Transform Transform2D TileSet::tile_get_shape_transform(int p_id, int p_shape_id) const { ERR_FAIL_COND_V(!tile_map.has(p_id), Transform2D()); - if (tile_map[p_id].shapes_data.size() > p_shape_id) + if (p_shape_id < tile_map[p_id].shapes_data.size()) return tile_map[p_id].shapes_data[p_shape_id].shape_transform; return Transform2D(); @@ -765,7 +769,9 @@ Vector2 TileSet::tile_get_shape_offset(int p_id, int p_shape_id) const { void TileSet::tile_set_shape_one_way(int p_id, int p_shape_id, const bool p_one_way) { ERR_FAIL_COND(!tile_map.has(p_id)); - if (tile_map[p_id].shapes_data.size() <= p_shape_id) + ERR_FAIL_COND(p_shape_id < 0); + + if (p_shape_id >= tile_map[p_id].shapes_data.size()) tile_map[p_id].shapes_data.resize(p_shape_id + 1); tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision = p_one_way; emit_changed(); @@ -774,23 +780,27 @@ void TileSet::tile_set_shape_one_way(int p_id, int p_shape_id, const bool p_one_ bool TileSet::tile_get_shape_one_way(int p_id, int p_shape_id) const { ERR_FAIL_COND_V(!tile_map.has(p_id), false); - if (tile_map[p_id].shapes_data.size() > p_shape_id) + if (p_shape_id < tile_map[p_id].shapes_data.size()) return tile_map[p_id].shapes_data[p_shape_id].one_way_collision; return false; } void TileSet::tile_set_shape_one_way_margin(int p_id, int p_shape_id, float p_margin) { + ERR_FAIL_COND(!tile_map.has(p_id)); - if (tile_map[p_id].shapes_data.size() <= p_shape_id) + ERR_FAIL_COND(p_shape_id < 0); + + if (p_shape_id >= tile_map[p_id].shapes_data.size()) tile_map[p_id].shapes_data.resize(p_shape_id + 1); tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision_margin = p_margin; emit_changed(); } float TileSet::tile_get_shape_one_way_margin(int p_id, int p_shape_id) const { + ERR_FAIL_COND_V(!tile_map.has(p_id), 0); - if (tile_map[p_id].shapes_data.size() > p_shape_id) + if (p_shape_id < tile_map[p_id].shapes_data.size()) return tile_map[p_id].shapes_data[p_shape_id].one_way_collision_margin; return 0; @@ -820,7 +830,9 @@ void TileSet::autotile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> } Ref<OccluderPolygon2D> TileSet::autotile_get_light_occluder(int p_id, const Vector2 &p_coord) const { + ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<OccluderPolygon2D>()); + if (!tile_map[p_id].autotile_data.occluder_map.has(p_coord)) { return Ref<OccluderPolygon2D>(); } else { diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index dd595d9ff8..a3813f8fc6 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1762,6 +1762,7 @@ void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) { for (int i = 0; i < input_port_count; i++) { Vector<String> arr = input_strings[i].split(","); + ERR_FAIL_COND(arr.size() != 3); int port_idx = arr[0].to_int(); int port_type = arr[1].to_int(); @@ -1794,6 +1795,7 @@ void VisualShaderNodeGroupBase::set_outputs(const String &p_outputs) { for (int i = 0; i < output_port_count; i++) { Vector<String> arr = output_strings[i].split(","); + ERR_FAIL_COND(arr.size() != 3); int port_idx = arr[0].to_int(); int port_type = arr[1].to_int(); @@ -1810,6 +1812,23 @@ String VisualShaderNodeGroupBase::get_outputs() const { return outputs; } +bool VisualShaderNodeGroupBase::is_valid_port_name(const String &p_name) const { + if (!p_name.is_valid_identifier()) { + return false; + } + for (int i = 0; i < get_input_port_count(); i++) { + if (get_input_port_name(i) == p_name) { + return false; + } + } + for (int i = 0; i < get_output_port_count(); i++) { + if (get_output_port_name(i) == p_name) { + return false; + } + } + return true; +} + void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const String &p_name) { String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";"; @@ -1849,6 +1868,8 @@ void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const Strin void VisualShaderNodeGroupBase::remove_input_port(int p_id) { + ERR_FAIL_COND(!has_input_port(p_id)); + Vector<String> inputs_strings = inputs.split(";", false); int count = 0; int index = 0; @@ -1917,6 +1938,8 @@ void VisualShaderNodeGroupBase::add_output_port(int p_id, int p_type, const Stri void VisualShaderNodeGroupBase::remove_output_port(int p_id) { + ERR_FAIL_COND(!has_output_port(p_id)); + Vector<String> outputs_strings = outputs.split(";", false); int count = 0; int index = 0; @@ -1956,6 +1979,9 @@ void VisualShaderNodeGroupBase::clear_output_ports() { void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) { + ERR_FAIL_COND(!has_input_port(p_id)); + ERR_FAIL_COND(p_type < 0 || p_type > PORT_TYPE_TRANSFORM); + if (input_ports[p_id].type == p_type) return; @@ -1986,6 +2012,9 @@ VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_input_port_ty void VisualShaderNodeGroupBase::set_input_port_name(int p_id, const String &p_name) { + ERR_FAIL_COND(!has_input_port(p_id)); + ERR_FAIL_COND(!is_valid_port_name(p_name)); + if (input_ports[p_id].name == p_name) return; @@ -2016,6 +2045,9 @@ String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const { void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) { + ERR_FAIL_COND(!has_output_port(p_id)); + ERR_FAIL_COND(p_type < 0 || p_type > PORT_TYPE_TRANSFORM); + if (output_ports[p_id].type == p_type) return; @@ -2045,6 +2077,10 @@ VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_output_port_t } void VisualShaderNodeGroupBase::set_output_port_name(int p_id, const String &p_name) { + + ERR_FAIL_COND(!has_output_port(p_id)); + ERR_FAIL_COND(!is_valid_port_name(p_name)); + if (output_ports[p_id].name == p_name) return; @@ -2125,6 +2161,8 @@ void VisualShaderNodeGroupBase::_bind_methods() { ClassDB::bind_method(D_METHOD("set_outputs", "outputs"), &VisualShaderNodeGroupBase::set_outputs); ClassDB::bind_method(D_METHOD("get_outputs"), &VisualShaderNodeGroupBase::get_outputs); + ClassDB::bind_method(D_METHOD("is_valid_port_name", "name"), &VisualShaderNodeGroupBase::is_valid_port_name); + ClassDB::bind_method(D_METHOD("add_input_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_input_port); ClassDB::bind_method(D_METHOD("remove_input_port", "id"), &VisualShaderNodeGroupBase::remove_input_port); ClassDB::bind_method(D_METHOD("get_input_port_count"), &VisualShaderNodeGroupBase::get_input_port_count); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 1ab3c0c9cc..a36776e701 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -355,6 +355,8 @@ public: void set_outputs(const String &p_outputs); String get_outputs() const; + bool is_valid_port_name(const String &p_name) const; + void add_input_port(int p_id, int p_type, const String &p_name); void remove_input_port(int p_id); virtual int get_input_port_count() const; diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index b4c3670a7b..172a2a3429 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -346,8 +346,7 @@ void BodySW::set_state(PhysicsServer::BodyState p_state, const Variant &p_varian //biased_angular_velocity=Vector3(); set_active(false); } else { - if (mode != PhysicsServer::BODY_MODE_STATIC) - set_active(true); + set_active(true); } } break; case PhysicsServer::BODY_STATE_CAN_SLEEP: { diff --git a/servers/physics/gjk_epa.cpp b/servers/physics/gjk_epa.cpp index ae512183fd..1d5ca42838 100644 --- a/servers/physics/gjk_epa.cpp +++ b/servers/physics/gjk_epa.cpp @@ -722,7 +722,10 @@ struct GJK append(m_stock,face); return(0); } - m_status=m_stock.root?eStatus::OutOfVertices:eStatus::OutOfFaces; + // -- GODOT start -- + //m_status=m_stock.root?eStatus::OutOfVertices:eStatus::OutOfFaces; + m_status=eStatus::OutOfFaces; + // -- GODOT end -- return(0); } sFace* findbest() diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index bc6010117c..75910ff1c0 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -137,6 +137,8 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC3); |