diff options
61 files changed, 571 insertions, 211 deletions
diff --git a/core/cowdata.h b/core/cowdata.h index 3e40ad0f4b..c92e20920c 100644 --- a/core/cowdata.h +++ b/core/cowdata.h @@ -33,6 +33,7 @@ #include <string.h> +#include "core/error_macros.h" #include "core/os/memory.h" #include "core/safe_refcount.h" diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp index 271e5c5a0b..5684c82d1c 100644 --- a/core/io/config_file.cpp +++ b/core/io/config_file.cpp @@ -123,6 +123,13 @@ void ConfigFile::erase_section(const String &p_section) { values.erase(p_section); } +void ConfigFile::erase_section_key(const String &p_section, const String &p_key) { + + ERR_FAIL_COND_MSG(!values.has(p_section), "Cannot erase key from nonexistent section '" + p_section + "'."); + + values[p_section].erase(p_key); +} + Error ConfigFile::save(const String &p_path) { Error err; @@ -293,6 +300,7 @@ void ConfigFile::_bind_methods() { ClassDB::bind_method(D_METHOD("get_section_keys", "section"), &ConfigFile::_get_section_keys); ClassDB::bind_method(D_METHOD("erase_section", "section"), &ConfigFile::erase_section); + ClassDB::bind_method(D_METHOD("erase_section_key", "section", "key"), &ConfigFile::erase_section_key); ClassDB::bind_method(D_METHOD("load", "path"), &ConfigFile::load); ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save); diff --git a/core/io/config_file.h b/core/io/config_file.h index 3ab6fef868..d927779f9c 100644 --- a/core/io/config_file.h +++ b/core/io/config_file.h @@ -60,6 +60,7 @@ public: void get_section_keys(const String &p_section, List<String> *r_keys) const; void erase_section(const String &p_section); + void erase_section_key(const String &p_section, const String &p_key); Error save(const String &p_path); Error load(const String &p_path); diff --git a/core/list.h b/core/list.h index d1b528562d..c46888e01c 100644 --- a/core/list.h +++ b/core/list.h @@ -31,6 +31,7 @@ #ifndef GLOBALS_LIST_H #define GLOBALS_LIST_H +#include "core/error_macros.h" #include "core/os/memory.h" #include "core/sort_array.h" diff --git a/core/map.h b/core/map.h index c87ee42e1b..77e73d70cb 100644 --- a/core/map.h +++ b/core/map.h @@ -31,6 +31,7 @@ #ifndef MAP_H #define MAP_H +#include "core/error_macros.h" #include "core/set.h" // based on the very nice implementation of rb-trees by: diff --git a/core/math/basis.h b/core/math/basis.h index 053effda69..4be4ea4cd3 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -28,13 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Circular dependency between Vector3 and Basis :/ -#include "core/math/vector3.h" - #ifndef BASIS_H #define BASIS_H #include "core/math/quat.h" +#include "core/math/vector3.h" class Basis { public: diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index f04e40cb6c..50fcdb2c13 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -30,6 +30,8 @@ #include "math_funcs.h" +#include "core/error_macros.h" + RandomPCG Math::default_rand(RandomPCG::DEFAULT_SEED, RandomPCG::DEFAULT_INC); #define PHI 0x9e3779b9 diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index 73927821cf..ebc1599820 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -134,6 +134,21 @@ Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const { return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta; } +Basis Vector3::outer(const Vector3 &p_b) const { + + Vector3 row0(x * p_b.x, x * p_b.y, x * p_b.z); + Vector3 row1(y * p_b.x, y * p_b.y, y * p_b.z); + Vector3 row2(z * p_b.x, z * p_b.y, z * p_b.z); + + return Basis(row0, row1, row2); +} + +Basis Vector3::to_diagonal_matrix() const { + return Basis(x, 0, 0, + 0, y, 0, + 0, 0, z); +} + Vector3::operator String() const { return (rtos(x) + ", " + rtos(y) + ", " + rtos(z)); diff --git a/core/math/vector3.h b/core/math/vector3.h index c68b075613..de1743d88f 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -96,8 +96,8 @@ struct Vector3 { _FORCE_INLINE_ Vector3 cross(const Vector3 &p_b) const; _FORCE_INLINE_ real_t dot(const Vector3 &p_b) const; - _FORCE_INLINE_ Basis outer(const Vector3 &p_b) const; - _FORCE_INLINE_ Basis to_diagonal_matrix() const; + Basis outer(const Vector3 &p_b) const; + Basis to_diagonal_matrix() const; _FORCE_INLINE_ Vector3 abs() const; _FORCE_INLINE_ Vector3 floor() const; @@ -154,9 +154,6 @@ struct Vector3 { _FORCE_INLINE_ Vector3() { x = y = z = 0; } }; -// Should be included after class definition, otherwise we get circular refs -#include "core/math/basis.h" - Vector3 Vector3::cross(const Vector3 &p_b) const { Vector3 ret( @@ -172,21 +169,6 @@ real_t Vector3::dot(const Vector3 &p_b) const { return x * p_b.x + y * p_b.y + z * p_b.z; } -Basis Vector3::outer(const Vector3 &p_b) const { - - Vector3 row0(x * p_b.x, x * p_b.y, x * p_b.z); - Vector3 row1(y * p_b.x, y * p_b.y, y * p_b.z); - Vector3 row2(z * p_b.x, z * p_b.y, z * p_b.z); - - return Basis(row0, row1, row2); -} - -Basis Vector3::to_diagonal_matrix() const { - return Basis(x, 0, 0, - 0, y, 0, - 0, 0, z); -} - Vector3 Vector3::abs() const { return Vector3(Math::abs(x), Math::abs(y), Math::abs(z)); diff --git a/core/os/memory.h b/core/os/memory.h index 8778cb63ad..a68a359546 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -31,6 +31,7 @@ #ifndef MEMORY_H #define MEMORY_H +#include "core/error_macros.h" #include "core/safe_refcount.h" #include <stddef.h> diff --git a/core/self_list.h b/core/self_list.h index 314d440977..07abcd1d53 100644 --- a/core/self_list.h +++ b/core/self_list.h @@ -31,6 +31,7 @@ #ifndef SELF_LIST_H #define SELF_LIST_H +#include "core/error_macros.h" #include "core/typedefs.h" template <class T> diff --git a/core/sort_array.h b/core/sort_array.h index 8660ee3333..d330e0c647 100644 --- a/core/sort_array.h +++ b/core/sort_array.h @@ -31,6 +31,7 @@ #ifndef SORT_ARRAY_H #define SORT_ARRAY_H +#include "core/error_macros.h" #include "core/typedefs.h" #define ERR_BAD_COMPARE(cond) \ diff --git a/core/typedefs.h b/core/typedefs.h index 660139b90a..767a97ac38 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -108,7 +108,6 @@ T *_nullptr() { #include "core/int_types.h" #include "core/error_list.h" -#include "core/error_macros.h" /** Generic ABS function, for math uses please use Math::abs */ diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml index aeeebdf00d..6f1627e296 100644 --- a/doc/classes/Camera2D.xml +++ b/doc/classes/Camera2D.xml @@ -51,6 +51,7 @@ <argument index="0" name="margin" type="int" enum="Margin"> </argument> <description> + Returns the specified margin. See also [member drag_margin_bottom], [member drag_margin_top], [member drag_margin_left], and [member drag_margin_right]. </description> </method> <method name="get_limit" qualifiers="const"> @@ -59,6 +60,7 @@ <argument index="0" name="margin" type="int" enum="Margin"> </argument> <description> + Returns the specified camera limit. See also [member limit_bottom], [member limit_top], [member limit_left], and [member limit_right]. </description> </method> <method name="make_current"> @@ -84,6 +86,7 @@ <argument index="1" name="drag_margin" type="float"> </argument> <description> + Sets the specified margin. See also [member drag_margin_bottom], [member drag_margin_top], [member drag_margin_left], and [member drag_margin_right]. </description> </method> <method name="set_limit"> @@ -94,6 +97,7 @@ <argument index="1" name="limit" type="int"> </argument> <description> + Sets the specified camera limit. See also [member limit_bottom], [member limit_top], [member limit_left], and [member limit_right]. </description> </method> </methods> @@ -161,6 +165,7 @@ [b]Note:[/b] Used the same as [member offset_h]. </member> <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Camera2D.Camera2DProcessMode" default="1"> + The camera's process callback. See [enum Camera2DProcessMode]. </member> <member name="rotating" type="bool" setter="set_rotating" getter="is_rotating" default="false"> If [code]true[/code], the camera rotates with the target. @@ -183,8 +188,10 @@ The camera's position takes into account vertical/horizontal offsets and the screen size. </constant> <constant name="CAMERA2D_PROCESS_PHYSICS" value="0" enum="Camera2DProcessMode"> + The camera updates with the [code]_physics_process[/code] callback. </constant> <constant name="CAMERA2D_PROCESS_IDLE" value="1" enum="Camera2DProcessMode"> + The camera updates with the [code]_process[/code] callback. </constant> </constants> </class> diff --git a/doc/classes/CameraFeed.xml b/doc/classes/CameraFeed.xml index 6d7757f9f5..f490faf369 100644 --- a/doc/classes/CameraFeed.xml +++ b/doc/classes/CameraFeed.xml @@ -14,28 +14,30 @@ <return type="int"> </return> <description> - Gets the unique ID for this feed. + Returns the unique ID for this feed. </description> </method> <method name="get_name" qualifiers="const"> <return type="String"> </return> <description> - Gets the camera's name. + Returns the camera's name. </description> </method> <method name="get_position" qualifiers="const"> <return type="int" enum="CameraFeed.FeedPosition"> </return> <description> - Position of camera on the device. + Returns the position of camera on the device. </description> </method> </methods> <members> <member name="feed_is_active" type="bool" setter="set_active" getter="is_active" default="false"> + If [code]true[/code], the feed is active. </member> <member name="feed_transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D( 1, 0, 0, -1, 0, 1 )"> + The transform applied to the camera's image. </member> </members> <constants> diff --git a/doc/classes/ClippedCamera.xml b/doc/classes/ClippedCamera.xml index f6a2a3bc11..9eda79bbae 100644 --- a/doc/classes/ClippedCamera.xml +++ b/doc/classes/ClippedCamera.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="ClippedCamera" inherits="Camera" category="Core" version="3.2"> <brief_description> + A [Camera] that includes collision. </brief_description> <description> + This node extends [Camera] to add collisions with [Area] and/or [PhysicsBody] nodes. The camera cannot move through colliding objects. </description> <tutorials> </tutorials> @@ -13,6 +15,7 @@ <argument index="0" name="node" type="Object"> </argument> <description> + Adds a collision exception so the camera does not collide with the specified node. </description> </method> <method name="add_exception_rid"> @@ -21,18 +24,21 @@ <argument index="0" name="rid" type="RID"> </argument> <description> + Adds a collision exception so the camera does not collide with the specified [RID]. </description> </method> <method name="clear_exceptions"> <return type="void"> </return> <description> + Removes all collision exceptions. </description> </method> <method name="get_clip_offset" qualifiers="const"> <return type="float"> </return> <description> + Returns the distance the camera has been offset due to a collision. </description> </method> <method name="get_collision_mask_bit" qualifiers="const"> @@ -41,6 +47,8 @@ <argument index="0" name="bit" type="int"> </argument> <description> + Returns [code]true[/code] if the specified bit index is on. + [b]Note:[/b] Bit indices range from 0-19. </description> </method> <method name="remove_exception"> @@ -49,6 +57,7 @@ <argument index="0" name="node" type="Object"> </argument> <description> + Removes a collision exception with the specified node. </description> </method> <method name="remove_exception_rid"> @@ -57,6 +66,7 @@ <argument index="0" name="rid" type="RID"> </argument> <description> + Removes a collision exception with the specified [RID]. </description> </method> <method name="set_collision_mask_bit"> @@ -67,25 +77,34 @@ <argument index="1" name="value" type="bool"> </argument> <description> + Sets the specified bit index to the [code]value[/code]. + [b]Note:[/b] Bit indices range from 0-19. </description> </method> </methods> <members> <member name="clip_to_areas" type="bool" setter="set_clip_to_areas" getter="is_clip_to_areas_enabled" default="false"> + If [code]true[/code], the camera stops on contact with [Area]s. </member> <member name="clip_to_bodies" type="bool" setter="set_clip_to_bodies" getter="is_clip_to_bodies_enabled" default="true"> + If [code]true[/code], the camera stops on contact with [PhysicsBody]s. </member> <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1"> + The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> + The camera's collision margin. The camera can't get closer than this distance to a colliding object. </member> <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="ClippedCamera.ProcessMode" default="0"> + The camera's process callback. See [enum ProcessMode]. </member> </members> <constants> <constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ProcessMode"> + The camera updates with the [code]_physics_process[/code] callback. </constant> <constant name="CLIP_PROCESS_IDLE" value="1" enum="ProcessMode"> + The camera updates with the [code]_process[/code] callback. </constant> </constants> </class> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index cd36f4fdf0..07ce76fdb2 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -51,8 +51,10 @@ [b]Note:[/b] Cannot be enabled if raw mode is on. </member> <member name="presets_enabled" type="bool" setter="set_presets_enabled" getter="are_presets_enabled" default="true"> + If [code]true[/code], the "add preset" button is enabled. </member> <member name="presets_visible" type="bool" setter="set_presets_visible" getter="are_presets_visible" default="true"> + If [code]true[/code], saved color presets are visible. </member> <member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode" default="false"> If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index afb3977849..6d4adfad51 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -71,6 +71,7 @@ <return type="int" enum="Input.CursorShape"> </return> <description> + Returns the currently assigned cursor shape (see [enum CursorShape]). </description> </method> <method name="get_gravity" qualifiers="const"> diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index d9400088dd..50b300d216 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -89,6 +89,36 @@ An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators. </description> </method> + <method name="add_icon_radio_check_item"> + <return type="void"> + </return> + <argument index="0" name="texture" type="Texture"> + </argument> + <argument index="1" name="label" type="String"> + </argument> + <argument index="2" name="id" type="int" default="-1"> + </argument> + <argument index="3" name="accel" type="int" default="0"> + </argument> + <description> + Same as [method add_icon_check_item], but uses a radio check button. + </description> + </method> + <method name="add_icon_radio_check_shortcut"> + <return type="void"> + </return> + <argument index="0" name="texture" type="Texture"> + </argument> + <argument index="1" name="shortcut" type="ShortCut"> + </argument> + <argument index="2" name="id" type="int" default="-1"> + </argument> + <argument index="3" name="global" type="bool" default="false"> + </argument> + <description> + Same as [method add_icon_check_shortcut], but uses a radio check button. + </description> + </method> <method name="add_icon_shortcut"> <return type="void"> </return> @@ -119,6 +149,25 @@ An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators. </description> </method> + <method name="add_multistate_item"> + <return type="void"> + </return> + <argument index="0" name="label" type="String"> + </argument> + <argument index="1" name="max_states" type="int"> + </argument> + <argument index="2" name="default_state" type="int"> + </argument> + <argument index="3" name="id" type="int" default="-1"> + </argument> + <argument index="4" name="accel" type="int" default="0"> + </argument> + <description> + Adds a new multistate item with text [code]label[/code]. + Contrarily to normal binary items, multistate items can have more than two states, as defined by [code]max_states[/code]. Each press or activate of the item will increase the state by one. The default value is defined by [code]default_state[/code]. + An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators. + </description> + </method> <method name="add_radio_check_item"> <return type="void"> </return> @@ -129,7 +178,7 @@ <argument index="2" name="accel" type="int" default="0"> </argument> <description> - Adds a new radio button with text [code]label[/code]. + Adds a new radio check button with text [code]label[/code]. An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators. [b]Note:[/b] Checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it. </description> diff --git a/doc/classes/RigidBody.xml b/doc/classes/RigidBody.xml index 4378fc3ffe..624b576f4d 100644 --- a/doc/classes/RigidBody.xml +++ b/doc/classes/RigidBody.xml @@ -88,6 +88,7 @@ <argument index="0" name="axis" type="int" enum="PhysicsServer.BodyAxis"> </argument> <description> + Returns [code]true[/code] if the specified linear or rotational axis is locked. </description> </method> <method name="get_colliding_bodies" qualifiers="const"> @@ -106,6 +107,7 @@ <argument index="1" name="lock" type="bool"> </argument> <description> + Locks the specified linear or rotational axis. </description> </method> <method name="set_axis_velocity"> @@ -183,6 +185,8 @@ The body mode. See [enum Mode] for possible values. </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> + The physics material override for the body. + If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. </member> <member name="sleeping" type="bool" setter="set_sleeping" getter="is_sleeping" default="false"> If [code]true[/code], the body is sleeping and will not calculate forces until woken up by a collision or the [code]apply_impulse[/code] method. diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml index 32a1634f77..c960ef5aee 100644 --- a/doc/classes/RigidBody2D.xml +++ b/doc/classes/RigidBody2D.xml @@ -169,6 +169,8 @@ The body's mode. See [enum Mode] for possible values. </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> + The physics material override for the body. + If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. </member> <member name="sleeping" type="bool" setter="set_sleeping" getter="is_sleeping" default="false"> If [code]true[/code], the body is sleeping and will not calculate forces until woken up by a collision or by using [method apply_impulse] or [method add_force]. diff --git a/doc/classes/StaticBody.xml b/doc/classes/StaticBody.xml index a9709d00df..f8840ddc14 100644 --- a/doc/classes/StaticBody.xml +++ b/doc/classes/StaticBody.xml @@ -28,6 +28,8 @@ Deprecated, use [member PhysicsMaterial.friction] instead via [member physics_material_override]. </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> + The physics material override for the body. + If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. </member> </members> <constants> diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml index 4a7f71b667..34276ec535 100644 --- a/doc/classes/StaticBody2D.xml +++ b/doc/classes/StaticBody2D.xml @@ -27,6 +27,8 @@ Deprecated, use [member PhysicsMaterial.friction] instead via [member physics_material_override]. </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> + The physics material override for the body. + If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. </member> </members> <constants> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 01d690589b..a4c976591f 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -120,6 +120,15 @@ Returns the custom background color of column [code]column[/code]. </description> </method> + <method name="get_custom_color" qualifiers="const"> + <return type="Color"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <description> + Returns the custom color of column [code]column[/code]. + </description> + </method> <method name="get_expand_right" qualifiers="const"> <return type="bool"> </return> diff --git a/doc/classes/VideoPlayer.xml b/doc/classes/VideoPlayer.xml index 18a85d496f..2215f26c23 100644 --- a/doc/classes/VideoPlayer.xml +++ b/doc/classes/VideoPlayer.xml @@ -65,6 +65,7 @@ If [code]true[/code], the video is paused. </member> <member name="stream" type="VideoStream" setter="set_stream" getter="get_stream"> + The assigned video stream. See description for supported formats. </member> <member name="stream_position" type="float" setter="set_stream_position" getter="get_stream_position"> The current position of the stream, in seconds. diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 61bcfff419..088ce3d198 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -2905,16 +2905,10 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); glActiveTexture(GL_TEXTURE0); - if (!storage->frame.current_rt->used_dof_blur_near) { - if (storage->frame.current_rt->mip_maps[0].color) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); - } else { - for (int i = 0; i < storage->frame.current_rt->mip_maps[i].sizes.size(); i++) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i].color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, storage->frame.current_rt->mip_maps[0].sizes[i].width, storage->frame.current_rt->mip_maps[0].sizes[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); - } + if (storage->frame.current_rt->mip_maps[0].color) { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); + } else { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -3303,6 +3297,12 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const reflection_probe_count = 0; } + if (env && env->bg_mode == VS::ENV_BG_CANVAS) { + // If using canvas background, copy 2d to screen copy texture + // TODO: When GLES2 renders to current_rt->mip_maps[], this copy will no longer be needed + _copy_texture_to_buffer(storage->frame.current_rt->color, storage->frame.current_rt->copy_screen_effect.fbo); + } + // render list stuff render_list.clear(); @@ -3439,8 +3439,11 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const clear_color = Color(0.0, 1.0, 0.0, 1.0); } } break; + case VS::ENV_BG_CANVAS: { + // use screen copy as background + _copy_texture_to_buffer(storage->frame.current_rt->copy_screen_effect.color, current_fb); + } break; default: { - // FIXME: implement other background modes } break; } } diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 6faf76e395..451d6adaa9 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -5757,7 +5757,8 @@ void RasterizerStorageGLES2::initialize() { config.multisample_supported = config.extensions.has("GL_EXT_framebuffer_multisample") || config.extensions.has("GL_EXT_multisampled_render_to_texture") || config.extensions.has("GL_APPLE_framebuffer_multisample"); #ifdef GLES_OVER_GL - config.render_to_mipmap_supported = true; + //TODO: causes huge problems with desktop video drivers. Making false for now, needs to be true to render SCREEN_TEXTURE mipmaps + config.render_to_mipmap_supported = false; #else //check if mipmaps can be used for SCREEN_TEXTURE and Glow on Mobile and web platforms config.render_to_mipmap_supported = config.extensions.has("GL_OES_fbo_render_mipmap") && config.extensions.has("GL_EXT_texture_lod"); diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 6a57a2e562..da46b393c6 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -30,6 +30,7 @@ #include "net_socket_posix.h" +#ifndef UNIX_SOCKET_UNAVAILABLE #if defined(UNIX_ENABLED) #include <errno.h> @@ -280,6 +281,21 @@ void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_ _sock = p_sock; _ip_type = p_ip_type; _is_stream = p_is_stream; + // Disable descriptor sharing with subprocesses. + _set_close_exec_enabled(true); +} + +void NetSocketPosix::_set_close_exec_enabled(bool p_enabled) { +#ifndef WINDOWS_ENABLED + // Enable close on exec to avoid sharing with subprocesses. Off by default on Windows. +#if defined(NO_FCNTL) + unsigned long par = p_enabled ? 1 : 0; + SOCK_IOCTL(_sock, FIOCLEX, &par); +#else + int opts = fcntl(_sock, F_GETFD); + fcntl(_sock, F_SETFD, opts | FD_CLOEXEC); +#endif +#endif } Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { @@ -320,6 +336,9 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { _is_stream = p_sock_type == TYPE_TCP; + // Disable descriptor sharing with subprocesses. + _set_close_exec_enabled(true); + #if defined(WINDOWS_ENABLED) if (!_is_stream) { // Disable windows feature/bug reporting WSAECONNRESET/WSAENETRESET when @@ -691,3 +710,4 @@ Error NetSocketPosix::join_multicast_group(const IP_Address &p_multi_address, St Error NetSocketPosix::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) { return _change_multicast_group(p_multi_address, p_if_name, false); } +#endif diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index 40406b241a..e549ea1d6a 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -61,6 +61,7 @@ private: NetError _get_socket_error(); void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream); _FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add); + _FORCE_INLINE_ void _set_close_exec_enabled(bool p_enabled); protected: static NetSocket *_create_func(); diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index b2567249d8..8a03292708 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -141,7 +141,7 @@ EditorAbout::EditorAbout() { hbc->add_child(about_text); TabContainer *tc = memnew(TabContainer); - tc->set_custom_minimum_size(Size2(630, 240) * EDSCALE); + tc->set_custom_minimum_size(Size2(950, 400) * EDSCALE); tc->set_v_size_flags(Control::SIZE_EXPAND_FILL); vbc->add_child(tc); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 2b58d105de..83434a6d9f 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1107,37 +1107,47 @@ void EditorHelp::_update_doc() { class_desc->add_newline(); class_desc->add_newline(); - for (int i = 0; i < methods.size(); i++) { + for (int pass = 0; pass < 2; pass++) { + Vector<DocData::MethodDoc> methods_filtered; - class_desc->push_font(doc_code_font); - _add_method(methods[i], false); - class_desc->pop(); + for (int i = 0; i < methods.size(); i++) { + const String &q = methods[i].qualifiers; + if ((pass == 0 && q.find("virtual") != -1) || (pass == 1 && q.find("virtual") == -1)) { + methods_filtered.push_back(methods[i]); + } + } - class_desc->add_newline(); - class_desc->add_newline(); + for (int i = 0; i < methods_filtered.size(); i++) { - class_desc->push_color(text_color); - class_desc->push_font(doc_font); - class_desc->push_indent(1); - if (methods[i].description.strip_edges() != String()) { - _add_text(methods[i].description); - } else { - class_desc->add_image(get_icon("Error", "EditorIcons")); - class_desc->add_text(" "); - class_desc->push_color(comment_color); - class_desc->append_bbcode(TTR("There is currently no description for this method. Please help us by [color=$color][url=$url]contributing one[/url][/color]!").replace("$url", CONTRIBUTE_URL).replace("$color", link_color_text)); + class_desc->push_font(doc_code_font); + _add_method(methods_filtered[i], false); class_desc->pop(); - } - class_desc->pop(); - class_desc->pop(); - class_desc->pop(); - class_desc->add_newline(); - class_desc->add_newline(); - class_desc->add_newline(); + class_desc->add_newline(); + class_desc->add_newline(); + + class_desc->push_color(text_color); + class_desc->push_font(doc_font); + class_desc->push_indent(1); + if (methods_filtered[i].description.strip_edges() != String()) { + _add_text(methods_filtered[i].description); + } else { + class_desc->add_image(get_icon("Error", "EditorIcons")); + class_desc->add_text(" "); + class_desc->push_color(comment_color); + class_desc->append_bbcode(TTR("There is currently no description for this method. Please help us by [color=$color][url=$url]contributing one[/url][/color]!").replace("$url", CONTRIBUTE_URL).replace("$color", link_color_text)); + class_desc->pop(); + } + + class_desc->pop(); + class_desc->pop(); + class_desc->pop(); + class_desc->add_newline(); + class_desc->add_newline(); + class_desc->add_newline(); + } } } - scroll_locked = false; } diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 690b7a8ec4..460f75eef0 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2649,6 +2649,7 @@ void EditorPropertyResource::update_property() { if (res == RES()) { assign->set_icon(Ref<Texture>()); assign->set_text(TTR("[empty]")); + assign->set_tooltip(""); } else { assign->set_icon(EditorNode::get_singleton()->get_object_icon(res.operator->(), "Node")); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index b7d36ce75a..0d388512f4 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -72,7 +72,7 @@ class SnapDialog : public ConfirmationDialog { public: SnapDialog() { - const int SPIN_BOX_GRID_RANGE = 256; + const int SPIN_BOX_GRID_RANGE = 16384; const int SPIN_BOX_ROTATION_RANGE = 360; Label *label; VBoxContainer *container; @@ -96,6 +96,8 @@ public: grid_offset_x = memnew(SpinBox); grid_offset_x->set_min(-SPIN_BOX_GRID_RANGE); grid_offset_x->set_max(SPIN_BOX_GRID_RANGE); + grid_offset_x->set_allow_lesser(true); + grid_offset_x->set_allow_greater(true); grid_offset_x->set_suffix("px"); grid_offset_x->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_offset_x); @@ -103,6 +105,8 @@ public: grid_offset_y = memnew(SpinBox); grid_offset_y->set_min(-SPIN_BOX_GRID_RANGE); grid_offset_y->set_max(SPIN_BOX_GRID_RANGE); + grid_offset_y->set_allow_lesser(true); + grid_offset_y->set_allow_greater(true); grid_offset_y->set_suffix("px"); grid_offset_y->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_offset_y); @@ -115,6 +119,7 @@ public: grid_step_x = memnew(SpinBox); grid_step_x->set_min(0.01); grid_step_x->set_max(SPIN_BOX_GRID_RANGE); + grid_step_x->set_allow_greater(true); grid_step_x->set_suffix("px"); grid_step_x->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_step_x); @@ -122,6 +127,7 @@ public: grid_step_y = memnew(SpinBox); grid_step_y->set_min(0.01); grid_step_y->set_max(SPIN_BOX_GRID_RANGE); + grid_step_y->set_allow_greater(true); grid_step_y->set_suffix("px"); grid_step_y->set_h_size_flags(SIZE_EXPAND_FILL); child_container->add_child(grid_step_y); @@ -2708,6 +2714,7 @@ void CanvasItemEditor::_draw_ruler_tool() { font_secondary_color.a = 0.5; float text_height = font->get_height(); const float text_width = 76; + const float angle_text_width = 54; Point2 text_pos = (begin + end) / 2 - Vector2(text_width / 2, text_height / 2); text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5); @@ -2715,14 +2722,38 @@ void CanvasItemEditor::_draw_ruler_tool() { viewport->draw_string(font, text_pos, vformat("%.2f px", length_vector.length()), font_color); if (draw_secondary_lines) { + int horizontal_axis_angle = round(180 * atan2(length_vector.y, length_vector.x) / Math_PI); + int vertictal_axis_angle = 90 - horizontal_axis_angle; Point2 text_pos2 = text_pos; text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2); viewport->draw_string(font, text_pos2, vformat("%.2f px", length_vector.y), font_secondary_color); + Point2 v_angle_text_pos = Point2(); + v_angle_text_pos.x = CLAMP(begin.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width); + v_angle_text_pos.y = begin.y < end.y ? MIN(text_pos2.y - 2 * text_height, begin.y - text_height * 0.5) : MAX(text_pos2.y + text_height * 3, begin.y + text_height * 1.5); + viewport->draw_string(font, v_angle_text_pos, vformat("%d deg", vertictal_axis_angle), font_secondary_color); + text_pos2 = text_pos; text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y - text_height / 2) : MAX(text_pos.y + text_height * 2, end.y - text_height / 2); viewport->draw_string(font, text_pos2, vformat("%.2f px", length_vector.x), font_secondary_color); + + Point2 h_angle_text_pos = Point2(); + h_angle_text_pos.x = CLAMP(end.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width); + if (begin.y < end.y) { + h_angle_text_pos.y = end.y + text_height * 1.5; + if (ABS(text_pos2.x - h_angle_text_pos.x) < text_width) { + int height_multiplier = 1.5 + (int)is_snap_active; + h_angle_text_pos.y = MAX(text_pos.y + height_multiplier * text_height, MAX(end.y + text_height * 1.5, text_pos2.y + height_multiplier * text_height)); + } + } else { + h_angle_text_pos.y = end.y - text_height * 0.5; + if (ABS(text_pos2.x - h_angle_text_pos.x) < text_width) { + int height_multiplier = 1 + (int)is_snap_active; + h_angle_text_pos.y = MIN(text_pos.y - height_multiplier * text_height, MIN(end.y - text_height * 0.5, text_pos2.y - height_multiplier * text_height)); + } + } + viewport->draw_string(font, h_angle_text_pos, vformat("%d deg", horizontal_axis_angle), font_secondary_color); } if (is_snap_active) { diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index a56cfede34..35187214a6 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -74,6 +74,26 @@ static const char *_axis_names[JOY_AXIS_MAX * 2] = { "", " (R2)" }; +void ProjectSettingsEditor::_unhandled_input(const Ref<InputEvent> &p_event) { + + const Ref<InputEventKey> k = p_event; + + if (k.is_valid() && is_window_modal_on_top() && k->is_pressed()) { + + if (k->get_scancode_with_modifiers() == (KEY_MASK_CMD | KEY_F)) { + if (search_button->is_pressed()) { + search_box->grab_focus(); + search_box->select_all(); + } else { + // This toggles the search bar display while giving the button its "pressed" appearance + search_button->set_pressed(true); + } + + accept_event(); + } + } +} + void ProjectSettingsEditor::_notification(int p_what) { switch (p_what) { @@ -116,6 +136,7 @@ void ProjectSettingsEditor::_notification(int p_what) { } break; case NOTIFICATION_POPUP_HIDE: { EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "project_settings", get_rect()); + set_process_unhandled_input(false); } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { search_button->set_icon(get_icon("Search", "EditorIcons")); @@ -800,6 +821,7 @@ void ProjectSettingsEditor::popup_project_settings() { _update_translations(); autoload_settings->update_autoload(); plugin_settings->update_plugins(); + set_process_unhandled_input(true); } void ProjectSettingsEditor::update_plugins() { @@ -823,13 +845,9 @@ void ProjectSettingsEditor::_item_adds(String) { void ProjectSettingsEditor::_item_add() { - Variant value; - switch (type->get_selected()) { - case 0: value = false; break; - case 1: value = 0; break; - case 2: value = 0.0; break; - case 3: value = ""; break; - } + // Initialize the property with the default value for the given type + Variant::CallError ce; + const Variant value = Variant::construct(Variant::Type(type->get_selected()), NULL, 0, ce); String catname = category->get_text().strip_edges(); String propname = property->get_text().strip_edges(); @@ -1697,6 +1715,7 @@ void ProjectSettingsEditor::_editor_restart_close() { void ProjectSettingsEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_unhandled_input"), &ProjectSettingsEditor::_unhandled_input); ClassDB::bind_method(D_METHOD("_item_selected"), &ProjectSettingsEditor::_item_selected); ClassDB::bind_method(D_METHOD("_item_add"), &ProjectSettingsEditor::_item_add); ClassDB::bind_method(D_METHOD("_item_adds"), &ProjectSettingsEditor::_item_adds); @@ -1811,10 +1830,11 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { type = memnew(OptionButton); type->set_h_size_flags(Control::SIZE_EXPAND_FILL); add_prop_bar->add_child(type); - type->add_item("bool"); - type->add_item("int"); - type->add_item("float"); - type->add_item("string"); + + // Start at 1 to avoid adding "Nil" as an option + for (int i = 1; i < Variant::VARIANT_MAX; i++) { + type->add_item(Variant::get_type_name(Variant::Type(i)), i); + } Button *add = memnew(Button); add_prop_bar->add_child(add); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 4dfd8ba602..c164b49d0e 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -178,6 +178,7 @@ class ProjectSettingsEditor : public AcceptDialog { void _editor_restart_close(); protected: + void _unhandled_input(const Ref<InputEvent> &p_event); void _notification(int p_what); static void _bind_methods(); diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index c9c1f9c3e0..f8425ebe22 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -140,32 +140,35 @@ void EditorSettingsDialog::_notification(int p_what) { void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) { - Ref<InputEventKey> k = p_event; + const Ref<InputEventKey> k = p_event; - if (k.is_valid() && is_window_modal_on_top()) { + if (k.is_valid() && is_window_modal_on_top() && k->is_pressed()) { - if (k->is_pressed()) { + bool handled = false; - bool handled = false; + if (ED_IS_SHORTCUT("editor/undo", p_event)) { + String action = undo_redo->get_current_action_name(); + if (action != "") + EditorNode::get_log()->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR); + undo_redo->undo(); + handled = true; + } - if (ED_IS_SHORTCUT("editor/undo", p_event)) { - String action = undo_redo->get_current_action_name(); - if (action != "") - EditorNode::get_log()->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR); - undo_redo->undo(); - handled = true; - } - if (ED_IS_SHORTCUT("editor/redo", p_event)) { - undo_redo->redo(); - String action = undo_redo->get_current_action_name(); - if (action != "") - EditorNode::get_log()->add_message("Redo: " + action, EditorLog::MSG_TYPE_EDITOR); - handled = true; - } + if (ED_IS_SHORTCUT("editor/redo", p_event)) { + undo_redo->redo(); + String action = undo_redo->get_current_action_name(); + if (action != "") + EditorNode::get_log()->add_message("Redo: " + action, EditorLog::MSG_TYPE_EDITOR); + handled = true; + } - if (handled) { - accept_event(); - } + if (k->get_scancode_with_modifiers() == (KEY_MASK_CMD | KEY_F)) { + _focus_current_search_box(); + handled = true; + } + + if (handled) { + accept_event(); } } } @@ -408,7 +411,6 @@ EditorSettingsDialog::EditorSettingsDialog() { tabs->set_tab_align(TabContainer::ALIGN_LEFT); tabs->connect("tab_changed", this, "_tabs_tab_changed"); add_child(tabs); - //set_child_rect(tabs); // General Tab @@ -425,7 +427,6 @@ EditorSettingsDialog::EditorSettingsDialog() { hbc->add_child(search_box); inspector = memnew(SectionedInspector); - //inspector->hide_top_label(); inspector->get_inspector()->set_use_filter(true); inspector->register_search_box(search_box); inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -474,7 +475,6 @@ EditorSettingsDialog::EditorSettingsDialog() { shortcuts->set_v_size_flags(SIZE_EXPAND_FILL); shortcuts->set_columns(2); shortcuts->set_hide_root(true); - //shortcuts->set_hide_folding(true); shortcuts->set_column_titles_visible(true); shortcuts->set_column_title(0, TTR("Name")); shortcuts->set_column_title(1, TTR("Binding")); @@ -495,9 +495,7 @@ EditorSettingsDialog::EditorSettingsDialog() { press_a_key->connect("gui_input", this, "_wait_for_key"); press_a_key->connect("confirmed", this, "_press_a_key_confirm"); - //get_ok()->set_text("Apply"); set_hide_on_ok(true); - //get_cancel()->set_text("Close"); timer = memnew(Timer); timer->set_wait_time(1.5); diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml index 7e1cac243a..aa48ab44f2 100644 --- a/modules/gdnative/doc_classes/GDNativeLibrary.xml +++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml @@ -1,35 +1,50 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.2"> <brief_description> + An external library containing functions or script classes to use in Godot. </brief_description> <description> + A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as [ARVRInterfaceGDNative]. The library must be compiled for each platform and architecture that the project will run on. </description> <tutorials> + <link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link> + <link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-cpp-example.html</link> </tutorials> <methods> <method name="get_current_dependencies" qualifiers="const"> <return type="PoolStringArray"> </return> <description> + Returns paths to all dependency libraries for the current platform and architecture. </description> </method> <method name="get_current_library_path" qualifiers="const"> <return type="String"> </return> <description> + Returns the path to the dynamic library file for the current platform and architecture. </description> </method> </methods> <members> <member name="config_file" type="ConfigFile" setter="set_config_file" getter="get_config_file"> + This resource in INI-style [ConfigFile] format, as in [code].gdnlib[/code] files. </member> <member name="load_once" type="bool" setter="set_load_once" getter="should_load_once" default="true"> + If [code]true[/code], Godot loads only one copy of the library and each script that references the library will share static data like static or global variables. + If [code]false[/code], Godot loads a separate copy of the library into memory for each script that references it. </member> <member name="reloadable" type="bool" setter="set_reloadable" getter="is_reloadable" default="true"> + If [code]true[/code], the editor will temporarily unload the library whenever the user switches away from the editor window, allowing the user to recompile the library without restarting Godot. + [b]Note:[/b] If the library defines tool scripts that run inside the editor, [code]reloadable[/code] must be [code]false[/code]. Otherwise, the editor will attempt to unload the tool scripts while they're in use and crash. </member> <member name="singleton" type="bool" setter="set_singleton" getter="is_singleton" default="false"> + If [code]true[/code], Godot loads the library at startup rather than the first time a script uses the library, calling [code]{prefix}gdnative_singleton[/code] after initializing the library (where [code]{prefix}[/code] is the value of [member symbol_prefix]). The library remains loaded as long as Godot is running. + [b]Note:[/b] A singleton library cannot be [member reloadable]. </member> <member name="symbol_prefix" type="String" setter="set_symbol_prefix" getter="get_symbol_prefix" default=""godot_""> + The prefix this library's entry point functions begin with. For example, a GDNativeLibrary would declare its [code]gdnative_init[/code] function as [code]godot_gdnative_init[/code] by default. + On platforms that require statically linking libraries (currently only iOS), each library must have a different [code]symbol_prefix[/code]. </member> </members> <constants> diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 783ad4e147..ee9e71d4a0 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -339,7 +339,7 @@ bool GDNative::initialize() { if (err || !library_init) { OS::get_singleton()->close_dynamic_library(native_handle); native_handle = NULL; - ERR_PRINT("Failed to obtain godot_gdnative_init symbol"); + ERR_PRINTS("Failed to obtain " + library->get_symbol_prefix() + "gdnative_init symbol"); return false; } diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 6ff6262b56..0194199133 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -277,7 +277,7 @@ void register_gdnative_types() { proc_ptr); if (err != OK) { - ERR_PRINT((String("No godot_gdnative_singleton in \"" + singleton->get_library()->get_current_library_path()) + "\" found").utf8().get_data()); + ERR_PRINTS("No " + lib->get_symbol_prefix() + "gdnative_singleton in \"" + singleton->get_library()->get_current_library_path() + "\" found"); } else { singleton_gdnatives.push_back(singleton); ((void (*)())proc_ptr)(); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 067fa6f4b9..67dce172dc 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -95,6 +95,11 @@ public class GodotLib { public static native void touch(int what, int pointer, int howmany, int[] arr); /** + * Forward hover events from the main thread to the GL thread. + */ + public static native void hover(int type, int x, int y); + + /** * Forward accelerometer sensor events from the main thread to the GL thread. * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) */ diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index 2beca67922..2756ca6c83 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -188,7 +188,18 @@ public class GodotInputHandler implements InputDeviceListener { } return true; } - }; + } else if ((event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) { + final int x = Math.round(event.getX()); + final int y = Math.round(event.getY()); + final int type = event.getAction(); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.hover(type, x, y); + } + }); + return true; + } return false; } diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 30676783db..7daea19961 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -826,6 +826,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jo */ } +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jobject obj, jint p_type, jint p_x, jint p_y) { + if (step == 0) + return; + + os_android->process_hover(p_type, Point2(p_x, p_y)); +} + /* * Android Key codes. */ diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index 11bda94f8d..a564bbd4a1 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -45,6 +45,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jobject obj, jint ev, jint pointer, jint count, jintArray positions); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jobject obj, jint p_type, jint p_x, jint p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jobject obj, jint p_device, jint p_button, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jobject obj, jint p_device, jint p_axis, jfloat p_value); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 49ab0ea84a..91bd6cbdd2 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -477,6 +477,23 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos> } } +void OS_Android::process_hover(int p_type, Point2 p_pos) { + // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER + switch (p_type) { + case 7: // hover move + case 9: // hover enter + case 10: { // hover exit + Ref<InputEventMouseMotion> ev; + ev.instance(); + ev->set_position(p_pos); + ev->set_global_position(p_pos); + ev->set_relative(p_pos - hover_prev_pos); + input->parse_input_event(ev); + hover_prev_pos = p_pos; + } break; + } +} + void OS_Android::process_accelerometer(const Vector3 &p_accelerometer) { input->set_accelerometer(p_accelerometer); diff --git a/platform/android/os_android.h b/platform/android/os_android.h index a17941f7c0..9bad9b2e01 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -70,6 +70,7 @@ public: private: Vector<TouchPos> touch; + Point2 hover_prev_pos; // needed to calculate the relative position on hover events bool use_gl2; bool use_apk_expansion; @@ -186,6 +187,7 @@ public: void process_magnetometer(const Vector3 &p_magnetometer); void process_gyroscope(const Vector3 &p_gyroscope); void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points); + void process_hover(int p_type, Point2 p_pos); void process_joy_event(JoypadEvent p_event); void process_event(Ref<InputEvent> p_event); void init_video_mode(int p_video_width, int p_video_height); diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index af9ce2a4bf..83f92ce2bc 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -135,12 +135,12 @@ void Sprite::set_texture(const Ref<Texture> &p_texture) { return; if (texture.is_valid()) - texture->remove_change_receptor(this); + texture->disconnect(CoreStringNames::get_singleton()->changed, this, "_texture_changed"); texture = p_texture; if (texture.is_valid()) - texture->add_change_receptor(this); + texture->connect(CoreStringNames::get_singleton()->changed, this, "_texture_changed"); update(); emit_signal("texture_changed"); @@ -389,11 +389,11 @@ void Sprite::_validate_property(PropertyInfo &property) const { } } -void Sprite::_changed_callback(Object *p_changed, const char *p_prop) { +void Sprite::_texture_changed() { // Changes to the texture need to trigger an update to make // the editor redraw the sprite with the updated texture. - if (texture.is_valid() && texture.ptr() == p_changed) { + if (texture.is_valid()) { update(); } } @@ -443,6 +443,8 @@ void Sprite::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rect"), &Sprite::get_rect); + ClassDB::bind_method(D_METHOD("_texture_changed"), &Sprite::_texture_changed); + ADD_SIGNAL(MethodInfo("frame_changed")); ADD_SIGNAL(MethodInfo("texture_changed")); @@ -480,6 +482,4 @@ Sprite::Sprite() { } Sprite::~Sprite() { - if (texture.is_valid()) - texture->remove_change_receptor(this); } diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h index 5e6717a3f5..d3c0112e62 100644 --- a/scene/2d/sprite.h +++ b/scene/2d/sprite.h @@ -57,6 +57,8 @@ class Sprite : public Node2D { void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const; + void _texture_changed(); + protected: void _notification(int p_what); @@ -64,8 +66,6 @@ protected: virtual void _validate_property(PropertyInfo &property) const; - virtual void _changed_callback(Object *p_changed, const char *p_prop); - public: virtual Dictionary _edit_get_state() const; virtual void _edit_set_state(const Dictionary &p_state); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index fc67b28095..fafbcf0c55 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1412,6 +1412,9 @@ void Control::_size_changed() { } void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) { + + ERR_FAIL_INDEX((int)p_margin, 4); + Rect2 parent_rect = get_parent_anchorable_rect(); float parent_range = (p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? parent_rect.size.x : parent_rect.size.y; float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range; @@ -1456,6 +1459,9 @@ void Control::set_anchor_and_margin(Margin p_margin, float p_anchor, float p_pos } void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { + + ERR_FAIL_INDEX((int)p_preset, 16); + //Left switch (p_preset) { case PRESET_TOP_LEFT: @@ -1570,6 +1576,10 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { } void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode, int p_margin) { + + ERR_FAIL_INDEX((int)p_preset, 16); + ERR_FAIL_INDEX((int)p_resize_mode, 4); + // Calculate the size if the node is not resized Size2 min_size = get_minimum_size(); Size2 new_size = get_size(); @@ -1704,6 +1714,8 @@ void Control::set_anchors_and_margins_preset(LayoutPreset p_preset, LayoutPreset float Control::get_anchor(Margin p_margin) const { + ERR_FAIL_INDEX_V(int(p_margin), 4, 0.0); + return data.anchor[p_margin]; } @@ -1720,6 +1732,8 @@ void Control::_change_notify_margins() { void Control::set_margin(Margin p_margin, float p_value) { + ERR_FAIL_INDEX((int)p_margin, 4); + data.margin[p_margin] = p_value; _size_changed(); } @@ -1740,6 +1754,8 @@ void Control::set_end(const Size2 &p_point) { float Control::get_margin(Margin p_margin) const { + ERR_FAIL_INDEX_V((int)p_margin, 4, 0); + return data.margin[p_margin]; } @@ -1951,6 +1967,8 @@ void Control::add_constant_override(const StringName &p_name, int p_constant) { void Control::set_focus_mode(FocusMode p_focus_mode) { + ERR_FAIL_INDEX((int)p_focus_mode, 3); + if (is_inside_tree() && p_focus_mode == FOCUS_NONE && data.focus_mode != FOCUS_NONE && has_focus()) release_focus(); @@ -2298,6 +2316,8 @@ Control *Control::make_custom_tooltip(const String &p_text) const { void Control::set_default_cursor_shape(CursorShape p_shape) { + ERR_FAIL_INDEX(int(p_shape), CURSOR_MAX); + data.default_cursor = p_shape; } @@ -2358,6 +2378,8 @@ NodePath Control::get_focus_previous() const { Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) { + ERR_FAIL_INDEX_V((int)p_margin, 4, NULL); + if (p_count >= MAX_NEIGHBOUR_SEARCH_COUNT) return NULL; if (!data.focus_neighbour[p_margin].is_empty()) { @@ -2760,6 +2782,8 @@ bool Control::is_clipping_contents() { void Control::set_h_grow_direction(GrowDirection p_direction) { + ERR_FAIL_INDEX((int)p_direction, 3); + data.h_grow = p_direction; _size_changed(); } @@ -2771,6 +2795,8 @@ Control::GrowDirection Control::get_h_grow_direction() const { void Control::set_v_grow_direction(GrowDirection p_direction) { + ERR_FAIL_INDEX((int)p_direction, 3); + data.v_grow = p_direction; _size_changed(); } diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 9bc593ea3b..24c046457b 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -637,6 +637,8 @@ bool FileDialog::is_mode_overriding_title() const { void FileDialog::set_mode(Mode p_mode) { + ERR_FAIL_INDEX((int)p_mode, 5); + mode = p_mode; switch (mode) { diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index a3bc68ffcd..4d06bee0d4 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -430,6 +430,7 @@ ItemList::SelectMode ItemList::get_select_mode() const { void ItemList::set_icon_mode(IconMode p_mode) { + ERR_FAIL_INDEX((int)p_mode, 2); icon_mode = p_mode; update(); shape_changed = true; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index a7c6c5ccab..08faaf7d45 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -79,7 +79,7 @@ Size2 PopupMenu::get_minimum_size() const { if (items[i].checkable_type) has_check = true; - String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text; + String text = items[i].xl_text; size.width += font->get_string_size(text).width; if (i > 0) size.height += vseparation; @@ -519,7 +519,7 @@ void PopupMenu::_notification(int p_what) { hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation))); } - String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text; + String text = items[i].xl_text; item_ofs.x += items[i].h_ofs; if (items[i].separator) { @@ -627,63 +627,50 @@ void PopupMenu::_notification(int p_what) { } } -void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { +/* Methods to add items with or without icon, checkbox, shortcut. + * Be sure to keep them in sync when adding new properties in the Item struct. + */ - Item item; - item.icon = p_icon; - item.text = p_label; - item.xl_text = tr(p_label); +#define ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel) \ + item.text = p_label; \ + item.xl_text = tr(p_label); \ + item.id = p_id == -1 ? items.size() : p_id; \ item.accel = p_accel; - item.id = p_id; - items.push_back(item); - update(); - minimum_size_changed(); -} + void PopupMenu::add_item(const String &p_label, int p_id, uint32_t p_accel) { Item item; - item.text = p_label; - item.xl_text = tr(p_label); - item.accel = p_accel; - item.id = p_id == -1 ? items.size() : p_id; + ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) { +void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { Item item; - item.text = p_label; - item.xl_text = tr(p_label); - item.id = p_id; - item.submenu = p_submenu; + ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); + item.icon = p_icon; items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { +void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) { Item item; - item.icon = p_icon; - item.text = p_label; - item.xl_text = tr(p_label); - item.accel = p_accel; - item.id = p_id; + ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) { +void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { Item item; - item.text = p_label; - item.xl_text = tr(p_label); - item.accel = p_accel; - item.id = p_id == -1 ? items.size() : p_id; + ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); + item.icon = p_icon; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); @@ -692,63 +679,59 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p_accel) { - add_check_item(p_label, p_id, p_accel); - items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + Item item; + ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); + item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.push_back(item); update(); minimum_size_changed(); } void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) { - add_icon_check_item(p_icon, p_label, p_id, p_accel); - items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + Item item; + ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); + item.icon = p_icon; + item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { - - ERR_FAIL_COND(p_shortcut.is_null()); - - _ref_shortcut(p_shortcut); +void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, uint32_t p_accel) { Item item; - item.id = p_id; - item.icon = p_icon; - item.shortcut = p_shortcut; - item.shortcut_is_global = p_global; + ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); + item.max_states = p_max_states; + item.state = p_default_state; items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { - - ERR_FAIL_COND(p_shortcut.is_null()); +#define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \ + ERR_FAIL_COND_MSG(p_shortcut.is_null(), "Cannot add item with invalid ShortCut."); \ + _ref_shortcut(p_shortcut); \ + item.text = p_shortcut->get_name(); \ + item.xl_text = tr(item.text); \ + item.id = p_id == -1 ? items.size() : p_id; \ + item.shortcut = p_shortcut; \ + item.shortcut_is_global = p_global; - _ref_shortcut(p_shortcut); +void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { Item item; - item.id = p_id; - item.shortcut = p_shortcut; - item.shortcut_is_global = p_global; + ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { - - ERR_FAIL_COND(p_shortcut.is_null()); - - _ref_shortcut(p_shortcut); +void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { Item item; - item.id = p_id; - item.shortcut = p_shortcut; - item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; + ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); item.icon = p_icon; - item.shortcut_is_global = p_global; items.push_back(item); update(); minimum_size_changed(); @@ -756,14 +739,19 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<Sh void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { - ERR_FAIL_COND(p_shortcut.is_null()); + Item item; + ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); + item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; + items.push_back(item); + update(); + minimum_size_changed(); +} - _ref_shortcut(p_shortcut); +void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { Item item; - item.id = p_id; - item.shortcut = p_shortcut; - item.shortcut_is_global = p_global; + ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); + item.icon = p_icon; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); @@ -772,26 +760,42 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bo void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { - add_check_shortcut(p_shortcut, p_id, p_global); - items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + Item item; + ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); + item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.push_back(item); update(); minimum_size_changed(); } -void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, uint32_t p_accel) { +void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) { + + Item item; + ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); + item.icon = p_icon; + item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.push_back(item); + update(); + minimum_size_changed(); +} + +void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) { Item item; item.text = p_label; item.xl_text = tr(p_label); - item.accel = p_accel; - item.id = p_id; - item.max_states = p_max_states; - item.state = p_default_state; + item.id = p_id == -1 ? items.size() : p_id; + item.submenu = p_submenu; items.push_back(item); update(); minimum_size_changed(); } +#undef ITEM_SETUP_WITH_ACCEL +#undef ITEM_SETUP_WITH_SHORTCUT + +/* Methods to modify existing items. */ + void PopupMenu::set_item_text(int p_idx, const String &p_text) { ERR_FAIL_INDEX(p_idx, items.size()); @@ -1380,18 +1384,24 @@ void PopupMenu::clear_autohide_areas() { void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input); - ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("add_icon_check_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_check_item, DEFVAL(-1), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_check_item", "label", "id", "accel"), &PopupMenu::add_check_item, DEFVAL(-1), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_icon_check_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_check_item, DEFVAL(-1), DEFVAL(0)); ClassDB::bind_method(D_METHOD("add_radio_check_item", "label", "id", "accel"), &PopupMenu::add_radio_check_item, DEFVAL(-1), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("add_submenu_item", "label", "submenu", "id"), &PopupMenu::add_submenu_item, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_icon_radio_check_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_radio_check_item, DEFVAL(-1), DEFVAL(0)); + + ClassDB::bind_method(D_METHOD("add_multistate_item", "label", "max_states", "default_state", "id", "accel"), &PopupMenu::add_multistate_item, DEFVAL(0), DEFVAL(-1), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("add_icon_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_shortcut, DEFVAL(-1), DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_shortcut", "shortcut", "id", "global"), &PopupMenu::add_shortcut, DEFVAL(-1), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("add_icon_check_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_check_shortcut, DEFVAL(-1), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_icon_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_shortcut, DEFVAL(-1), DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_check_shortcut", "shortcut", "id", "global"), &PopupMenu::add_check_shortcut, DEFVAL(-1), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_icon_check_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_check_shortcut, DEFVAL(-1), DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_radio_check_shortcut", "shortcut", "id", "global"), &PopupMenu::add_radio_check_shortcut, DEFVAL(-1), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_icon_radio_check_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_radio_check_shortcut, DEFVAL(-1), DEFVAL(false)); + + ClassDB::bind_method(D_METHOD("add_submenu_item", "label", "submenu", "id"), &PopupMenu::add_submenu_item, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("set_item_text", "idx", "text"), &PopupMenu::set_item_text); ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "icon"), &PopupMenu::set_item_icon); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 8bfe8fc607..8c33178b09 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -120,21 +120,23 @@ protected: static void _bind_methods(); public: - void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0); void add_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0); - void add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0); + void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0); void add_check_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0); + void add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0); void add_radio_check_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0); void add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0); - void add_submenu_item(const String &p_label, const String &p_submenu, int p_id = -1); - void add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_multistate_item(const String &p_label, int p_max_states, int p_default_state = 0, int p_id = -1, uint32_t p_accel = 0); + void add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); - void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); void add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); + void add_icon_radio_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false); - void add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id = -1, uint32_t p_accel = 0); + void add_submenu_item(const String &p_label, const String &p_submenu, int p_id = -1); void set_item_text(int p_idx, const String &p_text); void set_item_icon(int p_idx, const Ref<Texture> &p_icon); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index c5330c78e1..42cb89b2d6 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -143,6 +143,8 @@ Rect2 RichTextLabel::_get_text_rect() { int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) { + ERR_FAIL_INDEX_V((int)p_mode, 3, 0); + RID ci; if (r_outside) *r_outside = false; @@ -1416,6 +1418,9 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) { } bool RichTextLabel::_find_by_type(Item *p_item, ItemType p_type) { + + ERR_FAIL_INDEX_V((int)p_type, 19, false); + Item *item = p_item; while (item) { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index e2bb4e3e91..c0b0944e47 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1271,7 +1271,8 @@ void TextEdit::_notification(int p_what) { } // Loop through characters in one line. - for (int j = 0; j < str.length(); j++) { + int j = 0; + for (; j < str.length(); j++) { if (syntax_coloring) { if (color_map.has(last_wrap_column + j)) { @@ -1501,7 +1502,7 @@ void TextEdit::_notification(int p_what) { } } - if (cursor.column == last_wrap_column + str.length() && cursor.line == line && cursor_wrap_index == line_wrap_index && (char_ofs + char_margin) >= xmargin_beg) { + if (cursor.column == (last_wrap_column + j) && cursor.line == line && cursor_wrap_index == line_wrap_index && (char_ofs + char_margin) >= xmargin_beg) { cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y); cursor_pos.y += (get_row_height() - cache.font->get_height()) / 2; diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index 423794d8ba..473cee5ca1 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "texture_rect.h" +#include "core/core_string_names.h" #include "servers/visual_server.h" void TextureRect::_notification(int p_what) { @@ -123,6 +124,7 @@ void TextureRect::_bind_methods() { ClassDB::bind_method(D_METHOD("is_flipped_v"), &TextureRect::is_flipped_v); ClassDB::bind_method(D_METHOD("set_stretch_mode", "stretch_mode"), &TextureRect::set_stretch_mode); ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureRect::get_stretch_mode); + ClassDB::bind_method(D_METHOD("_texture_changed"), &TextureRect::_texture_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand"); @@ -140,9 +142,27 @@ void TextureRect::_bind_methods() { BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_COVERED); } +void TextureRect::_texture_changed() { + + if (texture.is_valid()) { + update(); + minimum_size_changed(); + } +} + void TextureRect::set_texture(const Ref<Texture> &p_tex) { + if (p_tex == texture) + return; + + if (texture.is_valid()) + texture->disconnect(CoreStringNames::get_singleton()->changed, this, "_texture_changed"); + texture = p_tex; + + if (texture.is_valid()) + texture->connect(CoreStringNames::get_singleton()->changed, this, "_texture_changed"); + update(); /* if (texture.is_valid()) diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h index 1c5bd9d99c..d144020562 100644 --- a/scene/gui/texture_rect.h +++ b/scene/gui/texture_rect.h @@ -56,6 +56,8 @@ private: Ref<Texture> texture; StretchMode stretch_mode; + void _texture_changed(); + protected: void _notification(int p_what); virtual Size2 get_minimum_size() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 1b52796dc7..c9d1295557 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -827,6 +827,7 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_color", "column", "color"), &TreeItem::set_custom_color); ClassDB::bind_method(D_METHOD("clear_custom_color", "column"), &TreeItem::clear_custom_color); + ClassDB::bind_method(D_METHOD("get_custom_color", "column"), &TreeItem::get_custom_color); ClassDB::bind_method(D_METHOD("set_custom_bg_color", "column", "color", "just_outline"), &TreeItem::set_custom_bg_color, DEFVAL(false)); ClassDB::bind_method(D_METHOD("clear_custom_bg_color", "column"), &TreeItem::clear_custom_bg_color); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index d15a972358..c2e2f85723 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -117,6 +117,7 @@ void ImageTexture::reload_from_file() { } else { Resource::reload_from_file(); _change_notify(); + emit_changed(); } } @@ -180,6 +181,7 @@ void ImageTexture::_reload_hook(const RID &p_hook) { VisualServer::get_singleton()->texture_set_data(texture, img); _change_notify(); + emit_changed(); } void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uint32_t p_flags) { @@ -190,6 +192,7 @@ void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uin w = p_width; h = p_height; _change_notify(); + emit_changed(); } void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags) { @@ -202,23 +205,23 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags); VisualServer::get_singleton()->texture_set_data(texture, p_image); _change_notify(); + emit_changed(); image_stored = true; } void ImageTexture::set_flags(uint32_t p_flags) { - /* uint32_t cube = flags & FLAG_CUBEMAP; - if (flags == p_flags&cube) + if (flags == p_flags) return; - flags=p_flags|cube; */ flags = p_flags; if (w == 0 || h == 0) { return; //uninitialized, do not set to texture } VisualServer::get_singleton()->texture_set_flags(texture, p_flags); _change_notify("flags"); + emit_changed(); } uint32_t ImageTexture::get_flags() const { @@ -250,6 +253,8 @@ void ImageTexture::set_data(const Ref<Image> &p_image) { VisualServer::get_singleton()->texture_set_data(texture, p_image); _change_notify(); + emit_changed(); + alpha_cache.unref(); image_stored = true; } @@ -736,6 +741,7 @@ Error StreamTexture::load(const String &p_path) { format = image->get_format(); _change_notify(); + emit_changed(); return OK; } String StreamTexture::get_load_path() const { @@ -827,6 +833,7 @@ void StreamTexture::set_flags(uint32_t p_flags) { flags = p_flags; VS::get_singleton()->texture_set_flags(texture, flags); _change_notify("flags"); + emit_changed(); } void StreamTexture::reload_from_file() { diff --git a/scene/resources/world.cpp b/scene/resources/world.cpp index 0ca5d7eb36..2c22f45f9d 100644 --- a/scene/resources/world.cpp +++ b/scene/resources/world.cpp @@ -332,7 +332,9 @@ World::World() { PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/3d/default_gravity", 9.8)); PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/3d/default_gravity_vector", Vector3(0, -1, 0))); PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/3d/default_linear_damp", 0.1)); + ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_linear_damp", PropertyInfo(Variant::REAL, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater")); PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/3d/default_angular_damp", 0.1)); + ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_angular_damp", PropertyInfo(Variant::REAL, "physics/3d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater")); #ifdef _3D_DISABLED indexer = NULL; diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 13b45f58dc..b5743ad416 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -394,7 +394,9 @@ World2D::World2D() { Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 98)); Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/2d/default_gravity_vector", Vector2(0, 1))); Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/2d/default_linear_damp", 0.1)); - Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1)); + ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_linear_damp", PropertyInfo(Variant::REAL, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater")); + Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1.0)); + ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_angular_damp", PropertyInfo(Variant::REAL, "physics/2d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater")); indexer = memnew(SpatialIndexer2D); } diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 3b549afb02..ae99d64eee 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2914,6 +2914,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg); + // Check if block has a variable with the same name as function to prevent shader crash. + ShaderLanguage::BlockNode *bnode = p_block; + while (bnode) { + if (bnode->variables.has(name)) { + _set_error("Expected function name"); + return NULL; + } + bnode = bnode->parent_block; + } + //test if function was parsed first for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == name) { @@ -3842,9 +3852,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } StringName name = tk.text; - if (_find_identifier(p_block, p_builtin_types, name)) { - _set_error("Redefinition of '" + String(name) + "'"); - return ERR_PARSE_ERROR; + ShaderLanguage::IdentifierType itype; + if (_find_identifier(p_block, p_builtin_types, name, (ShaderLanguage::DataType *)0, &itype)) { + if (itype != IDENTIFIER_FUNCTION) { + _set_error("Redefinition of '" + String(name) + "'"); + return ERR_PARSE_ERROR; + } } BlockNode::Variable var; @@ -4002,6 +4015,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui return ERR_PARSE_ERROR; } + if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { + _set_error("Expected constant expression"); + return ERR_PARSE_ERROR; + } + if (var.type != n->get_datatype()) { _set_error("Invalid assignment of '" + get_datatype_name(n->get_datatype()) + "' to '" + get_datatype_name(var.type) + "'"); return ERR_PARSE_ERROR; @@ -4062,7 +4080,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui Node *n = _parse_and_reduce_expression(p_block, p_builtin_types); if (!n) return ERR_PARSE_ERROR; - + if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { + _set_error("Expected constant expression after '='"); + return ERR_PARSE_ERROR; + } decl.initializer = n; if (var.type != n->get_datatype()) { @@ -5121,9 +5142,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct pname = tk.text; - if (_find_identifier(func_node->body, builtin_types, pname)) { - _set_error("Redefinition of '" + String(pname) + "'"); - return ERR_PARSE_ERROR; + ShaderLanguage::IdentifierType itype; + if (_find_identifier(func_node->body, builtin_types, pname, (ShaderLanguage::DataType *)0, &itype)) { + if (itype != IDENTIFIER_FUNCTION) { + _set_error("Redefinition of '" + String(pname) + "'"); + return ERR_PARSE_ERROR; + } } FunctionNode::Argument arg; arg.type = ptype; |