diff options
118 files changed, 2511 insertions, 288 deletions
diff --git a/core/os/input.cpp b/core/os/input.cpp index caa9fb1493..63bf1db499 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -89,6 +89,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f)); ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release); ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW)); + ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape); ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event); ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input); diff --git a/core/os/input.h b/core/os/input.h index c8b80b28d0..de04f239e6 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -121,10 +121,10 @@ public: virtual bool is_emulating_touch_from_mouse() const = 0; virtual bool is_emulating_mouse_from_touch() const = 0; - virtual CursorShape get_default_cursor_shape() = 0; + virtual CursorShape get_default_cursor_shape() const = 0; virtual void set_default_cursor_shape(CursorShape p_shape) = 0; + virtual CursorShape get_current_cursor_shape() const = 0; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0; - virtual void set_mouse_in_window(bool p_in_window) = 0; virtual String get_joy_button_string(int p_button) = 0; virtual String get_joy_axis_string(int p_axis) = 0; diff --git a/core/os/os.cpp b/core/os/os.cpp index 03e63f636e..ea378c9e83 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -220,6 +220,16 @@ int OS::get_virtual_keyboard_height() const { return 0; } +void OS::set_cursor_shape(CursorShape p_shape) { +} + +OS::CursorShape OS::get_cursor_shape() const { + return CURSOR_ARROW; +} + +void OS::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +} + void OS::print_all_resources(String p_to_file) { ERR_FAIL_COND(p_to_file != "" && _OSPRF); diff --git a/core/os/os.h b/core/os/os.h index d02d5a2c84..12012fba80 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -377,8 +377,9 @@ public: // returns height of the currently shown virtual keyboard (0 if keyboard is hidden) virtual int get_virtual_keyboard_height() const; - virtual void set_cursor_shape(CursorShape p_shape) = 0; - virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) = 0; + virtual void set_cursor_shape(CursorShape p_shape); + virtual CursorShape get_cursor_shape() const; + virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); virtual bool get_swap_ok_cancel() { return false; } virtual void dump_memory_to_file(const char *p_file); diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 5752cdca2b..c86d1567dd 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -501,7 +501,7 @@ Error ProjectSettings::_load_settings_binary(const String p_path) { d.resize(vlen); f->get_buffer(d.ptrw(), vlen); Variant value; - err = decode_variant(value, d.ptr(), d.size(), NULL, false); + err = decode_variant(value, d.ptr(), d.size(), NULL, true); ERR_EXPLAIN("Error decoding property: " + key); ERR_CONTINUE(err != OK); set(key, value); @@ -694,7 +694,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str file->store_string(key); int len; - err = encode_variant(value, NULL, len, false); + err = encode_variant(value, NULL, len, true); if (err != OK) memdelete(file); ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA); @@ -702,7 +702,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str Vector<uint8_t> buff; buff.resize(len); - err = encode_variant(value, buff.ptrw(), len, false); + err = encode_variant(value, buff.ptrw(), len, true); if (err != OK) memdelete(file); ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA); diff --git a/doc/classes/AnimatedSprite.xml b/doc/classes/AnimatedSprite.xml index 0ee1c75348..555169545e 100644 --- a/doc/classes/AnimatedSprite.xml +++ b/doc/classes/AnimatedSprite.xml @@ -23,6 +23,8 @@ </return> <argument index="0" name="anim" type="String" default=""""> </argument> + <argument index="1" name="backwards" type="bool" default="false"> + </argument> <description> Play the animation set in parameter. If no parameter is provided, the current animation is played. Property [code]backwards[/code] plays the animation in reverse if set to [code]true[/code]. </description> diff --git a/doc/classes/AudioEffectInstance.xml b/doc/classes/AudioEffectInstance.xml new file mode 100644 index 0000000000..ed42928eb1 --- /dev/null +++ b/doc/classes/AudioEffectInstance.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioEffectInstance" inherits="Reference" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/AudioEffectSpectrumAnalyzer.xml b/doc/classes/AudioEffectSpectrumAnalyzer.xml new file mode 100644 index 0000000000..5732039467 --- /dev/null +++ b/doc/classes/AudioEffectSpectrumAnalyzer.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioEffectSpectrumAnalyzer" inherits="AudioEffect" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="buffer_length" type="float" setter="set_buffer_length" getter="get_buffer_length"> + </member> + <member name="fft_size" type="int" setter="set_fft_size" getter="get_fft_size" enum="AudioEffectSpectrumAnalyzer.FFT_Size"> + </member> + <member name="tap_back_pos" type="float" setter="set_tap_back_pos" getter="get_tap_back_pos"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml b/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml new file mode 100644 index 0000000000..0c0061beb4 --- /dev/null +++ b/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioEffectSpectrumAnalyzerInstance" inherits="AudioEffectInstance" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_magnitude_for_frequency_range" qualifiers="const"> + <return type="Vector2"> + </return> + <argument index="0" name="from_hz" type="float"> + </argument> + <argument index="1" name="to_hz" type="float"> + </argument> + <argument index="2" name="mode" type="int" enum="AudioEffectSpectrumAnalyzerInstance.MagnitudeMode" default="1"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + <constant name="MAGNITUDE_AVERAGE" value="0" enum="MagnitudeMode"> + </constant> + <constant name="MAGNITUDE_MAX" value="1" enum="MagnitudeMode"> + </constant> + </constants> +</class> diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml index 82e17e4957..32eed54882 100644 --- a/doc/classes/AudioServer.xml +++ b/doc/classes/AudioServer.xml @@ -97,6 +97,18 @@ Returns the number of effects on the bus at [code]bus_idx[/code]. </description> </method> + <method name="get_bus_effect_instance"> + <return type="AudioEffectInstance"> + </return> + <argument index="0" name="bus_idx" type="int"> + </argument> + <argument index="1" name="effect_idx" type="int"> + </argument> + <argument index="2" name="channel" type="int" default="0"> + </argument> + <description> + </description> + </method> <method name="get_bus_index" qualifiers="const"> <return type="int"> </return> diff --git a/doc/classes/AudioStreamGenerator.xml b/doc/classes/AudioStreamGenerator.xml new file mode 100644 index 0000000000..e41b5827b1 --- /dev/null +++ b/doc/classes/AudioStreamGenerator.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioStreamGenerator" inherits="AudioStream" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="buffer_length" type="float" setter="set_buffer_length" getter="get_buffer_length"> + </member> + <member name="mix_rate" type="float" setter="set_mix_rate" getter="get_mix_rate"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml new file mode 100644 index 0000000000..4b4d622741 --- /dev/null +++ b/doc/classes/AudioStreamGeneratorPlayback.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioStreamGeneratorPlayback" inherits="AudioStreamPlaybackResampled" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="can_push_buffer" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="amount" type="int"> + </argument> + <description> + </description> + </method> + <method name="clear_buffer"> + <return type="void"> + </return> + <description> + </description> + </method> + <method name="get_frames_available" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_skips" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="push_buffer"> + <return type="bool"> + </return> + <argument index="0" name="frames" type="PoolVector2Array"> + </argument> + <description> + </description> + </method> + <method name="push_frame"> + <return type="bool"> + </return> + <argument index="0" name="frame" type="Vector2"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/AudioStreamPlaybackResampled.xml b/doc/classes/AudioStreamPlaybackResampled.xml new file mode 100644 index 0000000000..764f966167 --- /dev/null +++ b/doc/classes/AudioStreamPlaybackResampled.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioStreamPlaybackResampled" inherits="AudioStreamPlayback" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index d8b87a3c19..1681d796ea 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -19,6 +19,12 @@ Returns the position in the [AudioStream] in seconds. </description> </method> + <method name="get_stream_playback"> + <return type="AudioStreamPlayback"> + </return> + <description> + </description> + </method> <method name="play"> <return type="void"> </return> diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml index 1cd2bf7645..e001d11727 100644 --- a/doc/classes/AudioStreamPlayer2D.xml +++ b/doc/classes/AudioStreamPlayer2D.xml @@ -19,6 +19,12 @@ Returns the position in the [AudioStream]. </description> </method> + <method name="get_stream_playback"> + <return type="AudioStreamPlayback"> + </return> + <description> + </description> + </method> <method name="play"> <return type="void"> </return> diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml index 8ff5223e4f..0d973a761a 100644 --- a/doc/classes/AudioStreamPlayer3D.xml +++ b/doc/classes/AudioStreamPlayer3D.xml @@ -19,6 +19,12 @@ Returns the position in the [AudioStream]. </description> </method> + <method name="get_stream_playback"> + <return type="AudioStreamPlayback"> + </return> + <description> + </description> + </method> <method name="play"> <return type="void"> </return> diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 7b43d58c71..3710bc3de6 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -76,6 +76,12 @@ This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1,0 or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the grid map editor. For further details, refer to Godot source code. </description> </method> + <method name="get_rotation_quat"> + <return type="Quat"> + </return> + <description> + </description> + </method> <method name="get_scale"> <return type="Vector3"> </return> @@ -90,6 +96,16 @@ Return the inverse of the matrix. </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="b" type="Basis"> + </argument> + <argument index="1" name="epsilon" type="float" default="0.00001"> + </argument> + <description> + </description> + </method> <method name="orthonormalized"> <return type="Basis"> </return> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index c1cf7dcabe..61ccc167a5 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -575,7 +575,7 @@ <constant name="BLEND_MODE_DISABLED" value="5" enum="BlendMode"> Disable blending mode. Colors including alpha are written as is. Only applicable for render targets with a transparent background. No lighting will be applied. </constant> - <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="29"> + <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="2000"> Canvas item transform has changed. Notification is only received if enabled by [method set_notify_transform] or [method set_notify_local_transform]. </constant> <constant name="NOTIFICATION_DRAW" value="30"> diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml index 3d69c92ea3..04aa7fbbf2 100644 --- a/doc/classes/CanvasLayer.xml +++ b/doc/classes/CanvasLayer.xml @@ -25,6 +25,10 @@ <member name="custom_viewport" type="Node" setter="set_custom_viewport" getter="get_custom_viewport"> The custom [Viewport] node assigned to the [CanvasLayer]. If null, uses the default viewport instead. </member> + <member name="follow_viewport_enable" type="bool" setter="set_follow_viewport" getter="is_following_viewport"> + </member> + <member name="follow_viewport_scale" type="float" setter="set_follow_viewport_scale" getter="get_follow_viewport_scale"> + </member> <member name="layer" type="int" setter="set_layer" getter="get_layer"> Layer index for draw order. Lower values are drawn first. Default value: [code]1[/code]. </member> diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml new file mode 100644 index 0000000000..e0e56dc009 --- /dev/null +++ b/doc/classes/EditorFeatureProfile.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorFeatureProfile" inherits="Reference" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_feature_name"> + <return type="String"> + </return> + <argument index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature"> + </argument> + <description> + </description> + </method> + <method name="is_class_disabled" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="class_name" type="String"> + </argument> + <description> + </description> + </method> + <method name="is_class_editor_disabled" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="class_name" type="String"> + </argument> + <description> + </description> + </method> + <method name="is_class_property_disabled" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="class_name" type="String"> + </argument> + <argument index="1" name="arg1" type="String"> + </argument> + <description> + </description> + </method> + <method name="is_feature_disabled" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature"> + </argument> + <description> + </description> + </method> + <method name="load_from_file"> + <return type="int" enum="Error"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + </description> + </method> + <method name="save_to_file"> + <return type="int" enum="Error"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_disable_class"> + <return type="void"> + </return> + <argument index="0" name="class_name" type="String"> + </argument> + <argument index="1" name="disable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_disable_class_editor"> + <return type="void"> + </return> + <argument index="0" name="class_name" type="String"> + </argument> + <argument index="1" name="disable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_disable_class_property"> + <return type="void"> + </return> + <argument index="0" name="class_name" type="String"> + </argument> + <argument index="1" name="property" type="String"> + </argument> + <argument index="2" name="arg2" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_disable_feature"> + <return type="void"> + </return> + <argument index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature"> + </argument> + <argument index="1" name="disable" type="bool"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + <constant name="FEATURE_3D" value="0" enum="Feature"> + </constant> + <constant name="FEATURE_SCRIPT" value="1" enum="Feature"> + </constant> + <constant name="FEATURE_ASSET_LIB" value="2" enum="Feature"> + </constant> + <constant name="FEATURE_SCENE_TREE" value="3" enum="Feature"> + </constant> + <constant name="FEATURE_IMPORT_DOCK" value="4" enum="Feature"> + </constant> + <constant name="FEATURE_NODE_DOCK" value="5" enum="Feature"> + </constant> + <constant name="FEATURE_FILESYSTEM_DOCK" value="6" enum="Feature"> + </constant> + <constant name="FEATURE_MAX" value="7" enum="Feature"> + </constant> + </constants> +</class> diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index 30ff609a81..2dc8d716a7 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -48,6 +48,12 @@ Returns the editor [Viewport]. </description> </method> + <method name="get_inspector" qualifiers="const"> + <return type="EditorInspector"> + </return> + <description> + </description> + </method> <method name="get_open_scenes" qualifiers="const"> <return type="Array"> </return> diff --git a/doc/classes/File.xml b/doc/classes/File.xml index 8a785ab263..79462816e3 100644 --- a/doc/classes/File.xml +++ b/doc/classes/File.xml @@ -227,7 +227,7 @@ </return> <argument index="0" name="path" type="String"> </argument> - <argument index="1" name="flags" type="int"> + <argument index="1" name="flags" type="int" enum="File.ModeFlags"> </argument> <description> Opens the file for writing or reading, depending on the flags. @@ -238,9 +238,9 @@ </return> <argument index="0" name="path" type="String"> </argument> - <argument index="1" name="mode_flags" type="int"> + <argument index="1" name="mode_flags" type="int" enum="File.ModeFlags"> </argument> - <argument index="2" name="compression_mode" type="int" default="0"> + <argument index="2" name="compression_mode" type="int" enum="File.CompressionMode" default="0"> </argument> <description> Opens a compressed file for reading or writing. Use COMPRESSION_* constants to set [code]compression_mode[/code]. @@ -251,7 +251,7 @@ </return> <argument index="0" name="path" type="String"> </argument> - <argument index="1" name="mode_flags" type="int"> + <argument index="1" name="mode_flags" type="int" enum="File.ModeFlags"> </argument> <argument index="2" name="key" type="PoolByteArray"> </argument> @@ -264,7 +264,7 @@ </return> <argument index="0" name="path" type="String"> </argument> - <argument index="1" name="mode_flags" type="int"> + <argument index="1" name="mode_flags" type="int" enum="File.ModeFlags"> </argument> <argument index="2" name="pass" type="String"> </argument> diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml index 8d8d4c46cc..6b7d9cc834 100644 --- a/doc/classes/MainLoop.xml +++ b/doc/classes/MainLoop.xml @@ -114,29 +114,29 @@ </method> </methods> <constants> - <constant name="NOTIFICATION_WM_MOUSE_ENTER" value="2"> + <constant name="NOTIFICATION_WM_MOUSE_ENTER" value="1002"> </constant> - <constant name="NOTIFICATION_WM_MOUSE_EXIT" value="3"> + <constant name="NOTIFICATION_WM_MOUSE_EXIT" value="1003"> </constant> - <constant name="NOTIFICATION_WM_FOCUS_IN" value="4"> + <constant name="NOTIFICATION_WM_FOCUS_IN" value="1004"> </constant> - <constant name="NOTIFICATION_WM_FOCUS_OUT" value="5"> + <constant name="NOTIFICATION_WM_FOCUS_OUT" value="1005"> </constant> - <constant name="NOTIFICATION_WM_QUIT_REQUEST" value="6"> + <constant name="NOTIFICATION_WM_QUIT_REQUEST" value="1006"> </constant> - <constant name="NOTIFICATION_WM_GO_BACK_REQUEST" value="7"> + <constant name="NOTIFICATION_WM_GO_BACK_REQUEST" value="1007"> </constant> - <constant name="NOTIFICATION_WM_UNFOCUS_REQUEST" value="8"> + <constant name="NOTIFICATION_WM_UNFOCUS_REQUEST" value="1008"> </constant> - <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="9"> + <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="1009"> </constant> - <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="90"> + <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="1010"> </constant> - <constant name="NOTIFICATION_WM_ABOUT" value="91"> + <constant name="NOTIFICATION_WM_ABOUT" value="1011"> </constant> - <constant name="NOTIFICATION_CRASH" value="92"> + <constant name="NOTIFICATION_CRASH" value="1012"> </constant> - <constant name="NOTIFICATION_OS_IME_UPDATE" value="93"> + <constant name="NOTIFICATION_OS_IME_UPDATE" value="1013"> </constant> </constants> </class> diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml index 8fb10696f2..02d87a9c48 100644 --- a/doc/classes/MeshLibrary.xml +++ b/doc/classes/MeshLibrary.xml @@ -68,6 +68,14 @@ <description> </description> </method> + <method name="get_item_navmesh_transform" qualifiers="const"> + <return type="Transform"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <description> + </description> + </method> <method name="get_item_preview" qualifiers="const"> <return type="Texture"> </return> @@ -132,6 +140,16 @@ <description> </description> </method> + <method name="set_item_navmesh_transform"> + <return type="void"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <argument index="1" name="navmesh" type="Transform"> + </argument> + <description> + </description> + </method> <method name="set_item_preview"> <return type="void"> </return> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index bf32d4041a..646b921743 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -886,15 +886,37 @@ <constant name="NOTIFICATION_PATH_CHANGED" value="23"> Notification received when the node's [NodePath] changed. </constant> - <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="24"> - Notification received when translations may have changed. Can be triggered by the user changing the locale. Can be used to respond to language changes, for example to change the UI strings on the fly. Useful when working with the built-in translation support, like [method Object.tr]. - </constant> <constant name="NOTIFICATION_INTERNAL_PROCESS" value="25"> Notification received every frame when the internal process flag is set (see [method set_process_internal]). </constant> <constant name="NOTIFICATION_INTERNAL_PHYSICS_PROCESS" value="26"> Notification received every frame when the internal physics process flag is set (see [method set_physics_process_internal]). </constant> + <constant name="NOTIFICATION_WM_MOUSE_ENTER" value="1002"> + </constant> + <constant name="NOTIFICATION_WM_MOUSE_EXIT" value="1003"> + </constant> + <constant name="NOTIFICATION_WM_FOCUS_IN" value="1004"> + </constant> + <constant name="NOTIFICATION_WM_FOCUS_OUT" value="1005"> + </constant> + <constant name="NOTIFICATION_WM_QUIT_REQUEST" value="1006"> + </constant> + <constant name="NOTIFICATION_WM_GO_BACK_REQUEST" value="1007"> + </constant> + <constant name="NOTIFICATION_WM_UNFOCUS_REQUEST" value="1008"> + </constant> + <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="1009"> + </constant> + <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="1010"> + Notification received when translations may have changed. Can be triggered by the user changing the locale. Can be used to respond to language changes, for example to change the UI strings on the fly. Useful when working with the built-in translation support, like [method Object.tr]. + </constant> + <constant name="NOTIFICATION_WM_ABOUT" value="1011"> + </constant> + <constant name="NOTIFICATION_CRASH" value="1012"> + </constant> + <constant name="NOTIFICATION_OS_IME_UPDATE" value="1013"> + </constant> <constant name="PAUSE_MODE_INHERIT" value="0" enum="PauseMode"> Inherits pause mode from the node's parent. For the root node, it is equivalent to PAUSE_MODE_STOP. Default. </constant> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index e67e3c9a03..ee3f3260d7 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -215,6 +215,8 @@ <member name="audio/channel_disable_time" type="float" setter="" getter=""> Audio buses will disable automatically when sound goes below a given DB threshold for a given time. This saves CPU as effects assigned to that bus will no longer do any processing. </member> + <member name="audio/default_bus_layout" type="String" setter="" getter=""> + </member> <member name="audio/driver" type="String" setter="" getter=""> </member> <member name="audio/enable_audio_input" type="bool" setter="" getter=""> diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml index 165ab0dc95..079d1388f0 100644 --- a/doc/classes/ResourceSaver.xml +++ b/doc/classes/ResourceSaver.xml @@ -27,7 +27,7 @@ </argument> <argument index="1" name="resource" type="Resource"> </argument> - <argument index="2" name="flags" type="int" default="0"> + <argument index="2" name="flags" type="int" enum="ResourceSaver.SaverFlags" default="0"> </argument> <description> Saves a resource to disk. diff --git a/doc/classes/Spatial.xml b/doc/classes/Spatial.xml index 7e42e06960..f28ddcf351 100644 --- a/doc/classes/Spatial.xml +++ b/doc/classes/Spatial.xml @@ -329,7 +329,7 @@ </signal> </signals> <constants> - <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="29"> + <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="2000"> Spatial nodes receives this notification when their global transform changes. This means that either the current or a parent node changed its transform. In order for [code]NOTIFICATION_TRANSFORM_CHANGED[/code] to work, users first need to ask for it, with [method set_notify_transform]. </constant> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 0cfa246275..67a9b80602 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -437,7 +437,7 @@ </return> <description> Returns [code]true[/code] if this string is free from characters that aren't allowed in file names, those being: - [code]: / \ ? * " | % < >[/code] + [code]: / \ ? * " | % < >[/code] </description> </method> <method name="is_valid_float"> diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml index d74f481f55..34f99755a4 100644 --- a/doc/classes/StyleBoxFlat.xml +++ b/doc/classes/StyleBoxFlat.xml @@ -148,12 +148,12 @@ <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color"> The color of the shadow. (This has no effect when shadow_size < 1) </member> - <member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size"> - The shadow size in pixels. - </member> <member name="shadow_offset" type="Vector2" setter="set_shadow_offset" getter="get_shadow_offset"> The shadow offset in pixels. Adjusts the position of the shadow relatively to the stylebox. </member> + <member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size"> + The shadow size in pixels. + </member> </members> <constants> </constants> diff --git a/doc/classes/TextureRect.xml b/doc/classes/TextureRect.xml index 7f26fe18e5..eb8014bab8 100644 --- a/doc/classes/TextureRect.xml +++ b/doc/classes/TextureRect.xml @@ -16,18 +16,18 @@ <member name="expand" type="bool" setter="set_expand" getter="has_expand"> If [code]true[/code], the texture scales to fit its bounding rectangle. Default value: [code]false[/code]. </member> - <member name="stretch_mode" type="int" setter="set_stretch_mode" getter="get_stretch_mode" enum="TextureRect.StretchMode"> - Controls the texture's behavior when resizing the node's bounding rectangle. See [enum StretchMode]. - </member> - <member name="texture" type="Texture" setter="set_texture" getter="get_texture"> - The node's [Texture] resource. - </member> <member name="flip_h" type="bool" setter="set_flip_h" getter="is_flipped_h"> If [code]true[/code], texture is flipped horizontally. Default value: [code]false[/code]. </member> <member name="flip_v" type="bool" setter="set_flip_v" getter="is_flipped_v"> If [code]true[/code], texture is flipped vertically. Default value: [code]false[/code]. </member> + <member name="stretch_mode" type="int" setter="set_stretch_mode" getter="get_stretch_mode" enum="TextureRect.StretchMode"> + Controls the texture's behavior when resizing the node's bounding rectangle. See [enum StretchMode]. + </member> + <member name="texture" type="Texture" setter="set_texture" getter="get_texture"> + The node's [Texture] resource. + </member> </members> <constants> <constant name="STRETCH_SCALE_ON_EXPAND" value="0" enum="StretchMode"> diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml index d2aa1a3f03..ea558735aa 100644 --- a/doc/classes/Thread.xml +++ b/doc/classes/Thread.xml @@ -34,7 +34,7 @@ </argument> <argument index="2" name="userdata" type="Variant" default="null"> </argument> - <argument index="3" name="priority" type="int" default="1"> + <argument index="3" name="priority" type="int" enum="Thread.Priority" default="1"> </argument> <description> Starts a new [Thread] that runs "method" on object "instance" with "userdata" passed as an argument. The "priority" of the [Thread] can be changed by passing a PRIORITY_* enum. diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 3c047487e0..54d9e05180 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -171,7 +171,7 @@ # Write your custom logic here. # To call the default method: .set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord) - [/codeblock] + [/codeblock] </description> </method> <method name="set_cellv"> diff --git a/doc/classes/Transform.xml b/doc/classes/Transform.xml index e110fa7b40..8c9a1a36b3 100644 --- a/doc/classes/Transform.xml +++ b/doc/classes/Transform.xml @@ -172,9 +172,9 @@ </constant> <constant name="FLIP_X" value="Transform( -1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> </constant> - <constant name="FLIP_Y" value="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <constant name="FLIP_Y" value="Transform( 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0 )"> </constant> - <constant name="FLIP_Z" value="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <constant name="FLIP_Z" value="Transform( 1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0 )"> </constant> </constants> </class> diff --git a/doc/classes/VisibilityNotifier.xml b/doc/classes/VisibilityNotifier.xml index e30078d82f..062371ba29 100644 --- a/doc/classes/VisibilityNotifier.xml +++ b/doc/classes/VisibilityNotifier.xml @@ -16,6 +16,7 @@ </return> <description> If [code]true[/code], the bounding box is on the screen. + Note: It takes one frame for the node's visibility to be assessed once added to the scene tree, so this method will return [code]false[/code] right after it is instantiated, even if it will be on screen in the draw pass. </description> </method> </methods> diff --git a/doc/classes/VisibilityNotifier2D.xml b/doc/classes/VisibilityNotifier2D.xml index 5689ced4bf..7b553c7518 100644 --- a/doc/classes/VisibilityNotifier2D.xml +++ b/doc/classes/VisibilityNotifier2D.xml @@ -16,6 +16,7 @@ </return> <description> If [code]true[/code], the bounding rectangle is on the screen. + Note: It takes one frame for the node's visibility to be assessed once added to the scene tree, so this method will return [code]false[/code] right after it is instantiated, even if it will be on screen in the draw pass. </description> </method> </methods> diff --git a/doc/classes/VisualShaderNodeBooleanConstant.xml b/doc/classes/VisualShaderNodeBooleanConstant.xml new file mode 100644 index 0000000000..dc2abfff25 --- /dev/null +++ b/doc/classes/VisualShaderNodeBooleanConstant.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeBooleanConstant" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="constant" type="bool" setter="set_constant" getter="get_constant"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeBooleanUniform.xml b/doc/classes/VisualShaderNodeBooleanUniform.xml new file mode 100644 index 0000000000..06dca13426 --- /dev/null +++ b/doc/classes/VisualShaderNodeBooleanUniform.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeBooleanUniform" inherits="VisualShaderNodeUniform" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeColorFunc.xml b/doc/classes/VisualShaderNodeColorFunc.xml new file mode 100644 index 0000000000..e906049cae --- /dev/null +++ b/doc/classes/VisualShaderNodeColorFunc.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeColorFunc" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeColorFunc.Function"> + </member> + </members> + <constants> + <constant name="FUNC_GRAYSCALE" value="0" enum="Function"> + </constant> + <constant name="FUNC_SEPIA" value="1" enum="Function"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeDeterminant.xml b/doc/classes/VisualShaderNodeDeterminant.xml new file mode 100644 index 0000000000..661894e7b6 --- /dev/null +++ b/doc/classes/VisualShaderNodeDeterminant.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeDeterminant" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeFaceForward.xml b/doc/classes/VisualShaderNodeFaceForward.xml new file mode 100644 index 0000000000..823e251203 --- /dev/null +++ b/doc/classes/VisualShaderNodeFaceForward.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeFaceForward" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeIf.xml b/doc/classes/VisualShaderNodeIf.xml new file mode 100644 index 0000000000..4e606b95aa --- /dev/null +++ b/doc/classes/VisualShaderNodeIf.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeIf" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeOuterProduct.xml b/doc/classes/VisualShaderNodeOuterProduct.xml new file mode 100644 index 0000000000..4ea4713428 --- /dev/null +++ b/doc/classes/VisualShaderNodeOuterProduct.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeOuterProduct" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarClamp.xml b/doc/classes/VisualShaderNodeScalarClamp.xml new file mode 100644 index 0000000000..66401c6bf6 --- /dev/null +++ b/doc/classes/VisualShaderNodeScalarClamp.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeScalarClamp" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarDerivativeFunc.xml b/doc/classes/VisualShaderNodeScalarDerivativeFunc.xml new file mode 100644 index 0000000000..c78be81034 --- /dev/null +++ b/doc/classes/VisualShaderNodeScalarDerivativeFunc.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeScalarDerivativeFunc" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeScalarDerivativeFunc.Function"> + </member> + </members> + <constants> + <constant name="FUNC_SUM" value="0" enum="Function"> + </constant> + <constant name="FUNC_X" value="1" enum="Function"> + </constant> + <constant name="FUNC_Y" value="2" enum="Function"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarFunc.xml b/doc/classes/VisualShaderNodeScalarFunc.xml index 67a5d3f5c4..66bdfab5a6 100644 --- a/doc/classes/VisualShaderNodeScalarFunc.xml +++ b/doc/classes/VisualShaderNodeScalarFunc.xml @@ -55,5 +55,27 @@ </constant> <constant name="FUNC_NEGATE" value="19" enum="Function"> </constant> + <constant name="FUNC_ACOSH" value="20" enum="Function"> + </constant> + <constant name="FUNC_ASINH" value="21" enum="Function"> + </constant> + <constant name="FUNC_ATANH" value="22" enum="Function"> + </constant> + <constant name="FUNC_DEGREES" value="23" enum="Function"> + </constant> + <constant name="FUNC_EXP2" value="24" enum="Function"> + </constant> + <constant name="FUNC_INVERSE_SQRT" value="25" enum="Function"> + </constant> + <constant name="FUNC_LOG2" value="26" enum="Function"> + </constant> + <constant name="FUNC_RADIANS" value="27" enum="Function"> + </constant> + <constant name="FUNC_RECIPROCAL" value="28" enum="Function"> + </constant> + <constant name="FUNC_ROUNDEVEN" value="29" enum="Function"> + </constant> + <constant name="FUNC_TRUNC" value="30" enum="Function"> + </constant> </constants> </class> diff --git a/doc/classes/VisualShaderNodeScalarOp.xml b/doc/classes/VisualShaderNodeScalarOp.xml index 34ec89f8be..c5a331679f 100644 --- a/doc/classes/VisualShaderNodeScalarOp.xml +++ b/doc/classes/VisualShaderNodeScalarOp.xml @@ -33,5 +33,7 @@ </constant> <constant name="OP_ATAN2" value="8" enum="Operator"> </constant> + <constant name="OP_STEP" value="9" enum="Operator"> + </constant> </constants> </class> diff --git a/doc/classes/VisualShaderNodeScalarSmoothStep.xml b/doc/classes/VisualShaderNodeScalarSmoothStep.xml new file mode 100644 index 0000000000..5be54d0b4f --- /dev/null +++ b/doc/classes/VisualShaderNodeScalarSmoothStep.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeScalarSmoothStep" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeSwitch.xml b/doc/classes/VisualShaderNodeSwitch.xml new file mode 100644 index 0000000000..1c346e7a1f --- /dev/null +++ b/doc/classes/VisualShaderNodeSwitch.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeSwitch" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTransformFunc.xml b/doc/classes/VisualShaderNodeTransformFunc.xml new file mode 100644 index 0000000000..601e66ca16 --- /dev/null +++ b/doc/classes/VisualShaderNodeTransformFunc.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTransformFunc" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeTransformFunc.Function"> + </member> + </members> + <constants> + <constant name="FUNC_INVERSE" value="0" enum="Function"> + </constant> + <constant name="FUNC_TRANSPOSE" value="1" enum="Function"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTransformMult.xml b/doc/classes/VisualShaderNodeTransformMult.xml index 47026b400e..e9c445526d 100644 --- a/doc/classes/VisualShaderNodeTransformMult.xml +++ b/doc/classes/VisualShaderNodeTransformMult.xml @@ -19,5 +19,9 @@ </constant> <constant name="OP_BxA" value="1" enum="Operator"> </constant> + <constant name="OP_AxB_COMP" value="2" enum="Operator"> + </constant> + <constant name="OP_BxA_COMP" value="3" enum="Operator"> + </constant> </constants> </class> diff --git a/doc/classes/VisualShaderNodeVectorClamp.xml b/doc/classes/VisualShaderNodeVectorClamp.xml new file mode 100644 index 0000000000..677625ebce --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorClamp.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorClamp" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorDerivativeFunc.xml b/doc/classes/VisualShaderNodeVectorDerivativeFunc.xml new file mode 100644 index 0000000000..e382cb0b58 --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorDerivativeFunc.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorDerivativeFunc" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeVectorDerivativeFunc.Function"> + </member> + </members> + <constants> + <constant name="FUNC_SUM" value="0" enum="Function"> + </constant> + <constant name="FUNC_X" value="1" enum="Function"> + </constant> + <constant name="FUNC_Y" value="2" enum="Function"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorDistance.xml b/doc/classes/VisualShaderNodeVectorDistance.xml new file mode 100644 index 0000000000..d83a520a46 --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorDistance.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorDistance" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorFunc.xml b/doc/classes/VisualShaderNodeVectorFunc.xml index 968d73d4e1..5e57d85b4c 100644 --- a/doc/classes/VisualShaderNodeVectorFunc.xml +++ b/doc/classes/VisualShaderNodeVectorFunc.xml @@ -27,5 +27,61 @@ </constant> <constant name="FUNC_HSV2RGB" value="5" enum="Function"> </constant> + <constant name="FUNC_ABS" value="6" enum="Function"> + </constant> + <constant name="FUNC_ACOS" value="7" enum="Function"> + </constant> + <constant name="FUNC_ACOSH" value="8" enum="Function"> + </constant> + <constant name="FUNC_ASIN" value="9" enum="Function"> + </constant> + <constant name="FUNC_ASINH" value="10" enum="Function"> + </constant> + <constant name="FUNC_ATAN" value="11" enum="Function"> + </constant> + <constant name="FUNC_ATANH" value="12" enum="Function"> + </constant> + <constant name="FUNC_CEIL" value="13" enum="Function"> + </constant> + <constant name="FUNC_COS" value="14" enum="Function"> + </constant> + <constant name="FUNC_COSH" value="15" enum="Function"> + </constant> + <constant name="FUNC_DEGREES" value="16" enum="Function"> + </constant> + <constant name="FUNC_EXP" value="17" enum="Function"> + </constant> + <constant name="FUNC_EXP2" value="18" enum="Function"> + </constant> + <constant name="FUNC_FLOOR" value="19" enum="Function"> + </constant> + <constant name="FUNC_FRAC" value="20" enum="Function"> + </constant> + <constant name="FUNC_INVERSE_SQRT" value="21" enum="Function"> + </constant> + <constant name="FUNC_LOG" value="22" enum="Function"> + </constant> + <constant name="FUNC_LOG2" value="23" enum="Function"> + </constant> + <constant name="FUNC_RADIANS" value="24" enum="Function"> + </constant> + <constant name="FUNC_ROUND" value="25" enum="Function"> + </constant> + <constant name="FUNC_ROUNDEVEN" value="26" enum="Function"> + </constant> + <constant name="FUNC_SIGN" value="27" enum="Function"> + </constant> + <constant name="FUNC_SIN" value="28" enum="Function"> + </constant> + <constant name="FUNC_SINH" value="29" enum="Function"> + </constant> + <constant name="FUNC_SQRT" value="30" enum="Function"> + </constant> + <constant name="FUNC_TAN" value="31" enum="Function"> + </constant> + <constant name="FUNC_TANH" value="32" enum="Function"> + </constant> + <constant name="FUNC_TRUNC" value="33" enum="Function"> + </constant> </constants> </class> diff --git a/doc/classes/VisualShaderNodeVectorOp.xml b/doc/classes/VisualShaderNodeVectorOp.xml index 16c1f8f25d..6524f129da 100644 --- a/doc/classes/VisualShaderNodeVectorOp.xml +++ b/doc/classes/VisualShaderNodeVectorOp.xml @@ -33,5 +33,11 @@ </constant> <constant name="OP_CROSS" value="8" enum="Operator"> </constant> + <constant name="OP_ATAN2" value="9" enum="Operator"> + </constant> + <constant name="OP_REFLECT" value="10" enum="Operator"> + </constant> + <constant name="OP_STEP" value="11" enum="Operator"> + </constant> </constants> </class> diff --git a/doc/classes/VisualShaderNodeVectorRefract.xml b/doc/classes/VisualShaderNodeVectorRefract.xml new file mode 100644 index 0000000000..32bb0692d4 --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorRefract.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorRefract" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorScalarSmoothStep.xml b/doc/classes/VisualShaderNodeVectorScalarSmoothStep.xml new file mode 100644 index 0000000000..a158b4731d --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorScalarSmoothStep.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorScalarSmoothStep" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorScalarStep.xml b/doc/classes/VisualShaderNodeVectorScalarStep.xml new file mode 100644 index 0000000000..88c9b006fc --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorScalarStep.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorScalarStep" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorSmoothStep.xml b/doc/classes/VisualShaderNodeVectorSmoothStep.xml new file mode 100644 index 0000000000..1ddd5f26ce --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorSmoothStep.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorSmoothStep" inherits="VisualShaderNode" category="Core" version="3.2"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/drivers/gles2/shaders/effect_blur.glsl b/drivers/gles2/shaders/effect_blur.glsl index a531802c75..df79e89931 100644 --- a/drivers/gles2/shaders/effect_blur.glsl +++ b/drivers/gles2/shaders/effect_blur.glsl @@ -116,12 +116,13 @@ void main() { #ifdef GAUSSIAN_HORIZONTAL vec2 pix_size = pixel_size; pix_size *= 0.5; //reading from larger buffer, so use more samples + // sigma 2 vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.214607; color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.157305; + color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.131514; color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.071303; color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.157305; + color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.131514; color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.071303; frag_color = color; #endif diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index fc15ca31b1..ff5a9f326f 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -117,12 +117,13 @@ void main() { #ifdef GAUSSIAN_HORIZONTAL vec2 pix_size = pixel_size; pix_size *= 0.5; //reading from larger buffer, so use more samples + // sigma 2 vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.214607; color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.157305; + color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.131514; color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.071303; color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.157305; + color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.131514; color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.071303; frag_color = color; #endif diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 09b23ae90e..2307d340d8 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -717,6 +717,9 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) { return; p_new_len = MAX(0.001, p_new_len); + if (use_fps && animation->get_step() > 0) { + p_new_len *= animation->get_step(); + } editing = true; undo_redo->create_action(TTR("Change Animation Length")); @@ -1017,7 +1020,11 @@ void AnimationTimelineEdit::update_values() { return; editing = true; - length->set_value(animation->get_length()); + if (use_fps && animation->get_step() > 0) { + length->set_value(animation->get_length() / animation->get_step()); + } else { + length->set_value(animation->get_length()); + } loop->set_pressed(animation->has_loop()); editing = false; } @@ -1104,6 +1111,7 @@ void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) { void AnimationTimelineEdit::set_use_fps(bool p_use_fps) { use_fps = p_use_fps; + update_values(); update(); } bool AnimationTimelineEdit::is_using_fps() const { @@ -1164,7 +1172,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() { len_hb->add_child(time_icon); length = memnew(EditorSpinSlider); length->set_min(0.001); - length->set_max(3600); + length->set_max(36000); length->set_step(0.01); length->set_allow_greater(true); length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0)); @@ -2532,6 +2540,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) { step->set_block_signals(false); step->set_read_only(false); snap->set_disabled(false); + snap_mode->set_disabled(true); } else { hscroll->hide(); edit->set_disabled(true); @@ -2540,6 +2549,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) { step->set_block_signals(false); step->set_read_only(true); snap->set_disabled(true); + snap_mode->set_disabled(false); } } @@ -3530,6 +3540,9 @@ void AnimationTrackEditor::_snap_mode_changed(int p_mode) { } void AnimationTrackEditor::_update_step_spinbox() { + if (!animation.is_valid()) { + return; + } step->set_block_signals(true); if (timeline->is_using_fps()) { @@ -5030,6 +5043,7 @@ AnimationTrackEditor::AnimationTrackEditor() { snap_mode->add_item(TTR("FPS")); bottom_hb->add_child(snap_mode); snap_mode->connect("item_selected", this, "_snap_mode_changed"); + snap_mode->set_disabled(true); bottom_hb->add_child(memnew(VSeparator)); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8a67002503..851d6a0aa6 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1306,6 +1306,7 @@ void EditorNode::_dialog_action(String p_file) { _save_default_environment(); _save_scene_with_preview(p_file, scene_idx); _add_to_recent_scenes(p_file); + save_layout(); if (scene_idx != -1) _discard_changes(); @@ -4069,6 +4070,7 @@ void EditorNode::_load_open_scenes_from_config(Ref<ConfigFile> p_layout, const S for (int i = 0; i < scenes.size(); i++) { load_scene(scenes[i]); } + save_layout(); restoring_scenes = false; } diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 0869f6ce77..9641e10114 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -687,7 +687,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE); theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01); theme->set_constant("draw_guides", "Tree", relationship_line_opacity < 0.01); - theme->set_constant("scroll_border", "Tree", default_margin_size * EDSCALE); + theme->set_constant("scroll_border", "Tree", 40 * EDSCALE); theme->set_constant("scroll_speed", "Tree", 12); Ref<StyleBoxFlat> style_tree_btn = style_default->duplicate(); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 5a1383be6d..c32cd1de50 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1021,6 +1021,7 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_ for (int j = 0; j < ed->get_edited_scene_count(); j++) { if (ed->get_scene_path(j) == file_changed_paths[i]) { ed->get_edited_scene_root(j)->set_filename(new_item_path); + editor->save_layout(); break; } } diff --git a/editor/icons/icon_auto_key.svg b/editor/icons/icon_auto_key.svg new file mode 100644 index 0000000000..cbafe1ac38 --- /dev/null +++ b/editor/icons/icon_auto_key.svg @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg6" + sodipodi:docname="icon_auto_key.svg" + inkscape:version="0.92.4 (5da689c313, 2019-01-14)"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1854" + inkscape:window-height="1016" + id="namedview8" + showgrid="false" + inkscape:zoom="10.429825" + inkscape:cx="10.199345" + inkscape:cy="-4.0344119" + inkscape:window-x="66" + inkscape:window-y="27" + inkscape:window-maximized="1" + inkscape:current-layer="svg6" /> + <path + style="fill:#e0e0e0;fill-opacity:1;stroke-width:0.0333107" + d="M 3.5469681,13.426786 C 2.7965829,13.263778 2.2774312,12.503915 2.4037297,11.753472 c 0.1081234,-0.642451 0.6006808,-1.135008 1.2431317,-1.243131 0.9667125,-0.162696 1.8555225,0.726112 1.6928259,1.692826 -0.103766,0.616558 -0.5592173,1.098057 -1.1588427,1.225117 -0.2719576,0.05763 -0.3626872,0.05741 -0.6338765,-0.0014 z m 8.0861339,-0.08275 c -0.746862,-0.13829 -1.23937,-0.720718 -1.23937,-1.465649 0,-0.527377 0.244831,-0.978806 0.679757,-1.253362 0.471386,-0.297574 1.114188,-0.297574 1.585574,0 0.682727,0.430986 0.892336,1.362194 0.460575,2.046149 -0.307786,0.487563 -0.940521,0.773963 -1.486536,0.672862 z M 0.60726032,9.8305658 V 7.7161233 L 1.1770842,7.7070075 1.7469079,7.6978939 3.1889882,5.1995916 4.6310686,2.7012893 h 3.1726318 3.1726316 l 1.442755,2.4983023 1.442755,2.4983023 0.651097,0.00903 0.651096,0.00903 v 2.1145264 2.1145257 h -0.566282 -0.566281 v -0.161225 c 0,-0.234927 -0.113135,-0.639704 -0.255664,-0.914727 -0.16895,-0.326004 -0.574198,-0.731251 -0.900202,-0.9002019 -0.656732,-0.3403483 -1.428549,-0.3403483 -2.085281,0 -0.326004,0.1689519 -0.731252,0.5741989 -0.9002019,0.9002029 -0.1425297,0.275023 -0.2556639,0.6798 -0.2556639,0.914727 v 0.161225 H 7.8570969 6.0797346 L 6.0617736,11.686851 C 6.006289,10.889347 5.447548,10.170679 4.6603773,9.884336 4.4466221,9.8065798 4.3737631,9.797427 3.9716406,9.7978134 3.5871254,9.7981885 3.4905638,9.809405 3.3054265,9.8752358 2.5067319,10.159236 1.9362359,10.884501 1.8813215,11.68568 l -0.017772,0.259329 H 1.2354063 0.60726287 Z M 12.399247,7.7466889 c 0,-0.037287 -0.02623,-0.1073444 -0.0583,-0.1556843 -0.03206,-0.04834 -0.561225,-0.958444 -1.17592,-2.0224529 L 10.047407,3.6339894 7.6977565,3.6254406 C 5.4917229,3.6174174 5.3450379,3.6204563 5.2979001,3.6754094 5.1898818,3.8013046 2.9723198,7.6840061 2.9723198,7.7472381 c 0,0.067139 0.00758,0.067247 4.7134636,0.067247 h 4.7134636 z" + id="path6243" + inkscape:connector-curvature="0" /> +</svg> diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index c3cac582ad..b2923a1ff2 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1340,6 +1340,10 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { // Confirms the node rotation if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Rotate CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, true, false, true); + } + drag_type = DRAG_NONE; return true; } @@ -1641,6 +1645,9 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { // Confirm resize if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Resize CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, false, true, true); + } drag_type = DRAG_NONE; viewport->update(); return true; @@ -1747,6 +1754,10 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { // Confirm resize if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Scale CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, false, true, true); + } + drag_type = DRAG_NONE; viewport->update(); return true; @@ -1852,6 +1863,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { _commit_canvas_item_state(drag_selection, TTR("Move CanvasItem"), true); } + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(true, false, false, true); + } drag_type = DRAG_NONE; viewport->update(); return true; @@ -3384,6 +3398,7 @@ void CanvasItemEditor::_notification(int p_what) { key_rot_button->set_icon(get_icon("KeyRotation", "EditorIcons")); key_scale_button->set_icon(get_icon("KeyScale", "EditorIcons")); key_insert_button->set_icon(get_icon("Key", "EditorIcons")); + key_auto_insert_button->set_icon(get_icon("AutoKey", "EditorIcons")); zoom_minus->set_icon(get_icon("ZoomLess", "EditorIcons")); zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); @@ -3716,6 +3731,77 @@ void CanvasItemEditor::_button_tool_select(int p_index) { tool = (Tool)p_index; } +void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing) { + + Map<Node *, Object *> &selection = editor_selection->get_selection(); + + for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { + + CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); + if (!canvas_item || !canvas_item->is_visible_in_tree()) + continue; + + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + continue; + + if (Object::cast_to<Node2D>(canvas_item)) { + Node2D *n2d = Object::cast_to<Node2D>(canvas_item); + + if (key_pos && p_location) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing); + if (key_rot && p_rotation) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), p_on_existing); + if (key_scale && p_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing); + + if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) { + //look for an IK chain + List<Node2D *> ik_chain; + + Node2D *n = Object::cast_to<Node2D>(n2d->get_parent_item()); + bool has_chain = false; + + while (n) { + + ik_chain.push_back(n); + if (n->has_meta("_edit_ik_")) { + has_chain = true; + break; + } + + if (!n->get_parent_item()) + break; + n = Object::cast_to<Node2D>(n->get_parent_item()); + } + + if (has_chain && ik_chain.size()) { + + for (List<Node2D *>::Element *F = ik_chain.front(); F; F = F->next()) { + + if (key_pos) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), p_on_existing); + if (key_rot) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), p_on_existing); + if (key_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), p_on_existing); + } + } + } + + } else if (Object::cast_to<Control>(canvas_item)) { + + Control *ctrl = Object::cast_to<Control>(canvas_item); + + if (key_pos) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing); + if (key_rot) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), p_on_existing); + if (key_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing); + } + } +} + void CanvasItemEditor::_popup_callback(int p_op) { last_option = MenuOption(p_op); @@ -3983,73 +4069,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { bool existing = p_op == ANIM_INSERT_KEY_EXISTING; - Map<Node *, Object *> &selection = editor_selection->get_selection(); - - for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); - if (!canvas_item || !canvas_item->is_visible_in_tree()) - continue; - - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) - continue; - - if (Object::cast_to<Node2D>(canvas_item)) { - Node2D *n2d = Object::cast_to<Node2D>(canvas_item); - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), existing); - - if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) { - //look for an IK chain - List<Node2D *> ik_chain; - - Node2D *n = Object::cast_to<Node2D>(n2d->get_parent_item()); - bool has_chain = false; - - while (n) { - - ik_chain.push_back(n); - if (n->has_meta("_edit_ik_")) { - has_chain = true; - break; - } - - if (!n->get_parent_item()) - break; - n = Object::cast_to<Node2D>(n->get_parent_item()); - } - - if (has_chain && ik_chain.size()) { - - for (List<Node2D *>::Element *F = ik_chain.front(); F; F = F->next()) { - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), existing); - } - } - } - - } else if (Object::cast_to<Control>(canvas_item)) { - - Control *ctrl = Object::cast_to<Control>(canvas_item); - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), existing); - } - } + _insert_animation_keys(true, true, true, existing); } break; case ANIM_INSERT_POS: { @@ -4866,6 +4886,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_loc_button->set_pressed(true); key_loc_button->set_focus_mode(FOCUS_NONE); key_loc_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_POS)); + key_loc_button->set_tooltip(TTR("Translation mask for inserting keys.")); animation_hb->add_child(key_loc_button); key_rot_button = memnew(Button); key_rot_button->set_toggle_mode(true); @@ -4873,21 +4894,30 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_rot_button->set_pressed(true); key_rot_button->set_focus_mode(FOCUS_NONE); key_rot_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_ROT)); + key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys.")); animation_hb->add_child(key_rot_button); key_scale_button = memnew(Button); key_scale_button->set_toggle_mode(true); key_scale_button->set_flat(true); key_scale_button->set_focus_mode(FOCUS_NONE); key_scale_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_SCALE)); + key_scale_button->set_tooltip(TTR("Scale mask for inserting keys.")); animation_hb->add_child(key_scale_button); key_insert_button = memnew(Button); key_insert_button->set_flat(true); key_insert_button->set_focus_mode(FOCUS_NONE); key_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY)); - key_insert_button->set_tooltip(TTR("Insert keys.")); + key_insert_button->set_tooltip(TTR("Insert keys (based on mask).")); key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), KEY_INSERT)); - animation_hb->add_child(key_insert_button); + key_auto_insert_button = memnew(Button); + key_auto_insert_button->set_flat(true); + key_auto_insert_button->set_toggle_mode(true); + key_auto_insert_button->set_focus_mode(FOCUS_NONE); + //key_auto_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY)); + key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated on scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time.")); + key_auto_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_auto_insert_key", TTR("Auto Insert Key"))); + animation_hb->add_child(key_auto_insert_button); animation_menu = memnew(MenuButton); animation_menu->set_text(TTR("Animation")); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 9173c55ae0..14ea81f302 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -351,6 +351,7 @@ private: Button *key_rot_button; Button *key_scale_button; Button *key_insert_button; + Button *key_auto_insert_button; PopupMenu *selection_menu; @@ -422,6 +423,8 @@ private: Object *_get_editor_data(Object *p_what); + void _insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing); + void _keying_changed(); void _unhandled_key_input(const Ref<InputEvent> &p_ev); diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h index 679235e316..701632e576 100644 --- a/editor/plugins/item_list_editor_plugin.h +++ b/editor/plugins/item_list_editor_plugin.h @@ -157,7 +157,7 @@ public: virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx, !p_enabled); } virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); } - virtual void set_item_id(int p_idx, int p_id) { pp->set_item_id(p_idx, p_idx); } + virtual void set_item_id(int p_idx, int p_id) { pp->set_item_id(p_idx, p_id); } virtual int get_item_id(int p_idx) const { return pp->get_item_id(p_idx); } virtual void set_item_separator(int p_idx, bool p_separator) { pp->set_item_as_separator(p_idx, p_separator); } diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 543771ad1c..c586985957 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -81,6 +81,8 @@ void ScriptTextEditor::set_edited_resource(const RES &p_res) { emit_signal("name_changed"); code_editor->update_line_and_column(); + + _validate_script(); } void ScriptTextEditor::_update_member_keywords() { diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 03277159fc..8cf00cf67d 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -1038,25 +1038,26 @@ void TileSetEditor::_on_workspace_overlay_draw() { tileset->get_tile_list(tiles); for (List<int>::Element *E = tiles->front(); E; E = E->next()) { int t_id = E->get(); - if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid) { - Rect2i region = tileset->tile_get_region(t_id); - region.position += WORKSPACE_MARGIN; - region.position *= workspace->get_scale().x; - Color c; - if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) - c = COLOR_SINGLE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) - c = COLOR_AUTOTILE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) - c = COLOR_ATLAS; - String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); - Ref<Font> font = get_font("font", "Label"); - region.set_size(font->get_string_size(tile_id_name)); - workspace_overlay->draw_rect(region, c); - region.position.y += region.size.y - 2; - c = Color(0.1, 0.1, 0.1); - workspace_overlay->draw_string(font, region.position, tile_id_name, c); - } + if (tileset->tile_get_texture(t_id)->get_rid() != current_texture_rid) + continue; + + Rect2 region = tileset->tile_get_region(t_id); + region.position += WORKSPACE_MARGIN; + region.position *= workspace->get_scale().x; + Color c; + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + c = COLOR_SINGLE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + c = COLOR_AUTOTILE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + c = COLOR_ATLAS; + String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); + Ref<Font> font = get_font("font", "Label"); + region.set_size(font->get_string_size(tile_id_name)); + workspace_overlay->draw_rect(region, c); + region.position.y += region.size.y - 2; + c = Color(0.1, 0.1, 0.1); + workspace_overlay->draw_string(font, region.position, tile_id_name, c); } } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 71e22afe95..0aba7f3d15 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1004,6 +1004,58 @@ void VisualShaderEditor::_duplicate_nodes() { } } +void VisualShaderEditor::_on_nodes_delete() { + + VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + List<int> to_erase; + + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); + if (gn) { + if (gn->is_selected() && gn->is_close_button_visible()) { + to_erase.push_back(gn->get_name().operator String().to_int()); + } + } + } + + if (to_erase.empty()) + return; + + undo_redo->create_action(TTR("Delete Nodes")); + + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { + undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, F->get()); + undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, visual_shader->get_node(type, F->get()), visual_shader->get_node_position(type, F->get()), F->get()); + } + + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + + List<VisualShader::Connection> used_conns; + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + if (E->get().from_node == F->get() || E->get().to_node == F->get()) { + + bool cancel = false; + for (List<VisualShader::Connection>::Element *R = used_conns.front(); R; R = R->next()) { + if (R->get().from_node == E->get().from_node && R->get().from_port == E->get().from_port && R->get().to_node == E->get().to_node && R->get().to_port == E->get().to_port) { + cancel = true; // to avoid ERR_ALREADY_EXISTS warning + break; + } + } + if (!cancel) { + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + used_conns.push_back(E->get()); + } + } + } + } + + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); +} + void VisualShaderEditor::_mode_selected(int p_id) { _update_options_menu(); _update_graph(); @@ -1175,6 +1227,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_node_selected", &VisualShaderEditor::_node_selected); ClassDB::bind_method("_scroll_changed", &VisualShaderEditor::_scroll_changed); ClassDB::bind_method("_delete_request", &VisualShaderEditor::_delete_request); + ClassDB::bind_method("_on_nodes_delete", &VisualShaderEditor::_on_nodes_delete); ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed); ClassDB::bind_method("_edit_port_default_input", &VisualShaderEditor::_edit_port_default_input); ClassDB::bind_method("_port_edited", &VisualShaderEditor::_port_edited); @@ -1224,6 +1277,7 @@ VisualShaderEditor::VisualShaderEditor() { graph->connect("node_selected", this, "_node_selected"); graph->connect("scroll_offset_changed", this, "_scroll_changed"); graph->connect("duplicate_nodes_request", this, "_duplicate_nodes"); + graph->connect("delete_nodes_request", this, "_on_nodes_delete"); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 2709d72931..4b0b48ad92 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -143,6 +143,7 @@ class VisualShaderEditor : public VBoxContainer { void _node_selected(Object *p_node); void _delete_request(int); + void _on_nodes_delete(); void _removed_from_graph(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 752c1afff2..bd245d5da9 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1741,7 +1741,7 @@ void SceneTreeDock::_update_script_button() { button_clear_script->show(); } } else { - button_create_script->show(); + button_create_script->hide(); Array selection = editor_selection->get_selected_nodes(); for (int i = 0; i < selection.size(); i++) { Node *n = Object::cast_to<Node>(selection[i]); @@ -2208,17 +2208,20 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (profile_allow_script_editing) { - if (!existing_script.is_valid()) { - menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); + if (selection.size() == 1) { + if (!existing_script.is_valid()) { + menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); + } else { + menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_ATTACH_SCRIPT); + } } if (selection.size() > 1 || existing_script.is_valid()) { menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); - menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_ATTACH_SCRIPT); } + menu->add_separator(); } if (profile_allow_editing) { - menu->add_separator(); if (selection.size() == 1) { menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); } @@ -2230,12 +2233,12 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("MoveDown", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN); menu->add_icon_shortcut(get_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE); menu->add_icon_shortcut(get_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT); + menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); } } if (selection.size() == 1) { if (profile_allow_editing) { - menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); menu->add_separator(); menu->add_icon_shortcut(get_icon("Blend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/merge_from_scene"), TOOL_MERGE_FROM_SCENE); menu->add_icon_shortcut(get_icon("CreateNewSceneFrom", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM); @@ -2277,7 +2280,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME); } menu->add_separator(); - menu->add_icon_item(get_icon("Help", "EditorIcons"), TTR("Open documentation"), TOOL_OPEN_DOCUMENTATION); + menu->add_icon_item(get_icon("Help", "EditorIcons"), TTR("Open Documentation"), TOOL_OPEN_DOCUMENTATION); if (profile_allow_editing) { menu->add_separator(); @@ -2508,7 +2511,6 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel HBoxContainer *filter_hbc = memnew(HBoxContainer); filter_hbc->add_constant_override("separate", 0); - ToolButton *tb; ED_SHORTCUT("scene_tree/rename", TTR("Rename")); ED_SHORTCUT("scene_tree/batch_rename", TTR("Batch Rename"), KEY_MASK_CMD | KEY_F2); @@ -2529,19 +2531,17 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel ED_SHORTCUT("scene_tree/delete_no_confirm", TTR("Delete (No Confirm)"), KEY_MASK_SHIFT | KEY_DELETE); ED_SHORTCUT("scene_tree/delete", TTR("Delete"), KEY_DELETE); - tb = memnew(ToolButton); - tb->connect("pressed", this, "_tool_selected", make_binds(TOOL_NEW, false)); - tb->set_tooltip(TTR("Add/Create a New Node")); - tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node")); - filter_hbc->add_child(tb); - button_add = tb; + button_add = memnew(ToolButton); + button_add->connect("pressed", this, "_tool_selected", make_binds(TOOL_NEW, false)); + button_add->set_tooltip(TTR("Add/Create a New Node")); + button_add->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node")); + filter_hbc->add_child(button_add); - tb = memnew(ToolButton); - tb->connect("pressed", this, "_tool_selected", make_binds(TOOL_INSTANCE, false)); - tb->set_tooltip(TTR("Instance a scene file as a Node. Creates an inherited scene if no root node exists.")); - tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene")); - filter_hbc->add_child(tb); - button_instance = tb; + button_instance = memnew(ToolButton); + button_instance->connect("pressed", this, "_tool_selected", make_binds(TOOL_INSTANCE, false)); + button_instance->set_tooltip(TTR("Instance a scene file as a Node. Creates an inherited scene if no root node exists.")); + button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene")); + filter_hbc->add_child(button_instance); vbc->add_child(filter_hbc); filter = memnew(LineEdit); @@ -2551,21 +2551,19 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel filter->add_constant_override("minimum_spaces", 0); filter->connect("text_changed", this, "_filter_changed"); - tb = memnew(ToolButton); - tb->connect("pressed", this, "_tool_selected", make_binds(TOOL_ATTACH_SCRIPT, false)); - tb->set_tooltip(TTR("Attach a new or existing script for the selected node.")); - tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script")); - filter_hbc->add_child(tb); - tb->hide(); - button_create_script = tb; - - tb = memnew(ToolButton); - tb->connect("pressed", this, "_tool_selected", make_binds(TOOL_CLEAR_SCRIPT, false)); - tb->set_tooltip(TTR("Clear a script for the selected node.")); - tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/clear_script")); - filter_hbc->add_child(tb); - button_clear_script = tb; - tb->hide(); + button_create_script = memnew(ToolButton); + button_create_script->connect("pressed", this, "_tool_selected", make_binds(TOOL_ATTACH_SCRIPT, false)); + button_create_script->set_tooltip(TTR("Attach a new or existing script for the selected node.")); + button_create_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script")); + filter_hbc->add_child(button_create_script); + button_create_script->hide(); + + button_clear_script = memnew(ToolButton); + button_clear_script->connect("pressed", this, "_tool_selected", make_binds(TOOL_CLEAR_SCRIPT, false)); + button_clear_script->set_tooltip(TTR("Clear a script for the selected node.")); + button_clear_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/clear_script")); + filter_hbc->add_child(button_clear_script); + button_clear_script->hide(); button_hb = memnew(HBoxContainer); vbc->add_child(button_hb); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 42272d0e6e..f2d11c2753 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -1121,22 +1121,17 @@ SceneTreeEditor::~SceneTreeEditor() { void SceneTreeDialog::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - connect("confirmed", this, "_select"); - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - disconnect("confirmed", this, "_select"); - } - if (p_what == NOTIFICATION_DRAW) { - - RID ci = get_canvas_item(); - get_stylebox("panel", "PopupMenu")->draw(ci, Rect2(Point2(), get_size())); - } - - if (p_what == NOTIFICATION_VISIBILITY_CHANGED && is_visible_in_tree()) { - - tree->update_tree(); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + connect("confirmed", this, "_select"); + } break; + case NOTIFICATION_EXIT_TREE: { + disconnect("confirmed", this, "_select"); + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible_in_tree()) + tree->update_tree(); + } break; } } @@ -1165,8 +1160,6 @@ SceneTreeDialog::SceneTreeDialog() { tree = memnew(SceneTreeEditor(false, false, true)); add_child(tree); - //set_child_rect(tree); - tree->get_scene_tree()->connect("item_activated", this, "_select"); } diff --git a/main/input_default.cpp b/main/input_default.cpp index e9f1eeff6a..6c3252ad1a 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -623,7 +623,8 @@ bool InputDefault::is_emulating_mouse_from_touch() const { return emulate_mouse_from_touch; } -Input::CursorShape InputDefault::get_default_cursor_shape() { +Input::CursorShape InputDefault::get_default_cursor_shape() const { + return default_shape; } @@ -638,6 +639,11 @@ void InputDefault::set_default_cursor_shape(CursorShape p_shape) { parse_input_event(mm); } +Input::CursorShape InputDefault::get_current_cursor_shape() const { + + return (Input::CursorShape)OS::get_singleton()->get_cursor_shape(); +} + void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (Engine::get_singleton()->is_editor_hint()) return; @@ -645,21 +651,6 @@ void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_sh OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot); } -void InputDefault::set_mouse_in_window(bool p_in_window) { - /* no longer supported, leaving this for reference to anyone who might want to implement hardware cursors - if (custom_cursor.is_valid()) { - - if (p_in_window) { - set_mouse_mode(MOUSE_MODE_HIDDEN); - VisualServer::get_singleton()->cursor_set_visible(true); - } else { - set_mouse_mode(MOUSE_MODE_VISIBLE); - VisualServer::get_singleton()->cursor_set_visible(false); - } - } - */ -} - void InputDefault::accumulate_input_event(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); diff --git a/main/input_default.h b/main/input_default.h index 79a90cc4a4..f9b4cbbd57 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -242,10 +242,10 @@ public: void set_emulate_mouse_from_touch(bool p_emulate); virtual bool is_emulating_mouse_from_touch() const; - virtual CursorShape get_default_cursor_shape(); + virtual CursorShape get_default_cursor_shape() const; virtual void set_default_cursor_shape(CursorShape p_shape); + virtual CursorShape get_current_cursor_shape() const; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()); - virtual void set_mouse_in_window(bool p_in_window); void parse_mapping(String p_mapping); void joy_button(int p_device, int p_button, bool p_pressed); diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 71e7eecd1d..9882a89794 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -6427,7 +6427,24 @@ "major": 3, "minor": 1 }, - "next": null, + "next": { + "type": "NET", + "version": { + "major": 3, + "minor": 2 + }, + "next": null, + "api": [ + { + "name": "godot_net_bind_webrtc_peer", + "return_type": "void", + "arguments": [ + ["godot_object *", "p_obj"], + ["const godot_net_webrtc_peer *", "p_interface"] + ] + } + ] + }, "api": [ { "name": "godot_net_bind_stream_peer", diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h index d7de04e725..c1bc9daab5 100644 --- a/modules/gdnative/include/net/godot_net.h +++ b/modules/gdnative/include/net/godot_net.h @@ -111,6 +111,35 @@ typedef struct { /* Binds a MultiplayerPeerGDNative to the provided interface */ void GDAPI godot_net_bind_multiplayer_peer(godot_object *p_obj, const godot_net_multiplayer_peer *); +typedef struct { + godot_gdnative_api_version version; /* version of our API */ + + godot_object *data; /* User reference */ + + /* This is PacketPeer */ + godot_error (*get_packet)(void *, const uint8_t **, int *); + godot_error (*put_packet)(void *, const uint8_t *, int); + godot_int (*get_available_packet_count)(const void *); + godot_int (*get_max_packet_size)(const void *); + + /* This is WebRTCPeer */ + void (*set_write_mode)(void *, godot_int); + godot_int (*get_write_mode)(const void *); + bool (*was_string_packet)(const void *); + godot_int (*get_connection_state)(const void *); + + godot_error (*create_offer)(void *); + godot_error (*set_remote_description)(void *, const char *, const char *); + godot_error (*set_local_description)(void *, const char *, const char *); + godot_error (*add_ice_candidate)(void *, const char *, int, const char *); + godot_error (*poll)(void *); + + void *next; /* For extension? */ +} godot_net_webrtc_peer; + +/* Binds a PacketPeerGDNative to the provided interface */ +void GDAPI godot_net_bind_webrtc_peer(godot_object *p_obj, const godot_net_webrtc_peer *); + #ifdef __cplusplus } #endif diff --git a/modules/gdnative/net/SCsub b/modules/gdnative/net/SCsub index e915703935..18ab9986b0 100644 --- a/modules/gdnative/net/SCsub +++ b/modules/gdnative/net/SCsub @@ -3,5 +3,11 @@ Import('env') Import('env_gdnative') -env_gdnative.add_source_files(env.modules_sources, '*.cpp') +env_net = env_gdnative.Clone() + +has_webrtc = env_net["module_webrtc_enabled"] +if has_webrtc: + env_net.Append(CPPDEFINES=['WEBRTC_GDNATIVE_ENABLED']) + +env_net.add_source_files(env.modules_sources, '*.cpp') diff --git a/modules/gdnative/net/webrtc_peer_gdnative.cpp b/modules/gdnative/net/webrtc_peer_gdnative.cpp new file mode 100644 index 0000000000..60b1ed4fe4 --- /dev/null +++ b/modules/gdnative/net/webrtc_peer_gdnative.cpp @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* packet_peer_gdnative.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 "modules/gdnative/gdnative.h" +#include "modules/gdnative/include/net/godot_net.h" + +#ifdef WEBRTC_GDNATIVE_ENABLED +#include "modules/webrtc/webrtc_peer_gdnative.h" +#endif + +extern "C" { + +void GDAPI godot_net_bind_webrtc_peer(godot_object *p_obj, const godot_net_webrtc_peer *p_impl) { +#ifdef WEBRTC_GDNATIVE_ENABLED + ((WebRTCPeerGDNative *)p_obj)->set_native_webrtc_peer(p_impl); +#endif +} +} diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 0676317f6e..eada389c51 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1945,6 +1945,10 @@ String GDScriptWarning::get_message() const { CHECK_SYMBOLS(1); return "The local variable '" + symbols[0] + "' is declared but never used in the block."; } break; + case SHADOWED_VARIABLE: { + CHECK_SYMBOLS(2); + return "The local variable '" + symbols[0] + "' is shadowing an already defined variable at line " + symbols[1] + "."; + } break; case UNUSED_CLASS_VARIABLE: { CHECK_SYMBOLS(1); return "The class variable '" + symbols[0] + "' is declared but never used in the script."; @@ -2048,6 +2052,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) { "UNASSIGNED_VARIABLE", "UNASSIGNED_VARIABLE_OP_ASSIGN", "UNUSED_VARIABLE", + "SHADOWED_VARIABLE", "UNUSED_CLASS_VARIABLE", "UNUSED_ARGUMENT", "UNREACHABLE_CODE", diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index c67e390e32..1d75d9e2fe 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -273,6 +273,7 @@ struct GDScriptWarning { UNASSIGNED_VARIABLE, // Variable used but never assigned UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc) UNUSED_VARIABLE, // Local variable is declared but never used + SHADOWED_VARIABLE, // Variable name shadowed by other variable UNUSED_CLASS_VARIABLE, // Class variable is declared but never used in the file UNUSED_ARGUMENT, // Function argument is never used UNREACHABLE_CODE, // Code after a return statement diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 8a9eacd835..80af094c2c 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -7658,6 +7658,11 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) { if (p_function->arguments_usage[i] == 0 && !p_function->arguments[i].operator String().begins_with("_")) { _add_warning(GDScriptWarning::UNUSED_ARGUMENT, p_function->line, p_function->name, p_function->arguments[i].operator String()); } + for (int j = 0; j < current_class->variables.size(); j++) { + if (current_class->variables[j].identifier == p_function->arguments[i]) { + _add_warning(GDScriptWarning::SHADOWED_VARIABLE, p_function->line, p_function->arguments[i], itos(current_class->variables[j].line)); + } + } #endif // DEBUG_ENABLED } @@ -7731,6 +7736,17 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) { p_function->return_type.has_type = false; p_function->return_type.may_yield = true; } + +#ifdef DEBUG_ENABLED + for (Map<StringName, LocalVarNode *>::Element *E = p_function->body->variables.front(); E; E = E->next()) { + LocalVarNode *lv = E->get(); + for (int i = 0; i < current_class->variables.size(); i++) { + if (current_class->variables[i].identifier == lv->name) { + _add_warning(GDScriptWarning::SHADOWED_VARIABLE, lv->line, lv->name, itos(current_class->variables[i].line)); + } + } + } +#endif // DEBUG_ENABLED } void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml index b5bc35df69..06d22a2d65 100644 --- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml +++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml @@ -37,6 +37,14 @@ Generate a noise image with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. </description> </method> + <method name="get_noise_1d"> + <return type="float"> + </return> + <argument index="0" name="x" type="float"> + </argument> + <description> + </description> + </method> <method name="get_noise_2d"> <return type="float"> </return> diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub new file mode 100644 index 0000000000..446bd530c2 --- /dev/null +++ b/modules/webrtc/SCsub @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +# Thirdparty source files + +env_webrtc = env_modules.Clone() +use_gdnative = env_webrtc["module_gdnative_enabled"] + +if use_gdnative: # GDNative is retained in Javascript for export compatibility + env_webrtc.Append(CPPDEFINES=['WEBRTC_GDNATIVE_ENABLED']) + gdnative_includes = ["#modules/gdnative/include/"] + env_webrtc.Append(CPPPATH=gdnative_includes) + +env_webrtc.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/webrtc/config.py b/modules/webrtc/config.py new file mode 100644 index 0000000000..5ed245bad2 --- /dev/null +++ b/modules/webrtc/config.py @@ -0,0 +1,13 @@ +def can_build(env, platform): + return True + +def configure(env): + pass + +def get_doc_classes(): + return [ + "WebRTCPeer" + ] + +def get_doc_path(): + return "doc_classes" diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp new file mode 100644 index 0000000000..ee7a766bd9 --- /dev/null +++ b/modules/webrtc/register_types.cpp @@ -0,0 +1,55 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "register_types.h" +#include "webrtc_peer.h" + +#ifdef JAVASCRIPT_ENABLED +#include "emscripten.h" +#include "webrtc_peer_js.h" +#endif +#ifdef WEBRTC_GDNATIVE_ENABLED +#include "webrtc_peer_gdnative.h" +#endif + +void register_webrtc_types() { +#ifdef JAVASCRIPT_ENABLED + WebRTCPeerJS::make_default(); +#elif defined(WEBRTC_GDNATIVE_ENABLED) + WebRTCPeerGDNative::make_default(); +#endif + + ClassDB::register_custom_instance_class<WebRTCPeer>(); +#ifdef WEBRTC_GDNATIVE_ENABLED + ClassDB::register_class<WebRTCPeerGDNative>(); +#endif +} + +void unregister_webrtc_types() {} diff --git a/modules/webrtc/register_types.h b/modules/webrtc/register_types.h new file mode 100644 index 0000000000..18a5dcc5aa --- /dev/null +++ b/modules/webrtc/register_types.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +void register_webrtc_types(); +void unregister_webrtc_types(); diff --git a/modules/webrtc/webrtc_peer.cpp b/modules/webrtc/webrtc_peer.cpp new file mode 100644 index 0000000000..30c4505df9 --- /dev/null +++ b/modules/webrtc/webrtc_peer.cpp @@ -0,0 +1,81 @@ +/*************************************************************************/ +/* webrtc_peer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "webrtc_peer.h" + +WebRTCPeer *(*WebRTCPeer::_create)() = NULL; + +Ref<WebRTCPeer> WebRTCPeer::create_ref() { + + if (!_create) + return Ref<WebRTCPeer>(); + return Ref<WebRTCPeer>(_create()); +} + +WebRTCPeer *WebRTCPeer::create() { + + if (!_create) + return NULL; + return _create(); +} + +void WebRTCPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_offer"), &WebRTCPeer::create_offer); + ClassDB::bind_method(D_METHOD("set_local_description", "type", "sdp"), &WebRTCPeer::set_local_description); + ClassDB::bind_method(D_METHOD("set_remote_description", "type", "sdp"), &WebRTCPeer::set_remote_description); + ClassDB::bind_method(D_METHOD("poll"), &WebRTCPeer::poll); + ClassDB::bind_method(D_METHOD("add_ice_candidate", "media", "index", "name"), &WebRTCPeer::add_ice_candidate); + + ClassDB::bind_method(D_METHOD("was_string_packet"), &WebRTCPeer::was_string_packet); + ClassDB::bind_method(D_METHOD("set_write_mode", "write_mode"), &WebRTCPeer::set_write_mode); + ClassDB::bind_method(D_METHOD("get_write_mode"), &WebRTCPeer::get_write_mode); + ClassDB::bind_method(D_METHOD("get_connection_state"), &WebRTCPeer::get_connection_state); + + ADD_SIGNAL(MethodInfo("offer_created", PropertyInfo(Variant::STRING, "type"), PropertyInfo(Variant::STRING, "sdp"))); + ADD_SIGNAL(MethodInfo("new_ice_candidate", PropertyInfo(Variant::STRING, "media"), PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::STRING, "name"))); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "write_mode", PROPERTY_HINT_ENUM), "set_write_mode", "get_write_mode"); + + BIND_ENUM_CONSTANT(WRITE_MODE_TEXT); + BIND_ENUM_CONSTANT(WRITE_MODE_BINARY); + + BIND_ENUM_CONSTANT(STATE_NEW); + BIND_ENUM_CONSTANT(STATE_CONNECTING); + BIND_ENUM_CONSTANT(STATE_CONNECTED); + BIND_ENUM_CONSTANT(STATE_DISCONNECTED); + BIND_ENUM_CONSTANT(STATE_FAILED); + BIND_ENUM_CONSTANT(STATE_CLOSED); +} + +WebRTCPeer::WebRTCPeer() { +} + +WebRTCPeer::~WebRTCPeer() { +} diff --git a/modules/webrtc/webrtc_peer.h b/modules/webrtc/webrtc_peer.h new file mode 100644 index 0000000000..e141c14655 --- /dev/null +++ b/modules/webrtc/webrtc_peer.h @@ -0,0 +1,86 @@ +/*************************************************************************/ +/* webrtc_peer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef WEBRTC_PEER_H +#define WEBRTC_PEER_H + +#include "core/io/packet_peer.h" + +class WebRTCPeer : public PacketPeer { + GDCLASS(WebRTCPeer, PacketPeer); + +public: + enum WriteMode { + WRITE_MODE_TEXT, + WRITE_MODE_BINARY, + }; + + enum ConnectionState { + STATE_NEW, + STATE_CONNECTING, + STATE_CONNECTED, + STATE_DISCONNECTED, + STATE_FAILED, + STATE_CLOSED + }; + +protected: + static void _bind_methods(); + static WebRTCPeer *(*_create)(); + +public: + virtual void set_write_mode(WriteMode mode) = 0; + virtual WriteMode get_write_mode() const = 0; + virtual bool was_string_packet() const = 0; + virtual ConnectionState get_connection_state() const = 0; + + virtual Error create_offer() = 0; + virtual Error set_remote_description(String type, String sdp) = 0; + virtual Error set_local_description(String type, String sdp) = 0; + virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) = 0; + virtual Error poll() = 0; + + /** Inherited from PacketPeer: **/ + virtual int get_available_packet_count() const = 0; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) = 0; ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) = 0; + + virtual int get_max_packet_size() const = 0; + + static Ref<WebRTCPeer> create_ref(); + static WebRTCPeer *create(); + + WebRTCPeer(); + ~WebRTCPeer(); +}; + +VARIANT_ENUM_CAST(WebRTCPeer::WriteMode); +VARIANT_ENUM_CAST(WebRTCPeer::ConnectionState); +#endif // WEBRTC_PEER_H diff --git a/modules/webrtc/webrtc_peer_gdnative.cpp b/modules/webrtc/webrtc_peer_gdnative.cpp new file mode 100644 index 0000000000..f782944980 --- /dev/null +++ b/modules/webrtc/webrtc_peer_gdnative.cpp @@ -0,0 +1,114 @@ +/*************************************************************************/ +/* webrtc_peer_gdnative.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef WEBRTC_GDNATIVE_ENABLED + +#include "webrtc_peer_gdnative.h" + +void WebRTCPeerGDNative::_bind_methods() { +} + +WebRTCPeerGDNative::WebRTCPeerGDNative() { + interface = NULL; +} + +WebRTCPeerGDNative::~WebRTCPeerGDNative() { +} + +Error WebRTCPeerGDNative::create_offer() { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->create_offer(interface->data); +} + +Error WebRTCPeerGDNative::set_local_description(String p_type, String p_sdp) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->set_local_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data()); +} + +Error WebRTCPeerGDNative::set_remote_description(String p_type, String p_sdp) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->set_remote_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data()); +} + +Error WebRTCPeerGDNative::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->add_ice_candidate(interface->data, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data()); +} + +Error WebRTCPeerGDNative::poll() { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->poll(interface->data); +} + +void WebRTCPeerGDNative::set_write_mode(WriteMode p_mode) { + ERR_FAIL_COND(interface == NULL); + interface->set_write_mode(interface->data, p_mode); +} + +WebRTCPeer::WriteMode WebRTCPeerGDNative::get_write_mode() const { + ERR_FAIL_COND_V(interface == NULL, WRITE_MODE_BINARY); + return (WriteMode)interface->get_write_mode(interface->data); +} + +bool WebRTCPeerGDNative::was_string_packet() const { + ERR_FAIL_COND_V(interface == NULL, false); + return interface->was_string_packet(interface->data); +} + +WebRTCPeer::ConnectionState WebRTCPeerGDNative::get_connection_state() const { + ERR_FAIL_COND_V(interface == NULL, STATE_DISCONNECTED); + return STATE_DISCONNECTED; +} + +Error WebRTCPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size); +} + +Error WebRTCPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED); + return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size); +} + +int WebRTCPeerGDNative::get_max_packet_size() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_max_packet_size(interface->data); +} + +int WebRTCPeerGDNative::get_available_packet_count() const { + ERR_FAIL_COND_V(interface == NULL, 0); + return interface->get_available_packet_count(interface->data); +} + +void WebRTCPeerGDNative::set_native_webrtc_peer(const godot_net_webrtc_peer *p_impl) { + interface = p_impl; +} + +#endif // WEBRTC_GDNATIVE_ENABLED diff --git a/modules/webrtc/webrtc_peer_gdnative.h b/modules/webrtc/webrtc_peer_gdnative.h new file mode 100644 index 0000000000..6786cec8ea --- /dev/null +++ b/modules/webrtc/webrtc_peer_gdnative.h @@ -0,0 +1,78 @@ +/*************************************************************************/ +/* webrtc_peer_gdnative.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef WEBRTC_GDNATIVE_ENABLED + +#ifndef WEBRTC_PEER_GDNATIVE_H +#define WEBRTC_PEER_GDNATIVE_H + +#include "modules/gdnative/include/net/godot_net.h" +#include "webrtc_peer.h" + +class WebRTCPeerGDNative : public WebRTCPeer { + GDCLASS(WebRTCPeerGDNative, WebRTCPeer); + +protected: + static void _bind_methods(); + +private: + const godot_net_webrtc_peer *interface; + +public: + static WebRTCPeer *_create() { return memnew(WebRTCPeerGDNative); } + static void make_default() { WebRTCPeer::_create = WebRTCPeerGDNative::_create; } + + void set_native_webrtc_peer(const godot_net_webrtc_peer *p_impl); + + virtual void set_write_mode(WriteMode mode); + virtual WriteMode get_write_mode() const; + virtual bool was_string_packet() const; + virtual ConnectionState get_connection_state() const; + + virtual Error create_offer(); + virtual Error set_remote_description(String type, String sdp); + virtual Error set_local_description(String type, String sdp); + virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName); + virtual Error poll(); + + /** Inherited from PacketPeer: **/ + virtual int get_available_packet_count() const; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + + virtual int get_max_packet_size() const; + + WebRTCPeerGDNative(); + ~WebRTCPeerGDNative(); +}; + +#endif // WEBRTC_PEER_GDNATIVE_H + +#endif // WEBRTC_GDNATIVE_ENABLED diff --git a/modules/webrtc/webrtc_peer_js.cpp b/modules/webrtc/webrtc_peer_js.cpp new file mode 100644 index 0000000000..1282e075ab --- /dev/null +++ b/modules/webrtc/webrtc_peer_js.cpp @@ -0,0 +1,455 @@ +/*************************************************************************/ +/* webrtc_peer_js.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef JAVASCRIPT_ENABLED + +#include "webrtc_peer_js.h" +#include "emscripten.h" + +extern "C" { +EMSCRIPTEN_KEEPALIVE void _emrtc_on_ice_candidate(void *obj, char *p_MidName, int p_MlineIndexName, char *p_sdpName) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->emit_signal("new_ice_candidate", String(p_MidName), p_MlineIndexName, String(p_sdpName)); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_offer_created(void *obj, char *p_type, char *p_offer) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->emit_signal("offer_created", String(p_type), String(p_offer)); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_on_error(void *obj) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->_on_error(); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_on_open(void *obj) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->_on_open(); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_on_close(void *obj) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->_on_close(); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_on_message(void *obj, uint8_t *p_data, uint32_t p_size, bool p_is_string) { + WebRTCPeerJS *peer = static_cast<WebRTCPeerJS *>(obj); + peer->_on_message(p_data, p_size, p_is_string); +} + +EMSCRIPTEN_KEEPALIVE void _emrtc_bind_channel(int p_id) { + /* clang-format off */ + EM_ASM({ + if (!Module.IDHandler.has($0)) { + return; // Godot Object is gone! + } + var dict = Module.IDHandler.get($0); + var channel = dict["channel"]; + var c_ptr = dict["ptr"]; + + channel.onopen = function (evt) { + ccall("_emrtc_on_open", + "void", + ["number"], + [c_ptr] + ); + }; + channel.onclose = function (evt) { + ccall("_emrtc_on_close", + "void", + ["number"], + [c_ptr] + ); + }; + channel.onerror = function (evt) { + ccall("_emrtc_on_error", + "void", + ["number"], + [c_ptr] + ); + }; + + channel.binaryType = "arraybuffer"; + channel.onmessage = function(event) { + var buffer; + var is_string = 0; + if (event.data instanceof ArrayBuffer) { + + buffer = new Uint8Array(event.data); + + } else if (event.data instanceof Blob) { + + alert("Blob type not supported"); + return; + + } else if (typeof event.data === "string") { + + is_string = 1; + var enc = new TextEncoder("utf-8"); + buffer = new Uint8Array(enc.encode(event.data)); + + } else { + + alert("Unknown message type"); + return; + + } + var len = buffer.length*buffer.BYTES_PER_ELEMENT; + var out = Module._malloc(len); + Module.HEAPU8.set(buffer, out); + ccall("_emrtc_on_message", + "void", + ["number", "number", "number", "number"], + [c_ptr, out, len, is_string] + ); + Module._free(out); + } + }, p_id); + /* clang-format on */ +} +} + +void _emrtc_create_pc(int p_id) { + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var c_ptr = dict["ptr"]; + // Setup local connaction + var conn = new RTCPeerConnection(); + conn.onicecandidate = function(event) { + if (!Module.IDHandler.get($0)) return; + if (!event.candidate) return; + + var c = event.candidate; + // should emit on ice candidate + ccall("_emrtc_on_ice_candidate", + "void", + ["number", "string", "number", "string"], + [c_ptr, c.sdpMid, c.sdpMLineIndex, c.candidate] + ); + }; + conn.ondatachannel = function (evt) { + var dict = Module.IDHandler.get($0); + if (!dict || dict["channel"]) { + return; + } + var channel = evt.channel; + dict["channel"] = channel; + ccall("_emrtc_bind_channel", + "void", + ["number"], + [$0] + ); + }; + dict["conn"] = conn; + }, p_id); + /* clang-format on */ +} + +void WebRTCPeerJS::_on_open() { + in_buffer.resize(16); + _conn_state = STATE_CONNECTED; +} + +void WebRTCPeerJS::_on_close() { + close(); +} + +void WebRTCPeerJS::_on_error() { + close(); + _conn_state = STATE_FAILED; +} + +void WebRTCPeerJS::_on_message(uint8_t *p_data, uint32_t p_size, bool p_is_string) { + if (in_buffer.space_left() < p_size + 5) { + ERR_EXPLAIN("Buffer full! Dropping data"); + ERR_FAIL(); + } + + uint8_t is_string = p_is_string ? 1 : 0; + in_buffer.write((uint8_t *)&p_size, 4); + in_buffer.write((uint8_t *)&is_string, 1); + in_buffer.write(p_data, p_size); + queue_count++; +} + +void WebRTCPeerJS::close() { + in_buffer.resize(0); + queue_count = 0; + _was_string = false; + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + if (!dict) return; + if (dict["channel"]) { + dict["channel"].close(); + dict["channel"] = null; + } + if (dict["conn"]) { + dict["conn"].close(); + } + }, _js_id); + /* clang-format on */ + _conn_state = STATE_CLOSED; +} + +Error WebRTCPeerJS::create_offer() { + ERR_FAIL_COND_V(_conn_state != STATE_NEW, FAILED); + + _conn_state = STATE_CONNECTING; + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var conn = dict["conn"]; + var c_ptr = dict["ptr"]; + var onError = function(error) { + console.log(error); + ccall("_emrtc_on_error", + "void", + ["number"], + [c_ptr] + ); + }; + var onCreated = function(offer) { + ccall("_emrtc_offer_created", + "void", + ["number", "string", "string"], + [c_ptr, offer.type, offer.sdp] + ); + }; + + var channel = conn.createDataChannel("default"); + dict["channel"] = channel; + ccall("_emrtc_bind_channel", + "void", + ["number"], + [$0] + ); + conn.createOffer().then(onCreated).catch(onError); + }, _js_id); + /* clang-format on */ + return OK; +} + +Error WebRTCPeerJS::set_local_description(String type, String sdp) { + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var conn = dict["conn"]; + var c_ptr = dict["ptr"]; + var type = UTF8ToString($1); + var sdp = UTF8ToString($2); + var onError = function(error) { + console.log(error); + ccall("_emrtc_on_error", + "void", + ["number"], + [c_ptr] + ); + }; + conn.setLocalDescription({ + "sdp": sdp, + "type": type + }).catch(onError); + }, _js_id, type.utf8().get_data(), sdp.utf8().get_data()); + /* clang-format on */ + return OK; +} + +Error WebRTCPeerJS::set_remote_description(String type, String sdp) { + if (type == "offer") { + ERR_FAIL_COND_V(_conn_state != STATE_NEW, FAILED); + _conn_state = STATE_CONNECTING; + } + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var conn = dict["conn"]; + var c_ptr = dict["ptr"]; + var type = UTF8ToString($1); + var sdp = UTF8ToString($2); + + var onError = function(error) { + console.log(error); + ccall("_emrtc_on_error", + "void", + ["number"], + [c_ptr] + ); + }; + var onCreated = function(offer) { + ccall("_emrtc_offer_created", + "void", + ["number", "string", "string"], + [c_ptr, offer.type, offer.sdp] + ); + }; + var onSet = function() { + if (type != "offer") { + return; + } + conn.createAnswer().then(onCreated); + }; + conn.setRemoteDescription({ + "sdp": sdp, + "type": type + }).then(onSet).catch(onError); + }, _js_id, type.utf8().get_data(), sdp.utf8().get_data()); + /* clang-format on */ + return OK; +} + +Error WebRTCPeerJS::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) { + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var conn = dict["conn"]; + var c_ptr = dict["ptr"]; + var sdpMidName = UTF8ToString($1); + var sdpMlineIndexName = UTF8ToString($2); + var sdpName = UTF8ToString($3); + conn.addIceCandidate(new RTCIceCandidate({ + "candidate": sdpName, + "sdpMid": sdpMidName, + "sdpMlineIndex": sdpMlineIndexName + })); + }, _js_id, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data()); + /* clang-format on */ + return OK; +} + +Error WebRTCPeerJS::poll() { + return OK; +} + +WebRTCPeer::ConnectionState WebRTCPeerJS::get_connection_state() const { + return _conn_state; +} + +int WebRTCPeerJS::get_available_packet_count() const { + return queue_count; +} + +Error WebRTCPeerJS::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + ERR_FAIL_COND_V(_conn_state != STATE_CONNECTED, ERR_UNCONFIGURED); + + if (queue_count == 0) + return ERR_UNAVAILABLE; + + uint32_t to_read = 0; + uint32_t left = 0; + uint8_t is_string = 0; + r_buffer_size = 0; + + in_buffer.read((uint8_t *)&to_read, 4); + --queue_count; + left = in_buffer.data_left(); + + if (left < to_read + 1) { + in_buffer.advance_read(left); + return FAILED; + } + + in_buffer.read(&is_string, 1); + _was_string = is_string == 1; + in_buffer.read(packet_buffer, to_read); + *r_buffer = packet_buffer; + r_buffer_size = to_read; + + return OK; +} + +Error WebRTCPeerJS::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + ERR_FAIL_COND_V(_conn_state != STATE_CONNECTED, ERR_UNCONFIGURED); + + int is_bin = _write_mode == WebRTCPeer::WRITE_MODE_BINARY ? 1 : 0; + + /* clang-format off */ + EM_ASM({ + var dict = Module.IDHandler.get($0); + var channel = dict["channel"]; + var bytes_array = new Uint8Array($2); + var i = 0; + + for(i=0; i<$2; i++) { + bytes_array[i] = getValue($1+i, 'i8'); + } + + if ($3) { + channel.send(bytes_array.buffer); + } else { + var string = new TextDecoder("utf-8").decode(bytes_array); + channel.send(string); + } + }, _js_id, p_buffer, p_buffer_size, is_bin); + /* clang-format on */ + + return OK; +} + +int WebRTCPeerJS::get_max_packet_size() const { + return 1200; +} + +void WebRTCPeerJS::set_write_mode(WriteMode p_mode) { + _write_mode = p_mode; +} + +WebRTCPeer::WriteMode WebRTCPeerJS::get_write_mode() const { + return _write_mode; +} + +bool WebRTCPeerJS::was_string_packet() const { + return _was_string; +} + +WebRTCPeerJS::WebRTCPeerJS() { + queue_count = 0; + _was_string = false; + _write_mode = WRITE_MODE_BINARY; + _conn_state = STATE_NEW; + + /* clang-format off */ + _js_id = EM_ASM_INT({ + return Module.IDHandler.add({"conn": null, "ptr": $0, "channel": null}); + }, this); + /* clang-format on */ + _emrtc_create_pc(_js_id); +} + +WebRTCPeerJS::~WebRTCPeerJS() { + close(); + /* clang-format off */ + EM_ASM({ + Module.IDHandler.remove($0); + }, _js_id); + /* clang-format on */ +}; +#endif diff --git a/modules/webrtc/webrtc_peer_js.h b/modules/webrtc/webrtc_peer_js.h new file mode 100644 index 0000000000..02f0c9b55d --- /dev/null +++ b/modules/webrtc/webrtc_peer_js.h @@ -0,0 +1,88 @@ +/*************************************************************************/ +/* webrtc_peer_js.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef WEBRTC_PEER_JS_H +#define WEBRTC_PEER_JS_H + +#ifdef JAVASCRIPT_ENABLED + +#include "webrtc_peer.h" + +class WebRTCPeerJS : public WebRTCPeer { + +private: + enum { + PACKET_BUFFER_SIZE = 65536 - 5 // 4 bytes for the size, 1 for for type + }; + + bool _was_string; + WriteMode _write_mode; + + int _js_id; + RingBuffer<uint8_t> in_buffer; + int queue_count; + uint8_t packet_buffer[PACKET_BUFFER_SIZE]; + ConnectionState _conn_state; + +public: + static WebRTCPeer *_create() { return memnew(WebRTCPeerJS); } + static void make_default() { WebRTCPeer::_create = WebRTCPeerJS::_create; } + + virtual void set_write_mode(WriteMode mode); + virtual WriteMode get_write_mode() const; + virtual bool was_string_packet() const; + virtual ConnectionState get_connection_state() const; + + virtual Error create_offer(); + virtual Error set_remote_description(String type, String sdp); + virtual Error set_local_description(String type, String sdp); + virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName); + virtual Error poll(); + + /** Inherited from PacketPeer: **/ + virtual int get_available_packet_count() const; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + + virtual int get_max_packet_size() const; + + void close(); + void _on_open(); + void _on_close(); + void _on_error(); + void _on_message(uint8_t *p_data, uint32_t p_size, bool p_is_string); + + WebRTCPeerJS(); + ~WebRTCPeerJS(); +}; + +#endif + +#endif // WEBRTC_PEER_JS_H diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp index ed6cc5638e..39bf3de982 100644 --- a/modules/websocket/register_types.cpp +++ b/modules/websocket/register_types.cpp @@ -60,25 +60,6 @@ void register_websocket_types() { _SET_HINT(WSS_OUT_PKT, 1024, 16384); #ifdef JAVASCRIPT_ENABLED - EM_ASM({ - var IDHandler = {}; - IDHandler["ids"] = {}; - IDHandler["has"] = function(id) { - return IDHandler.ids.hasOwnProperty(id); - }; - IDHandler["add"] = function(obj) { - var id = crypto.getRandomValues(new Int32Array(32))[0]; - IDHandler.ids[id] = obj; - return id; - }; - IDHandler["get"] = function(id) { - return IDHandler.ids[id]; - }; - IDHandler["remove"] = function(id) { - delete IDHandler.ids[id]; - }; - Module["IDHandler"] = IDHandler; - }); EMWSPeer::make_default(); EMWSClient::make_default(); EMWSServer::make_default(); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index d65cf2f31e..93d39859f2 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -292,14 +292,6 @@ bool OS_Android::can_draw() const { return true; //always? } -void OS_Android::set_cursor_shape(CursorShape p_shape) { - - //android really really really has no mouse.. how amazing.. -} - -void OS_Android::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { -} - void OS_Android::main_loop_begin() { if (main_loop) diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 3a5404124a..d2198b0579 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -144,9 +144,6 @@ public: virtual bool can_draw() const; - virtual void set_cursor_shape(CursorShape p_shape); - virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); - void main_loop_begin(); bool main_loop_iterate(); void main_loop_request_go_back(); diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index a6d5a00852..f3fed6669b 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -203,6 +203,10 @@ void OS_Haiku::set_cursor_shape(CursorShape p_shape) { //ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED"); } +OS::CursorShape OS_Haiku::get_cursor_shape() const { + // TODO: implement get_cursor_shape +} + void OS_Haiku::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { // TODO } diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index d7eac10635..6ab006843a 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -86,6 +86,7 @@ public: virtual Point2 get_mouse_position() const; virtual int get_mouse_button_state() const; virtual void set_cursor_shape(CursorShape p_shape); + virtual CursorShape get_cursor_shape() const; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); virtual int get_screen_count() const; diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index 7d0fdd2078..e25efc813b 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -490,17 +490,11 @@ void OSIPhone::set_keep_screen_on(bool p_enabled) { _set_keep_screen_on(p_enabled); }; -void OSIPhone::set_cursor_shape(CursorShape p_shape){ - -}; - String OSIPhone::get_user_data_dir() const { return data_dir; }; -void OSIPhone::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot){}; - String OSIPhone::get_name() { return "iOS"; diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 30d7a1ba41..49c6475cf9 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -167,9 +167,6 @@ public: virtual void hide_virtual_keyboard(); virtual int get_virtual_keyboard_height() const; - virtual void set_cursor_shape(CursorShape p_shape); - virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); - virtual Size2 get_window_size() const; virtual Rect2 get_window_safe_area() const; diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub index a93c98a89f..85a633442e 100644 --- a/platform/javascript/SCsub +++ b/platform/javascript/SCsub @@ -20,6 +20,13 @@ for lib in js_libraries: env.Append(LINKFLAGS=['--js-library', env.File(lib).path]) env.Depends(build, js_libraries) +js_modules = [ + 'id_handler.js', +] +for module in js_modules: + env.Append(LINKFLAGS=['--pre-js', env.File(module).path]) +env.Depends(build, js_modules) + wrapper_start = env.File('pre.js') wrapper_end = env.File('engine.js') js_wrapped = env.Textfile('#bin/godot', [wrapper_start, js, wrapper_end], TEXTFILESUFFIX='${PROGSUFFIX}.wrapped.js') diff --git a/platform/javascript/id_handler.js b/platform/javascript/id_handler.js new file mode 100644 index 0000000000..36ef5aa8ef --- /dev/null +++ b/platform/javascript/id_handler.js @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* id_handler.js */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/*************************************************************************/ + +var IDHandler = function() { + + var ids = {}; + var size = 0; + + this.has = function(id) { + return ids.hasOwnProperty(id); + } + + this.add = function(obj) { + size += 1; + var id = crypto.getRandomValues(new Int32Array(32))[0]; + ids[id] = obj; + return id; + } + + this.get = function(id) { + return ids[id]; + } + + this.remove = function(id) { + size -= 1; + delete ids[id]; + } + + this.size = function() { + return size; + } + + this.ids = ids; +}; + +Module.IDHandler = new IDHandler; diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index dfe7b27bd0..125a88ab6d 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -172,6 +172,7 @@ public: virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); virtual void set_cursor_shape(CursorShape p_shape); + virtual CursorShape get_cursor_shape() const; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); virtual void set_mouse_show(bool p_show); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 4bbe30a7d1..5a4c0593bc 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -712,8 +712,6 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED) OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT); - if (OS_OSX::singleton->input) - OS_OSX::singleton->input->set_mouse_in_window(false); } - (void)mouseEntered:(NSEvent *)event { @@ -721,8 +719,6 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { return; if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED) OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER); - if (OS_OSX::singleton->input) - OS_OSX::singleton->input->set_mouse_in_window(true); OS::CursorShape p_shape = OS_OSX::singleton->cursor_shape; OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX; @@ -1696,6 +1692,11 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) { cursor_shape = p_shape; } +OS::CursorShape OS_OSX::get_cursor_shape() const { + + return cursor_shape; +} + void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (p_cursor.is_valid()) { Ref<Texture> texture = p_cursor; diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index e643d3e8bb..53f2a65c8e 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -198,12 +198,6 @@ String OS_Server::get_name() { void OS_Server::move_window_to_foreground() { } -void OS_Server::set_cursor_shape(CursorShape p_shape) { -} - -void OS_Server::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { -} - OS::PowerState OS_Server::get_power_state() { return power_manager->get_power_state(); } diff --git a/platform/server/os_server.h b/platform/server/os_server.h index eebe8ae777..7441064790 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -95,9 +95,6 @@ protected: public: virtual String get_name(); - virtual void set_cursor_shape(CursorShape p_shape); - virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); - virtual void set_mouse_show(bool p_show); virtual void set_mouse_grab(bool p_grab); virtual bool is_mouse_grab_enabled() const; diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index bc74da8a1b..82f09032f5 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -704,6 +704,11 @@ void OS_UWP::set_cursor_shape(CursorShape p_shape) { cursor_shape = p_shape; } +OS::CursorShape OS_UWP::get_cursor_shape() const { + + return cursor_shape; +} + void OS_UWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { // TODO } diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index fd78b3cdf7..00f79efb04 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -219,6 +219,7 @@ public: virtual String get_clipboard() const; void set_cursor_shape(CursorShape p_shape); + CursorShape get_cursor_shape() const; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); void set_icon(const Ref<Image> &p_icon); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 093fb05bae..1a5050a15a 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -384,8 +384,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) outside = true; if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED) main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT); - if (input) - input->set_mouse_in_window(false); } break; case WM_INPUT: { @@ -480,8 +478,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED) main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER); - if (input) - input->set_mouse_in_window(true); CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; @@ -2299,6 +2295,11 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) { cursor_shape = p_shape; } +OS::CursorShape OS_Windows::get_cursor_shape() const { + + return cursor_shape; +} + void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (p_cursor.is_valid()) { Ref<Texture> texture = p_cursor; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 2d03532c69..c15e1cabc3 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -273,6 +273,7 @@ public: virtual String get_clipboard() const; void set_cursor_shape(CursorShape p_shape); + CursorShape get_cursor_shape() const; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap); void set_icon(const Ref<Image> &p_icon); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index ba74ba2437..c96047dfbd 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -2041,15 +2041,11 @@ void OS_X11::process_xevents() { case LeaveNotify: { if (main_loop && !mouse_mode_grab) main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT); - if (input) - input->set_mouse_in_window(false); } break; case EnterNotify: { if (main_loop && !mouse_mode_grab) main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER); - if (input) - input->set_mouse_in_window(true); } break; case FocusIn: minimized = false; @@ -2722,6 +2718,11 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) { current_cursor = p_shape; } +OS::CursorShape OS_X11::get_cursor_shape() const { + + return current_cursor; +} + void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (p_cursor.is_valid()) { Ref<Texture> texture = p_cursor; diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 6d1a66af84..a54851d4e7 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -219,6 +219,7 @@ public: virtual String get_name(); virtual void set_cursor_shape(CursorShape p_shape); + virtual CursorShape get_cursor_shape() const; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); void set_mouse_mode(MouseMode p_mode); diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 5334caed67..3a3f90ac4b 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -32,9 +32,59 @@ #include "core/engine.h" +#define LINE_GRAB_WIDTH 8 +Rect2 OccluderPolygon2D::_edit_get_rect() const { + + if (rect_cache_dirty) { + if (closed) { + PoolVector<Vector2>::Read r = polygon.read(); + item_rect = Rect2(); + for (int i = 0; i < polygon.size(); i++) { + Vector2 pos = r[i]; + if (i == 0) + item_rect.position = pos; + else + item_rect.expand_to(pos); + } + rect_cache_dirty = false; + } else { + if (polygon.size() == 0) { + item_rect = Rect2(); + } else { + Vector2 d = Vector2(LINE_GRAB_WIDTH, LINE_GRAB_WIDTH); + item_rect = Rect2(polygon[0] - d, 2 * d); + for (int i = 1; i < polygon.size(); i++) { + item_rect.expand_to(polygon[i] - d); + item_rect.expand_to(polygon[i] + d); + } + } + } + } + + return item_rect; +} + +bool OccluderPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + + if (closed) { + return Geometry::is_point_in_polygon(p_point, Variant(polygon)); + } else { + const real_t d = LINE_GRAB_WIDTH / 2 + p_tolerance; + PoolVector<Vector2>::Read points = polygon.read(); + for (int i = 0; i < polygon.size() - 1; i++) { + Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, &points[i]); + if (p.distance_to(p_point) <= d) + return true; + } + + return false; + } +} + void OccluderPolygon2D::set_polygon(const PoolVector<Vector2> &p_polygon) { polygon = p_polygon; + rect_cache_dirty = true; VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, p_polygon, closed); emit_changed(); } @@ -100,6 +150,7 @@ OccluderPolygon2D::OccluderPolygon2D() { occ_polygon = VS::get_singleton()->canvas_occluder_polygon_create(); closed = true; cull = CULL_DISABLED; + rect_cache_dirty = true; } OccluderPolygon2D::~OccluderPolygon2D() { @@ -164,6 +215,16 @@ void LightOccluder2D::_notification(int p_what) { } } +Rect2 LightOccluder2D::_edit_get_rect() const { + + return occluder_polygon.is_valid() ? occluder_polygon->_edit_get_rect() : Rect2(); +} + +bool LightOccluder2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + + return occluder_polygon.is_valid() ? occluder_polygon->_edit_is_selected_on_click(p_point, p_tolerance) : false; +} + void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon) { #ifdef DEBUG_ENABLED diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index 498d65d764..7931cd0b30 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -50,10 +50,16 @@ private: bool closed; CullMode cull; + mutable Rect2 item_rect; + mutable bool rect_cache_dirty; + protected: static void _bind_methods(); public: + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + void set_polygon(const PoolVector<Vector2> &p_polygon); PoolVector<Vector2> get_polygon() const; @@ -85,6 +91,9 @@ protected: static void _bind_methods(); public: + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + void set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon); Ref<OccluderPolygon2D> get_occluder_polygon() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 92f7d6b588..7e59606d2b 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2850,7 +2850,7 @@ void Tree::_notification(int p_what) { if (p_what == NOTIFICATION_DRAG_BEGIN) { single_select_defer = NULL; - if (cache.scroll_speed > 0 && get_rect().has_point(get_viewport()->get_mouse_position() - get_global_position())) { + if (cache.scroll_speed > 0) { scrolling = true; set_physics_process_internal(true); } @@ -2897,22 +2897,22 @@ void Tree::_notification(int p_what) { } } - if (scrolling) { - Point2 point = get_viewport()->get_mouse_position() - get_global_position(); - if (point.x < cache.scroll_border) { - point.x -= cache.scroll_border; - } else if (point.x > get_size().width - cache.scroll_border) { - point.x -= get_size().width - cache.scroll_border; - } else { - point.x = 0; + Point2 mouse_position = get_viewport()->get_mouse_position() - get_global_position(); + if (scrolling && get_rect().grow(cache.scroll_border).has_point(mouse_position)) { + Point2 point; + + if ((ABS(mouse_position.x) < ABS(mouse_position.x - get_size().width)) && (ABS(mouse_position.x) < cache.scroll_border)) { + point.x = mouse_position.x - cache.scroll_border; + } else if (ABS(mouse_position.x - get_size().width) < cache.scroll_border) { + point.x = mouse_position.x - (get_size().width - cache.scroll_border); } - if (point.y < cache.scroll_border) { - point.y -= cache.scroll_border; - } else if (point.y > get_size().height - cache.scroll_border) { - point.y -= get_size().height - cache.scroll_border; - } else { - point.y = 0; + + if ((ABS(mouse_position.y) < ABS(mouse_position.y - get_size().height)) && (ABS(mouse_position.y) < cache.scroll_border)) { + point.y = mouse_position.y - cache.scroll_border; + } else if (ABS(mouse_position.y - get_size().height) < cache.scroll_border) { + point.y = mouse_position.y - (get_size().height - cache.scroll_border); } + point *= cache.scroll_speed * get_physics_process_delta_time(); point += get_scroll(); h_scroll->set_value(point.x); |