diff options
68 files changed, 842 insertions, 263 deletions
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 810e290922..bfa8b90344 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -184,11 +184,11 @@ void AStar::disconnect_points(int p_id, int p_with_id, bool bidirectional) { Point *a; bool a_exists = points.lookup(p_id, a); - CRASH_COND(!a_exists); + ERR_FAIL_COND(!a_exists); Point *b; bool b_exists = points.lookup(p_with_id, b); - CRASH_COND(!b_exists); + ERR_FAIL_COND(!b_exists); Segment s(p_id, p_with_id); int remove_direction = bidirectional ? (int)Segment::BIDIRECTIONAL : s.direction; @@ -406,11 +406,11 @@ float AStar::_estimate_cost(int p_from_id, int p_to_id) { Point *from_point; bool from_exists = points.lookup(p_from_id, from_point); - CRASH_COND(!from_exists); + ERR_FAIL_COND_V(!from_exists, 0); Point *to_point; bool to_exists = points.lookup(p_to_id, to_point); - CRASH_COND(!to_exists); + ERR_FAIL_COND_V(!to_exists, 0); return from_point->pos.distance_to(to_point->pos); } @@ -422,11 +422,11 @@ float AStar::_compute_cost(int p_from_id, int p_to_id) { Point *from_point; bool from_exists = points.lookup(p_from_id, from_point); - CRASH_COND(!from_exists); + ERR_FAIL_COND_V(!from_exists, 0); Point *to_point; bool to_exists = points.lookup(p_to_id, to_point); - CRASH_COND(!to_exists); + ERR_FAIL_COND_V(!to_exists, 0); return from_point->pos.distance_to(to_point->pos); } diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 381ba9d010..f09a904953 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -49,11 +49,11 @@ bool InputEvent::is_action(const StringName &p_action) const { return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action); } -bool InputEvent::is_action_pressed(const StringName &p_action) const { +bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo) const { bool pressed; bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); - return valid && pressed && !is_echo(); + return valid && pressed && (p_allow_echo || !is_echo()); } bool InputEvent::is_action_released(const StringName &p_action) const { @@ -112,7 +112,7 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device); ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action); - ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &InputEvent::is_action_pressed); + ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo"), &InputEvent::is_action_pressed, DEFVAL(false)); ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released); ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputEvent::get_action_strength); diff --git a/core/os/input_event.h b/core/os/input_event.h index 14649502ee..a4db618bfe 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -184,7 +184,7 @@ public: int get_device() const; bool is_action(const StringName &p_action) const; - bool is_action_pressed(const StringName &p_action) const; + bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false) const; bool is_action_released(const StringName &p_action) const; float get_action_strength(const StringName &p_action) const; diff --git a/core/script_language.h b/core/script_language.h index 116918fdc0..f90bb4b6c3 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -427,31 +427,6 @@ class ScriptDebugger { ScriptLanguage *break_lang; public: - typedef void (*RequestSceneTreeMessageFunc)(void *); - - struct LiveEditFuncs { - - void *udata; - void (*node_path_func)(void *, const NodePath &p_path, int p_id); - void (*res_path_func)(void *, const String &p_path, int p_id); - - void (*node_set_func)(void *, int p_id, const StringName &p_prop, const Variant &p_value); - void (*node_set_res_func)(void *, int p_id, const StringName &p_prop, const String &p_value); - void (*node_call_func)(void *, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); - void (*res_set_func)(void *, int p_id, const StringName &p_prop, const Variant &p_value); - void (*res_set_res_func)(void *, int p_id, const StringName &p_prop, const String &p_value); - void (*res_call_func)(void *, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); - void (*root_func)(void *, const NodePath &p_scene_path, const String &p_scene_from); - - void (*tree_create_node_func)(void *, const NodePath &p_parent, const String &p_type, const String &p_name); - void (*tree_instance_node_func)(void *, const NodePath &p_parent, const String &p_path, const String &p_name); - void (*tree_remove_node_func)(void *, const NodePath &p_at); - void (*tree_remove_and_keep_node_func)(void *, const NodePath &p_at, ObjectID p_keep_id); - void (*tree_restore_node_func)(void *, ObjectID p_id, const NodePath &p_at, int p_at_pos); - void (*tree_duplicate_node_func)(void *, const NodePath &p_at, const String &p_new_name); - void (*tree_reparent_node_func)(void *, const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos); - }; - _FORCE_INLINE_ static ScriptDebugger *get_singleton() { return singleton; } void set_lines_left(int p_left); int get_lines_left() const; @@ -480,8 +455,6 @@ public: virtual bool is_remote() const { return false; } virtual void request_quit() {} - virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {} - virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {} virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {} virtual bool is_profiling() const = 0; diff --git a/core/ustring.cpp b/core/ustring.cpp index 7ee2fee312..0f82ca7e15 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -1337,7 +1337,17 @@ String String::num_scientific(double p_num) { char buf[256]; #if defined(__GNUC__) || defined(_MSC_VER) + +#if (defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900)) && defined(_TWO_DIGIT_EXPONENT) && !defined(_UCRT) + // MinGW and old MSC require _set_output_format() to conform to C99 output for printf + unsigned int old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT); +#endif snprintf(buf, 256, "%lg", p_num); + +#if (defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900)) && defined(_TWO_DIGIT_EXPONENT) && !defined(_UCRT) + _set_output_format(old_exponent_format); +#endif + #else sprintf(buf, "%.16lg", p_num); #endif diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml index 7dcfa5345d..61e1ea9b8d 100644 --- a/doc/classes/AABB.xml +++ b/doc/classes/AABB.xml @@ -176,6 +176,14 @@ Returns [code]true[/code] if the [AABB] intersects the line segment between [code]from[/code] and [code]to[/code]. </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="aabb" type="AABB"> + </argument> + <description> + </description> + </method> <method name="merge"> <return type="AABB"> </return> diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index 46499ed349..deba30712e 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -151,6 +151,14 @@ [/codeblock] </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="color" type="Color"> + </argument> + <description> + </description> + </method> <method name="lightened"> <return type="Color"> </return> diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml index 5c49e227be..981e0a6180 100644 --- a/doc/classes/EditorScript.xml +++ b/doc/classes/EditorScript.xml @@ -5,7 +5,7 @@ </brief_description> <description> Scripts extending this class and implementing its [method _run] method can be executed from the Script Editor's [b]File > Run[/b] menu option (or by pressing [code]Ctrl+Shift+X[/code]) while the editor is running. This is useful for adding custom in-editor functionality to Godot. For more complex additions, consider using [EditorPlugin]s instead. - [b]Note:[/b] Extending scripts need to have [code]tool mode[/code] enabled. + [b]Note:[/b] Extending scripts need to have [code]tool[/code] mode enabled. [b]Example script:[/b] [codeblock] tool diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml index 3a73d44a01..d0e8a5972f 100644 --- a/doc/classes/HTTPRequest.xml +++ b/doc/classes/HTTPRequest.xml @@ -1,13 +1,43 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="HTTPRequest" inherits="Node" category="Core" version="3.2"> <brief_description> - A node with the ability to send HTTP requests. + A node with the ability to send HTTP(S) requests. </brief_description> <description> A node with the ability to send HTTP requests. Uses [HTTPClient] internally. Can be used to make HTTP requests, i.e. download or upload files or web content via HTTP. + [b]Example of loading and displaying an image using HTTPRequest:[/b] + [codeblock] + func _ready(): + # Create an HTTP request node and connect its completion signal. + var http_request = HTTPRequest.new() + add_child(http_request) + http_request.connect("request_completed", self, "_http_request_completed") + + # Perform the HTTP request. The URL below returns a PNG image as of writing. + var error = http_request.request("https://via.placeholder.com/512") + if error != OK: + push_error("An error occurred in the HTTP request.") + + + # Called when the HTTP request is completed. + func _http_request_completed(result, response_code, headers, body): + var image = Image.new() + var error = image.load_png_from_buffer(body) + if error != OK: + push_error("Couldn't load the image.") + + var texture = ImageTexture.new() + texture.create_from_image(image) + + # Display the image in a TextureRect node. + var texture_rect = TextureRect.new() + add_child(texture_rect) + texture_rect.texture = texture + [/codeblock] </description> <tutorials> + <link>https://docs.godotengine.org/en/latest/tutorials/networking/http_request_class.html</link> <link>https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link> </tutorials> <methods> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index d37ab64cb3..c6d63035d1 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -415,7 +415,7 @@ <argument index="1" name="grayscale" type="bool" default="false"> </argument> <description> - Saves the image as an EXR file to [code]path[/code]. If grayscale is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return [constant ERR_UNAVAILABLE] if Godot was compiled without the TinyEXR module. + Saves the image as an EXR file to [code]path[/code]. If [code]grayscale[/code] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return [constant ERR_UNAVAILABLE] if Godot was compiled without the TinyEXR module. </description> </method> <method name="save_png" qualifiers="const"> diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml index 4c8d83adba..d412ce09e2 100644 --- a/doc/classes/InputEvent.xml +++ b/doc/classes/InputEvent.xml @@ -51,8 +51,10 @@ </return> <argument index="0" name="action" type="String"> </argument> + <argument index="1" name="allow_echo" type="bool" default="false"> + </argument> <description> - Returns [code]true[/code] if the given action is being pressed (and is not an echo event for [InputEventKey] events). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag]. + Returns [code]true[/code] if the given action is being pressed (and is not an echo event for [InputEventKey] events, unless [code]allow_echo[/code] is [code]true[/code]). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag]. </description> </method> <method name="is_action_released" qualifiers="const"> diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml index cb89a746bf..5cd6a0c285 100644 --- a/doc/classes/InputEventMouseMotion.xml +++ b/doc/classes/InputEventMouseMotion.xml @@ -12,16 +12,16 @@ <methods> </methods> <members> + <member name="pressure" type="float" setter="set_pressure" getter="get_pressure" default="0.0"> + Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code]. + </member> <member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2( 0, 0 )"> The mouse position relative to the previous position (position at the last frame). </member> <member name="speed" type="Vector2" setter="set_speed" getter="get_speed" default="Vector2( 0, 0 )"> The mouse speed in pixels per second. </member> - <member name="pressure" type="float" setter="set_pressure" getter="get_pressure"> - Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code]. - </member> - <member name="tilt" type="Vector2" setter="set_tilt" getter="get_tilt"> + <member name="tilt" type="Vector2" setter="set_tilt" getter="get_tilt" default="Vector2( 0, 0 )"> Represents the angles of tilt of the pen. Positive X-coordinate value indicates a tilt to the right. Positive Y-coordinate value indicates a tilt toward the user. Ranges from [code]-1.0[/code] to [code]1.0[/code] for both axes. </member> </members> diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml index 69dfe28ac4..bb72f2734e 100644 --- a/doc/classes/Plane.xml +++ b/doc/classes/Plane.xml @@ -116,6 +116,14 @@ Returns the intersection point of a segment from position [code]begin[/code] to position [code]end[/code] with this plane. If no intersection is found, [code]null[/code] is returned. </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="plane" type="Plane"> + </argument> + <description> + </description> + </method> <method name="is_point_over"> <return type="bool"> </return> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index ec7cf14571..772c2f5073 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -282,6 +282,9 @@ <member name="debug/gdscript/warnings/enable" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables specific GDScript warnings (see [code]debug/gdscript/warnings/*[/code] settings). If [code]false[/code], disables all GDScript warnings. </member> + <member name="debug/gdscript/warnings/exclude_addons" type="bool" setter="" getter="" default="true"> + If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings. + </member> <member name="debug/gdscript/warnings/function_conflicts_constant" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables warnings when a function is declared with the same name as a constant. </member> diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml index 9d163e926c..f5ee99d30c 100644 --- a/doc/classes/Quat.xml +++ b/doc/classes/Quat.xml @@ -94,6 +94,14 @@ Returns the inverse of the quaternion. </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="quat" type="Quat"> + </argument> + <description> + </description> + </method> <method name="is_normalized"> <return type="bool"> </return> diff --git a/doc/classes/RayCast.xml b/doc/classes/RayCast.xml index 19f62a57bd..5e17d6e7d7 100644 --- a/doc/classes/RayCast.xml +++ b/doc/classes/RayCast.xml @@ -11,6 +11,7 @@ RayCast calculates intersection every physics frame (see [Node]), and the result is cached so it can be used later until the next frame. If multiple queries are required between physics frames (or during the same frame), use [method force_raycast_update] after adjusting the raycast. </description> <tutorials> + <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link> </tutorials> <methods> <method name="add_exception"> diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml index 81d66ef496..c5ba5da24e 100644 --- a/doc/classes/RayCast2D.xml +++ b/doc/classes/RayCast2D.xml @@ -11,6 +11,7 @@ RayCast2D calculates intersection every physics frame (see [Node]), and the result is cached so it can be used later until the next frame. If multiple queries are required between physics frames (or during the same frame) use [method force_raycast_update] after adjusting the raycast. </description> <tutorials> + <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link> </tutorials> <methods> <method name="add_exception"> diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml index 9d6bfbf398..07fa7777fe 100644 --- a/doc/classes/Rect2.xml +++ b/doc/classes/Rect2.xml @@ -137,6 +137,14 @@ Returns [code]true[/code] if the [Rect2] overlaps with another. </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="rect" type="Rect2"> + </argument> + <description> + </description> + </method> <method name="merge"> <return type="Rect2"> </return> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index bd81a48ff5..b6e2303d2a 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -204,6 +204,7 @@ </argument> <description> If [code]true[/code], the application automatically accepts quitting. Enabled by default. + For mobile platforms, see [method set_quit_on_go_back]. </description> </method> <method name="set_group"> @@ -248,6 +249,7 @@ </argument> <description> If [code]true[/code], the application quits automatically on going back (e.g. on Android). Enabled by default. + To handle 'Go Back' button when this option is disabled, use [constant MainLoop.NOTIFICATION_WM_GO_BACK_REQUEST]. </description> </method> <method name="set_screen_stretch"> diff --git a/doc/classes/SoftBody.xml b/doc/classes/SoftBody.xml index 93f02c0e01..a51907b1bf 100644 --- a/doc/classes/SoftBody.xml +++ b/doc/classes/SoftBody.xml @@ -77,9 +77,6 @@ </method> </methods> <members> - <member name="ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="false"> - If [code]true[/code], the [SoftBody] will respond to [RayCast]s. - </member> <member name="areaAngular_stiffness" type="float" setter="set_areaAngular_stiffness" getter="get_areaAngular_stiffness" default="0.5"> </member> <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1"> @@ -103,6 +100,9 @@ </member> <member name="pressure_coefficient" type="float" setter="set_pressure_coefficient" getter="get_pressure_coefficient" default="0.0"> </member> + <member name="ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true"> + If [code]true[/code], the [SoftBody] will respond to [RayCast]s. + </member> <member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision" default="5"> Increasing this value will improve the resulting simulation, but can affect performance. Use with care. </member> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index e883341107..75fceac500 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -310,11 +310,11 @@ <argument index="3" name="from_column" type="int"> </argument> <description> - Perform a search inside the text. Search flags can be specified in the [code]SEARCH_*[/code] enum. - Returns an empty [code]PoolIntArray[/code] if no result was found. Otherwise, the result line and column can be accessed at indices specified in the [code]SEARCH_RESULT_*[/code] enum, e.g: + Perform a search inside the text. Search flags can be specified in the [enum SearchFlags] enum. + Returns an empty [code]PoolIntArray[/code] if no result was found. Otherwise, the result line and column can be accessed at indices specified in the [enum SearchResult] enum, e.g: [codeblock] var result = search(key, flags, line, column) - if result.size() > 0: + if result.size() > 0: # result found var res_line = result[TextEdit.SEARCH_RESULT_LINE] var res_column = result[TextEdit.SEARCH_RESULT_COLUMN] @@ -513,13 +513,13 @@ Search from end to beginning. </constant> <constant name="SEARCH_RESULT_COLUMN" value="0" enum="SearchResult"> - Used to access the result column from [member search]. + Used to access the result column from [method search]. </constant> <constant name="SEARCH_RESULT_LINE" value="1" enum="SearchResult"> - Used to access the result line from [member search]. + Used to access the result line from [method search]. </constant> <constant name="MENU_CUT" value="0" enum="MenuItems"> - Cuts (Copies and clears) the selected text. + Cuts (copies and clears) the selected text. </constant> <constant name="MENU_COPY" value="1" enum="MenuItems"> Copies the selected text. diff --git a/doc/classes/TouchScreenButton.xml b/doc/classes/TouchScreenButton.xml index fccfb4cd6d..3d18534a68 100644 --- a/doc/classes/TouchScreenButton.xml +++ b/doc/classes/TouchScreenButton.xml @@ -37,7 +37,7 @@ The button's shape. </member> <member name="shape_centered" type="bool" setter="set_shape_centered" getter="is_shape_centered" default="true"> - If [code]true[/code], the button's shape is centered. + If [code]true[/code], the button's shape is centered in the provided texture. If no texture is used, this property has no effect. </member> <member name="shape_visible" type="bool" setter="set_shape_visible" getter="is_shape_visible" default="true"> If [code]true[/code], the button's shape is visible. diff --git a/doc/classes/Transform.xml b/doc/classes/Transform.xml index 6ebc389ed7..034a1b2f5b 100644 --- a/doc/classes/Transform.xml +++ b/doc/classes/Transform.xml @@ -89,6 +89,14 @@ Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use affine_inverse for transforms with scaling). </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="transform" type="Transform"> + </argument> + <description> + </description> + </method> <method name="looking_at"> <return type="Transform"> </return> diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml index 580da080b3..89ccffc2e9 100644 --- a/doc/classes/Transform2D.xml +++ b/doc/classes/Transform2D.xml @@ -106,6 +106,14 @@ Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use affine_inverse for transforms with scaling). </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="transform" type="Transform2D"> + </argument> + <description> + </description> + </method> <method name="orthonormalized"> <return type="Transform2D"> </return> diff --git a/doc/classes/VScrollBar.xml b/doc/classes/VScrollBar.xml index 4c06195d5c..6240178b82 100644 --- a/doc/classes/VScrollBar.xml +++ b/doc/classes/VScrollBar.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VScrollBar" inherits="ScrollBar" category="Core" version="3.2"> <brief_description> - Vertical version of [ScrollBar], which goes from left (min) to right (max). + Vertical version of [ScrollBar], which goes from top (min) to bottom (max). </brief_description> <description> </description> diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml index 28c3bc8e85..9d55f5846f 100644 --- a/doc/classes/Variant.xml +++ b/doc/classes/Variant.xml @@ -17,21 +17,21 @@ - VisualScript tracks properties inside Variants as well, but it also uses static typing. The GUI interface enforces that properties have a particular type that doesn't change over time. - C# is statically typed, but uses the Mono [code]object[/code] type in place of Godot's Variant class when it needs to represent a dynamic value. [code]object[/code] is the Mono runtime's equivalent of the same concept. - The statically-typed language NativeScript C++ does not define a built-in Variant-like class. Godot's GDNative bindings provide their own godot::Variant class for users; Any point at which the C++ code starts interacting with the Godot runtime is a place where you might have to start wrapping data inside Variant objects. - The global [member @GDScript.typeof] function returns the enumerated value of the Variant type stored in the current variable. These correspond to [code]TYPE_*[/code] constants in the [@GlobalScope] docs. + The global [method @GDScript.typeof] function returns the enumerated value of the Variant type stored in the current variable. These correspond to [code]TYPE_*[/code] constants in the [@GlobalScope] docs. [codeblock] var foo = 2 match typeof(foo): - TYPE_NIL: - print("foo is null!") - TYPE_INTEGER: - print("foo is an integer!") - TYPE_OBJECT: - # Note that Objects are their own special category. - # To get the name of the underlying Object type, you need the `get_class()` method. - print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string. - # Note also that there is not yet any way to get a script's `class_name` string easily. - # To fetch that value, you need to dig deeply into a hidden ProjectSettings setting: an Array of Dictionaries called "_global_script_classes". - # Open your project.godot file to see it up close. + TYPE_NIL: + print("foo is null") + TYPE_INTEGER: + print("foo is an integer") + TYPE_OBJECT: + # Note that Objects are their own special category. + # To get the name of the underlying Object type, you need the `get_class()` method. + print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string. + # Note also that there is not yet any way to get a script's `class_name` string easily. + # To fetch that value, you need to dig deeply into a hidden ProjectSettings setting: an Array of Dictionaries called "_global_script_classes". + # Open your project.godot file to see it up close. [/codeblock] A Variant takes up only 20 bytes and can store almost any engine datatype inside of it. Variants are rarely used to hold information for long periods of time. Instead, they are used mainly for communication, editing, serialization and moving data around. Godot has specifically invested in making its Variant class as flexible as possible; so much so that it is used for a multitude of operations to facilitate communication between all of Godot's systems. diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 987ed9867b..8ae5caf68c 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -153,6 +153,14 @@ Returns the vector with all components rounded down. </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="v" type="Vector2"> + </argument> + <description> + </description> + </method> <method name="is_normalized"> <return type="bool"> </return> diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 05ce6c43ae..29c24709e2 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -129,6 +129,14 @@ Returns the inverse of the vector. This is the same as [code]Vector3( 1.0 / v.x, 1.0 / v.y, 1.0 / v.z )[/code]. </description> </method> + <method name="is_equal_approx"> + <return type="bool"> + </return> + <argument index="0" name="v" type="Vector3"> + </argument> + <description> + </description> + </method> <method name="is_normalized"> <return type="bool"> </return> diff --git a/doc/classes/VisualShaderNodeInput.xml b/doc/classes/VisualShaderNodeInput.xml index 302c8dff71..bfcd4c734c 100644 --- a/doc/classes/VisualShaderNodeInput.xml +++ b/doc/classes/VisualShaderNodeInput.xml @@ -7,6 +7,12 @@ <tutorials> </tutorials> <methods> + <method name="get_input_real_name" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> </methods> <members> <member name="default_input_values" type="Array" setter="_set_default_input_values" getter="_get_default_input_values" override="true" default="[ ]" /> diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index f712219a64..6bcda62e7f 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -2767,6 +2767,8 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p if (use_post_process) { next_buffer = storage->frame.current_rt->mip_maps[0].sizes[0].fbo; + } else if (storage->frame.current_rt->external.fbo != 0) { + next_buffer = storage->frame.current_rt->external.fbo; } else { // set next_buffer to front buffer so multisample blit can happen if needed next_buffer = storage->frame.current_rt->fbo; @@ -2795,9 +2797,15 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p // In GLES2 Android Blit is not available, so just copy color texture manually _copy_texture_to_buffer(storage->frame.current_rt->multisample_color, next_buffer); +#else + // TODO: any other platform not supported? this will fail.. maybe we should just call _copy_texture_to_buffer here as well? #endif } else if (use_post_process) { - _copy_texture_to_buffer(storage->frame.current_rt->color, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); + if (storage->frame.current_rt->external.fbo != 0) { + _copy_texture_to_buffer(storage->frame.current_rt->external.color, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); + } else { + _copy_texture_to_buffer(storage->frame.current_rt->color, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); + } } if (!use_post_process) { @@ -3220,14 +3228,12 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const } else { state.render_no_shadows = false; - if (storage->frame.current_rt->external.fbo != 0) { + if (storage->frame.current_rt->multisample_active) { + current_fb = storage->frame.current_rt->multisample_fbo; + } else if (storage->frame.current_rt->external.fbo != 0) { current_fb = storage->frame.current_rt->external.fbo; } else { - if (storage->frame.current_rt->multisample_active) { - current_fb = storage->frame.current_rt->multisample_fbo; - } else { - current_fb = storage->frame.current_rt->fbo; - } + current_fb = storage->frame.current_rt->fbo; } env = environment_owner.getornull(p_environment); diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index fb21c0c5a1..4dc1b74310 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -96,7 +96,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { if (p_mode_flags == READ) { WIN32_FIND_DATAW d; HANDLE f = FindFirstFileW(path.c_str(), &d); - if (f) { + if (f != INVALID_HANDLE_VALUE) { String fname = d.cFileName; if (fname != String()) { diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index b331a39535..acfdea28e2 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -1329,7 +1329,8 @@ EditorAudioBuses::EditorAudioBuses() { add_child(top_hb); file = memnew(Label); - file->set_text(String(TTR("Layout")) + ": " + "default_bus_layout.tres"); + String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout"); + file->set_text(String(TTR("Layout")) + ": " + layout_path.get_file()); file->set_clip_text(true); file->set_h_size_flags(SIZE_EXPAND_FILL); top_hb->add_child(file); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 4855d3f69d..1cafd1d1f4 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -820,7 +820,7 @@ void EditorData::save_edited_scene_state(EditorSelection *p_selection, EditorHis ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); EditedScene &es = edited_scene.write[current_edited_scene]; - es.selection = p_selection->get_selected_node_list(); + es.selection = p_selection->get_full_selected_node_list(); es.history_current = p_history->current; es.history_stored = p_history->history; es.editor_states = get_editor_states(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d42345d9a2..0e373a5deb 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -71,6 +71,7 @@ #include "editor/import/resource_importer_texture.h" #include "editor/import/resource_importer_texture_atlas.h" #include "editor/import/resource_importer_wav.h" +#include "editor/multi_node_edit.h" #include "editor/plugins/animation_blend_space_1d_editor.h" #include "editor/plugins/animation_blend_space_2d_editor.h" #include "editor/plugins/animation_blend_tree_editor_plugin.h" @@ -1065,7 +1066,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { img->crop_from_point(x, y, vp_size, vp_size); } else { int ratio = vp_size / preview_size; - int size = preview_size * (ratio / 2); + int size = preview_size * MAX(1, ratio / 2); x = (img->get_width() - size) / 2; y = (img->get_height() - size) / 2; @@ -1742,15 +1743,37 @@ void EditorNode::_edit_current() { } else { + Node *selected_node = NULL; + if (current_obj->is_class("ScriptEditorDebuggerInspectedObject")) { editable_warning = TTR("This is a remote object, so changes to it won't be kept.\nPlease read the documentation relevant to debugging to better understand this workflow."); capitalize = false; disable_folding = true; + } else if (current_obj->is_class("MultiNodeEdit")) { + Node *scene = get_edited_scene(); + if (scene) { + MultiNodeEdit *multi_node_edit = Object::cast_to<MultiNodeEdit>(current_obj); + int node_count = multi_node_edit->get_node_count(); + if (node_count > 0) { + List<Node *> multi_nodes; + for (int node_index = 0; node_index < node_count; ++node_index) { + Node *node = scene->get_node(multi_node_edit->get_node(node_index)); + if (node) { + multi_nodes.push_back(node); + } + } + if (!multi_nodes.empty()) { + // Pick the top-most node + multi_nodes.sort_custom<Node::Comparator>(); + selected_node = multi_nodes.front()->get(); + } + } + } } get_inspector()->edit(current_obj); node_dock->set_node(NULL); - scene_tree_dock->set_selected(NULL); + scene_tree_dock->set_selected(selected_node); inspector_dock->update(NULL); } diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp index 85e47594a8..0792d5c95f 100644 --- a/editor/multi_node_edit.cpp +++ b/editor/multi_node_edit.cpp @@ -34,12 +34,10 @@ #include "editor_node.h" bool MultiNodeEdit::_set(const StringName &p_name, const Variant &p_value) { - return _set_impl(p_name, p_value, ""); } bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, const String &p_field) { - Node *es = EditorNode::get_singleton()->get_edited_scene(); if (!es) return false; @@ -88,7 +86,6 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, } bool MultiNodeEdit::_get(const StringName &p_name, Variant &r_ret) const { - Node *es = EditorNode::get_singleton()->get_edited_scene(); if (!es) return false; @@ -117,7 +114,6 @@ bool MultiNodeEdit::_get(const StringName &p_name, Variant &r_ret) const { } void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const { - HashMap<String, PLData> usage; Node *es = EditorNode::get_singleton()->get_edited_scene(); @@ -171,17 +167,23 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const { } void MultiNodeEdit::clear_nodes() { - nodes.clear(); } void MultiNodeEdit::add_node(const NodePath &p_node) { - nodes.push_back(p_node); } -void MultiNodeEdit::set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field) { +int MultiNodeEdit::get_node_count() const { + return nodes.size(); +} +NodePath MultiNodeEdit::get_node(int p_index) const { + ERR_FAIL_INDEX_V(p_index, nodes.size(), NodePath()); + return nodes[p_index]; +} + +void MultiNodeEdit::set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field) { _set_impl(p_property, p_value, p_field); } diff --git a/editor/multi_node_edit.h b/editor/multi_node_edit.h index b9192b206a..33df4a2ca5 100644 --- a/editor/multi_node_edit.h +++ b/editor/multi_node_edit.h @@ -54,6 +54,9 @@ public: void clear_nodes(); void add_node(const NodePath &p_node); + int get_node_count() const; + NodePath get_node(int p_index) const; + void set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field); MultiNodeEdit(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index d84a67dba1..c9dde5d54d 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3811,6 +3811,7 @@ void CanvasItemEditor::_notification(int p_what) { grid_snap_button->set_icon(get_icon("SnapGrid", "EditorIcons")); snap_config_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons")); skeleton_menu->set_icon(get_icon("Bone", "EditorIcons")); + override_camera_button->set_icon(get_icon("Camera2D", "EditorIcons")); pan_button->set_icon(get_icon("ToolPan", "EditorIcons")); ruler_button->set_icon(get_icon("Ruler", "EditorIcons")); pivot_button->set_icon(get_icon("EditPivot", "EditorIcons")); @@ -3880,6 +3881,15 @@ void CanvasItemEditor::_notification(int p_what) { anchor_mode_button->set_icon(get_icon("Anchor", "EditorIcons")); } + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (!is_visible() && override_camera_button->is_pressed()) { + ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + override_camera_button->set_pressed(false); + } + } } void CanvasItemEditor::_selection_changed() { @@ -4221,6 +4231,15 @@ void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) { grid_snap_active = p_status; viewport->update(); } +void CanvasItemEditor::_button_override_camera(bool p_pressed) { + ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + + if (p_pressed) { + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_2D); + } else { + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + } +} void CanvasItemEditor::_button_tool_select(int p_index) { @@ -4318,6 +4337,17 @@ void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) { viewport->update(); } +void CanvasItemEditor::_update_override_camera_button(bool p_game_running) { + if (p_game_running) { + override_camera_button->set_disabled(false); + override_camera_button->set_tooltip(TTR("Game camera override\nOverrides game camera with editor viewport camera.")); + } else { + override_camera_button->set_disabled(true); + override_camera_button->set_pressed(false); + override_camera_button->set_tooltip(TTR("Game camera override\nNo game instance running.")); + } +} + void CanvasItemEditor::_popup_callback(int p_op) { last_option = MenuOption(p_op); @@ -4915,6 +4945,8 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method("_button_zoom_plus", &CanvasItemEditor::_button_zoom_plus); ClassDB::bind_method("_button_toggle_smart_snap", &CanvasItemEditor::_button_toggle_smart_snap); ClassDB::bind_method("_button_toggle_grid_snap", &CanvasItemEditor::_button_toggle_grid_snap); + ClassDB::bind_method(D_METHOD("_button_override_camera", "pressed"), &CanvasItemEditor::_button_override_camera); + ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button); ClassDB::bind_method("_button_toggle_anchor_mode", &CanvasItemEditor::_button_toggle_anchor_mode); ClassDB::bind_method("_update_scroll", &CanvasItemEditor::_update_scroll); ClassDB::bind_method("_update_scrollbars", &CanvasItemEditor::_update_scrollbars); @@ -5246,6 +5278,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { editor_selection->connect("selection_changed", this, "update"); editor_selection->connect("selection_changed", this, "_selection_changed"); + editor->call_deferred("connect", "play_pressed", this, "_update_override_camera_button", make_binds(true)); + editor->call_deferred("connect", "stop_pressed", this, "_update_override_camera_button", make_binds(false)); + hb = memnew(HBoxContainer); add_child(hb); hb->set_anchors_and_margins_preset(Control::PRESET_WIDE); @@ -5491,6 +5526,15 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { hb->add_child(memnew(VSeparator)); + override_camera_button = memnew(ToolButton); + hb->add_child(override_camera_button); + override_camera_button->connect("toggled", this, "_button_override_camera"); + override_camera_button->set_toggle_mode(true); + override_camera_button->set_disabled(true); + _update_override_camera_button(false); + + hb->add_child(memnew(VSeparator)); + view_menu = memnew(MenuButton); view_menu->set_text(TTR("View")); hb->add_child(view_menu); @@ -5574,7 +5618,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { 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_tooltip(TTR("Auto insert keys when objects are translated, rotated or 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); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 058f9a77d3..3fdf00d611 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -364,6 +364,7 @@ private: ToolButton *ungroup_button; MenuButton *skeleton_menu; + ToolButton *override_camera_button; MenuButton *view_menu; HBoxContainer *animation_hb; MenuButton *animation_menu; @@ -537,8 +538,11 @@ private: void _button_zoom_plus(); void _button_toggle_smart_snap(bool p_status); void _button_toggle_grid_snap(bool p_status); + void _button_override_camera(bool p_pressed); void _button_tool_select(int p_index); + void _update_override_camera_button(bool p_game_running); + HSplitContainer *palette_split; VSplitContainer *bottom_split; diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index eb39496106..c989613f02 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -901,6 +901,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { + emit_signal("clicked", this); + float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor(); switch (b->get_button_index()) { @@ -2763,6 +2765,7 @@ void SpatialEditorViewport::_preview_exited_scene() { preview_camera->disconnect("toggled", this, "_toggle_camera_preview"); preview_camera->set_pressed(false); _toggle_camera_preview(false); + preview_camera->connect("toggled", this, "_toggle_camera_preview"); view_menu->show(); } @@ -3101,6 +3104,7 @@ void SpatialEditorViewport::_bind_methods() { ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpatialEditorViewport::drop_data_fw); ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport"))); + ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport"))); } void SpatialEditorViewport::reset() { @@ -3599,6 +3603,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed vbox->add_child(preview_camera); preview_camera->set_h_size_flags(0); preview_camera->hide(); + preview_camera->connect("toggled", this, "_toggle_camera_preview"); previewing = NULL; gizmo_scale = 1.0; @@ -4373,6 +4378,19 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) { tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed); snap_enabled = pressed; } break; + + case MENU_TOOL_OVERRIDE_CAMERA: { + ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger(); + + if (pressed) { + using Override = ScriptEditorDebugger::CameraOverride; + + debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id)); + } else { + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + } + + } break; } } @@ -4400,6 +4418,35 @@ void SpatialEditor::_menu_gizmo_toggled(int p_option) { update_all_gizmos(); } +void SpatialEditor::_update_camera_override_button(bool p_game_running) { + Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]; + + if (p_game_running) { + button->set_disabled(false); + button->set_tooltip(TTR("Game camera override\nNo game instance running.")); + } else { + button->set_disabled(true); + button->set_pressed(false); + button->set_tooltip(TTR("Game camera override\nOverrides game camera with editor viewport camera.")); + } +} + +void SpatialEditor::_update_camera_override_viewport(Object *p_viewport) { + SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport); + + if (!current_viewport) + return; + + ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger(); + + camera_override_viewport_id = current_viewport->index; + if (debugger->get_camera_override() >= ScriptEditorDebugger::OVERRIDE_3D_1) { + using Override = ScriptEditorDebugger::CameraOverride; + + debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id)); + } +} + void SpatialEditor::_menu_item_pressed(int p_option) { switch (p_option) { @@ -5294,6 +5341,7 @@ void SpatialEditor::_notification(int p_what) { tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons")); tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons")); + tool_option_button[SpatialEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_icon("Camera", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons")); @@ -5309,6 +5357,9 @@ void SpatialEditor::_notification(int p_what) { get_tree()->connect("node_removed", this, "_node_removed"); EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", this, "_refresh_menu_icons"); editor_selection->connect("selection_changed", this, "_refresh_menu_icons"); + + editor->connect("stop_pressed", this, "_update_camera_override_button", make_binds(false)); + editor->connect("play_pressed", this, "_update_camera_override_button", make_binds(true)); } else if (p_what == NOTIFICATION_ENTER_TREE) { _register_all_gizmos(); @@ -5343,6 +5394,13 @@ void SpatialEditor::_notification(int p_what) { // Update grid color by rebuilding grid. _finish_grid(); _init_grid(); + } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) { + ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + + debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false); + } } } @@ -5487,6 +5545,8 @@ void SpatialEditor::_bind_methods() { ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo); ClassDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view); ClassDB::bind_method("_refresh_menu_icons", &SpatialEditor::_refresh_menu_icons); + ClassDB::bind_method("_update_camera_override_button", &SpatialEditor::_update_camera_override_button); + ClassDB::bind_method("_update_camera_override_viewport", &SpatialEditor::_update_camera_override_viewport); ADD_SIGNAL(MethodInfo("transform_key_request")); ADD_SIGNAL(MethodInfo("item_lock_status_changed")); @@ -5540,6 +5600,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { snap_key_enabled = false; tool_mode = TOOL_MODE_SELECT; + camera_override_viewport_id = 0; + hbc_menu = memnew(HBoxContainer); vbc->add_child(hbc_menu); @@ -5637,6 +5699,17 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(memnew(VSeparator)); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton); + hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true); + button_binds.write[0] = MENU_TOOL_OVERRIDE_CAMERA; + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", this, "_menu_item_toggled", button_binds); + _update_camera_override_button(false); + + hbc_menu->add_child(memnew(VSeparator)); + // Drag and drop support; preview_node = memnew(Spatial); preview_bounds = AABB(); @@ -5725,6 +5798,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { viewports[i] = memnew(SpatialEditorViewport(this, editor, i)); viewports[i]->connect("toggle_maximize_view", this, "_toggle_maximize_view"); + viewports[i]->connect("clicked", this, "_update_camera_override_viewport"); viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept); viewport_base->add_child(viewports[i]); } diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index fe91c33642..65e3c32ca8 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -494,6 +494,7 @@ public: TOOL_OPT_LOCAL_COORDS, TOOL_OPT_USE_SNAP, + TOOL_OPT_OVERRIDE_CAMERA, TOOL_OPT_MAX }; @@ -559,6 +560,7 @@ private: MENU_TOOL_LIST_SELECT, MENU_TOOL_LOCAL_COORDS, MENU_TOOL_USE_SNAP, + MENU_TOOL_OVERRIDE_CAMERA, MENU_TRANSFORM_CONFIGURE_SNAP, MENU_TRANSFORM_DIALOG, MENU_VIEW_USE_1_VIEWPORT, @@ -585,9 +587,6 @@ private: PopupMenu *gizmos_menu; MenuButton *view_menu; - ToolButton *lock_button; - ToolButton *unlock_button; - AcceptDialog *accept; ConfirmationDialog *snap_dialog; @@ -615,13 +614,16 @@ private: void _menu_item_pressed(int p_option); void _menu_item_toggled(bool pressed, int p_option); void _menu_gizmo_toggled(int p_option); + void _update_camera_override_button(bool p_game_running); + void _update_camera_override_viewport(Object *p_viewport); HBoxContainer *hbc_menu; void _generate_selection_box(); UndoRedo *undo_redo; - void _instance_scene(); + int camera_override_viewport_id; + void _init_indicators(); void _update_gizmos_menu(); void _update_gizmos_menu_theme(); @@ -716,7 +718,7 @@ public: void set_can_preview(Camera *p_preview); SpatialEditorViewport *get_editor_viewport(int p_idx) { - ERR_FAIL_INDEX_V(p_idx, 4, NULL); + ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), NULL); return viewports[p_idx]; } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 90eb3045df..1a74779fb5 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -2462,7 +2462,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Darken", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), VisualShaderNodeColorOp::OP_DARKEN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Difference", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Difference operator."), VisualShaderNodeColorOp::OP_DIFFERENCE, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Dodge", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Dodge operator."), VisualShaderNodeColorOp::OP_DODGE, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("HardLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("HardLight operator"), VisualShaderNodeColorOp::OP_HARD_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("HardLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("HardLight operator."), VisualShaderNodeColorOp::OP_HARD_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Lighten", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Lighten operator."), VisualShaderNodeColorOp::OP_LIGHTEN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Overlay", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Overlay operator."), VisualShaderNodeColorOp::OP_OVERLAY, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Screen", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), VisualShaderNodeColorOp::OP_SCREEN, VisualShaderNode::PORT_TYPE_VECTOR)); @@ -2780,7 +2780,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside."))); add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants."))); + add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants."))); add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 06acdcd4e2..afbd8832f2 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -33,6 +33,8 @@ #include "core/io/marshalls.h" #include "core/project_settings.h" #include "core/ustring.h" +#include "editor/plugins/canvas_item_editor_plugin.h" +#include "editor/plugins/spatial_editor_plugin.h" #include "editor_network_profiler.h" #include "editor_node.h" #include "editor_profiler.h" @@ -1232,6 +1234,42 @@ void ScriptEditorDebugger::_notification(int p_what) { } } } + + if (camera_override == OVERRIDE_2D) { + CanvasItemEditor *editor = CanvasItemEditor::get_singleton(); + + Dictionary state = editor->get_state(); + float zoom = state["zoom"]; + Point2 offset = state["ofs"]; + Transform2D transform; + + transform.scale_basis(Size2(zoom, zoom)); + transform.elements[2] = -offset * zoom; + + Array msg; + msg.push_back("override_camera_2D:transform"); + msg.push_back(transform); + ppeer->put_var(msg); + + } else if (camera_override >= OVERRIDE_3D_1) { + int viewport_idx = camera_override - OVERRIDE_3D_1; + SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(viewport_idx); + Camera *const cam = viewport->get_camera(); + + Array msg; + msg.push_back("override_camera_3D:transform"); + msg.push_back(cam->get_camera_transform()); + if (cam->get_projection() == Camera::PROJECTION_ORTHOGONAL) { + msg.push_back(false); + msg.push_back(cam->get_size()); + } else { + msg.push_back(true); + msg.push_back(cam->get_fov()); + } + msg.push_back(cam->get_znear()); + msg.push_back(cam->get_zfar()); + ppeer->put_var(msg); + } } if (error_count != last_error_count || warning_count != last_warning_count) { @@ -1446,6 +1484,7 @@ void ScriptEditorDebugger::start() { set_process(true); breaked = false; + camera_override = OVERRIDE_NONE; } void ScriptEditorDebugger::pause() { @@ -1890,6 +1929,45 @@ void ScriptEditorDebugger::live_debug_reparent_node(const NodePath &p_at, const } } +ScriptEditorDebugger::CameraOverride ScriptEditorDebugger::get_camera_override() const { + return camera_override; +} + +void ScriptEditorDebugger::set_camera_override(CameraOverride p_override) { + + if (p_override == OVERRIDE_2D && camera_override != OVERRIDE_2D) { + if (connection.is_valid()) { + Array msg; + msg.push_back("override_camera_2D:set"); + msg.push_back(true); + ppeer->put_var(msg); + } + } else if (p_override != OVERRIDE_2D && camera_override == OVERRIDE_2D) { + if (connection.is_valid()) { + Array msg; + msg.push_back("override_camera_2D:set"); + msg.push_back(false); + ppeer->put_var(msg); + } + } else if (p_override >= OVERRIDE_3D_1 && camera_override < OVERRIDE_3D_1) { + if (connection.is_valid()) { + Array msg; + msg.push_back("override_camera_3D:set"); + msg.push_back(true); + ppeer->put_var(msg); + } + } else if (p_override < OVERRIDE_3D_1 && camera_override >= OVERRIDE_3D_1) { + if (connection.is_valid()) { + Array msg; + msg.push_back("override_camera_3D:set"); + msg.push_back(false); + ppeer->put_var(msg); + } + } + + camera_override = p_override; +} + void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool p_enabled) { if (connection.is_valid()) { diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index cc284476c0..14b024d066 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -35,6 +35,7 @@ #include "core/io/tcp_server.h" #include "editor/editor_inspector.h" #include "editor/property_editor.h" +#include "scene/3d/camera.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" @@ -58,6 +59,17 @@ class ScriptEditorDebugger : public Control { GDCLASS(ScriptEditorDebugger, Control); +public: + enum CameraOverride { + OVERRIDE_NONE, + OVERRIDE_2D, + OVERRIDE_3D_1, // 3D Viewport 1 + OVERRIDE_3D_2, // 3D Viewport 2 + OVERRIDE_3D_3, // 3D Viewport 3 + OVERRIDE_3D_4 // 3D Viewport 4 + }; + +private: enum MessageType { MESSAGE_ERROR, MESSAGE_WARNING, @@ -165,6 +177,8 @@ class ScriptEditorDebugger : public Control { bool live_debug; + CameraOverride camera_override; + void _performance_draw(); void _performance_select(); void _stack_dump_frame_selected(); @@ -250,6 +264,9 @@ public: void live_debug_duplicate_node(const NodePath &p_at, const String &p_new_name); void live_debug_reparent_node(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos); + CameraOverride get_camera_override() const; + void set_camera_override(CameraOverride p_override); + void set_breakpoint(const String &p_path, int p_line, bool p_enabled); void update_live_edit_root(); diff --git a/main/main.cpp b/main/main.cpp index 28ab80bec2..3911ae77dc 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -44,7 +44,6 @@ #include "core/project_settings.h" #include "core/register_core_types.h" #include "core/script_debugger_local.h" -#include "core/script_debugger_remote.h" #include "core/script_language.h" #include "core/translation.h" #include "core/version.h" @@ -59,6 +58,7 @@ #include "main/tests/test_main.h" #include "modules/register_module_types.h" #include "platform/register_platform_apis.h" +#include "scene/debugger/script_debugger_remote.h" #include "scene/main/scene_tree.h" #include "scene/main/viewport.h" #include "scene/register_scene_types.h" @@ -1581,6 +1581,12 @@ bool Main::start() { if (!project_manager && !editor) { // game if (game_path != "" || script != "") { + if (script_debugger && script_debugger->is_remote()) { + ScriptDebuggerRemote *remote_debugger = static_cast<ScriptDebuggerRemote *>(script_debugger); + + remote_debugger->set_scene_tree(sml); + } + //autoload List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index edb296437b..b90fab8221 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -2141,6 +2141,7 @@ GDScriptLanguage::GDScriptLanguage() { #ifdef DEBUG_ENABLED GLOBAL_DEF("debug/gdscript/warnings/enable", true); GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false); + GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true); GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false); for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 9d229adb2a..74b9440b3a 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -8373,6 +8373,9 @@ void GDScriptParser::_add_warning(int p_code, int p_line, const String &p_symbol } void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> &p_symbols) { + if (GLOBAL_GET("debug/gdscript/warnings/exclude_addons").booleanize() && base_path.begins_with("res://addons/")) { + return; + } if (tokenizer->is_ignoring_warnings() || !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize()) { return; } diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index fefad3584b..557699cf37 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -1144,11 +1144,21 @@ public: return valid; } + if (!_valid_resource_name(p_preset->get("package/short_name"))) { + valid = false; + err += TTR("Invalid package short name.") + "\n"; + } + if (!_valid_resource_name(p_preset->get("package/unique_name"))) { valid = false; err += TTR("Invalid package unique name.") + "\n"; } + if (!_valid_resource_name(p_preset->get("package/publisher_display_name"))) { + valid = false; + err += TTR("Invalid package publisher display name.") + "\n"; + } + if (!_valid_guid(p_preset->get("identity/product_guid"))) { valid = false; err += TTR("Invalid product GUID.") + "\n"; diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index cf68528388..9a1a759e72 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -325,12 +325,8 @@ void TouchScreenButton::_release(bool p_exiting_tree) { } Rect2 TouchScreenButton::_edit_get_rect() const { - if (texture.is_null()) { - if (shape.is_valid()) - return shape->get_rect(); - else - return CanvasItem::_edit_get_rect(); - } + if (texture.is_null()) + return CanvasItem::_edit_get_rect(); return Rect2(Size2(), texture->get_size()); } diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 241eb7d1ca..06b5613eb8 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -331,6 +331,13 @@ void Particles::_notification(int p_what) { set_process_internal(false); } } + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + // make sure particles are updated before rendering occurs if they were active before + if (is_visible_in_tree() && !VS::get_singleton()->particles_is_inactive(particles)) { + VS::get_singleton()->particles_request_process(particles); + } + } } void Particles::_bind_methods() { diff --git a/scene/SCsub b/scene/SCsub index d8839ce3a8..1c5b87b87a 100644 --- a/scene/SCsub +++ b/scene/SCsub @@ -30,6 +30,7 @@ SConscript('2d/SCsub') SConscript('animation/SCsub') SConscript('audio/SCsub') SConscript('resources/SCsub') +SConscript('debugger/SCsub') # Build it all as a library diff --git a/scene/debugger/SCsub b/scene/debugger/SCsub new file mode 100644 index 0000000000..b01e2fd54d --- /dev/null +++ b/scene/debugger/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import('env') + +env.add_source_files(env.scene_sources, "*.cpp") diff --git a/core/script_debugger_remote.cpp b/scene/debugger/script_debugger_remote.cpp index 65ef2a0978..c3c6a088cb 100644 --- a/core/script_debugger_remote.cpp +++ b/scene/debugger/script_debugger_remote.cpp @@ -37,7 +37,10 @@ #include "core/os/os.h" #include "core/project_settings.h" #include "scene/main/node.h" +#include "scene/main/scene_tree.h" +#include "scene/main/viewport.h" #include "scene/resources/packed_scene.h" +#include "servers/visual_server.h" void ScriptDebuggerRemote::_send_video_memory() { @@ -150,7 +153,10 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue, if (mouse_mode != Input::MOUSE_MODE_VISIBLE) Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + uint64_t loop_begin_usec = 0; + uint64_t loop_time_sec = 0; while (true) { + loop_begin_usec = OS::get_singleton()->get_ticks_usec(); _get_output(); @@ -279,9 +285,10 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue, break; } else if (command == "request_scene_tree") { - if (request_scene_tree) - request_scene_tree(request_scene_tree_ud); - +#ifdef DEBUG_ENABLED + if (scene_tree) + scene_tree->_debugger_request_tree(); +#endif } else if (command == "request_video_mem") { _send_video_memory(); @@ -293,6 +300,40 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue, _set_object_property(cmd[1], cmd[2], cmd[3]); + } else if (command == "override_camera_2D:set") { + bool enforce = cmd[1]; + + if (scene_tree) { + scene_tree->get_root()->enable_canvas_transform_override(enforce); + } + } else if (command == "override_camera_2D:transform") { + Transform2D transform = cmd[1]; + + if (scene_tree) { + scene_tree->get_root()->set_canvas_transform_override(transform); + } + } else if (command == "override_camera_3D:set") { + bool enable = cmd[1]; + + if (scene_tree) { + scene_tree->get_root()->enable_camera_override(enable); + } + } else if (command == "override_camera_3D:transform") { + Transform transform = cmd[1]; + bool is_perspective = cmd[2]; + float size_or_fov = cmd[3]; + float near = cmd[4]; + float far = cmd[5]; + + if (scene_tree) { + if (is_perspective) { + scene_tree->get_root()->set_camera_override_perspective(size_or_fov, near, far); + } else { + scene_tree->get_root()->set_camera_override_orthogonal(size_or_fov, near, far); + } + scene_tree->get_root()->set_camera_override_transform(transform); + } + } else if (command == "reload_scripts") { reload_all_scripts = true; } else if (command == "breakpoint") { @@ -315,6 +356,13 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue, OS::get_singleton()->delay_usec(10000); OS::get_singleton()->process_and_drop_events(); } + + // This is for the camera override to stay live even when the game is paused from the editor + loop_time_sec = (OS::get_singleton()->get_ticks_usec() - loop_begin_usec) / 1000000.0f; + VisualServer::get_singleton()->sync(); + if (VisualServer::get_singleton()->has_changed()) { + VisualServer::get_singleton()->draw(true, loop_time_sec * Engine::get_singleton()->get_time_scale()); + } } packet_peer_stream->put_var("debug_exit"); @@ -446,93 +494,75 @@ void ScriptDebuggerRemote::_err_handler(void *ud, const char *p_func, const char bool ScriptDebuggerRemote::_parse_live_edit(const Array &p_command) { +#ifdef DEBUG_ENABLED + String cmdstr = p_command[0]; - if (!live_edit_funcs || !cmdstr.begins_with("live_")) + if (!scene_tree || !cmdstr.begins_with("live_")) return false; - //print_line(Variant(cmd).get_construct_string()); if (cmdstr == "live_set_root") { - if (!live_edit_funcs->root_func) - return true; - //print_line("root: "+Variant(cmd).get_construct_string()); - live_edit_funcs->root_func(live_edit_funcs->udata, p_command[1], p_command[2]); + scene_tree->_live_edit_root_func(p_command[1], p_command[2]); } else if (cmdstr == "live_node_path") { - if (!live_edit_funcs->node_path_func) - return true; - //print_line("path: "+Variant(cmd).get_construct_string()); - - live_edit_funcs->node_path_func(live_edit_funcs->udata, p_command[1], p_command[2]); + scene_tree->_live_edit_node_path_func(p_command[1], p_command[2]); } else if (cmdstr == "live_res_path") { - if (!live_edit_funcs->res_path_func) - return true; - live_edit_funcs->res_path_func(live_edit_funcs->udata, p_command[1], p_command[2]); + scene_tree->_live_edit_res_path_func(p_command[1], p_command[2]); } else if (cmdstr == "live_node_prop_res") { - if (!live_edit_funcs->node_set_res_func) - return true; - live_edit_funcs->node_set_res_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); + scene_tree->_live_edit_node_set_res_func(p_command[1], p_command[2], p_command[3]); } else if (cmdstr == "live_node_prop") { - if (!live_edit_funcs->node_set_func) - return true; - live_edit_funcs->node_set_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); + scene_tree->_live_edit_node_set_func(p_command[1], p_command[2], p_command[3]); } else if (cmdstr == "live_res_prop_res") { - if (!live_edit_funcs->res_set_res_func) - return true; - live_edit_funcs->res_set_res_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); + scene_tree->_live_edit_res_set_res_func(p_command[1], p_command[2], p_command[3]); } else if (cmdstr == "live_res_prop") { - if (!live_edit_funcs->res_set_func) - return true; - live_edit_funcs->res_set_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); + scene_tree->_live_edit_res_set_func(p_command[1], p_command[2], p_command[3]); } else if (cmdstr == "live_node_call") { - if (!live_edit_funcs->node_call_func) - return true; - live_edit_funcs->node_call_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]); + scene_tree->_live_edit_node_call_func(p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]); } else if (cmdstr == "live_res_call") { - if (!live_edit_funcs->res_call_func) - return true; - live_edit_funcs->res_call_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]); + scene_tree->_live_edit_res_call_func(p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]); } else if (cmdstr == "live_create_node") { - live_edit_funcs->tree_create_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); + scene_tree->_live_edit_create_node_func(p_command[1], p_command[2], p_command[3]); } else if (cmdstr == "live_instance_node") { - live_edit_funcs->tree_instance_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); + scene_tree->_live_edit_instance_node_func(p_command[1], p_command[2], p_command[3]); } else if (cmdstr == "live_remove_node") { - live_edit_funcs->tree_remove_node_func(live_edit_funcs->udata, p_command[1]); + scene_tree->_live_edit_remove_node_func(p_command[1]); } else if (cmdstr == "live_remove_and_keep_node") { - live_edit_funcs->tree_remove_and_keep_node_func(live_edit_funcs->udata, p_command[1], p_command[2]); + scene_tree->_live_edit_remove_and_keep_node_func(p_command[1], p_command[2]); + } else if (cmdstr == "live_restore_node") { - live_edit_funcs->tree_restore_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); + scene_tree->_live_edit_restore_node_func(p_command[1], p_command[2], p_command[3]); } else if (cmdstr == "live_duplicate_node") { - live_edit_funcs->tree_duplicate_node_func(live_edit_funcs->udata, p_command[1], p_command[2]); + scene_tree->_live_edit_duplicate_node_func(p_command[1], p_command[2]); + } else if (cmdstr == "live_reparent_node") { - live_edit_funcs->tree_reparent_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4]); + scene_tree->_live_edit_reparent_node_func(p_command[1], p_command[2], p_command[3], p_command[4]); } else { @@ -540,6 +570,10 @@ bool ScriptDebuggerRemote::_parse_live_edit(const Array &p_command) { } return true; +#else + + return false; +#endif } void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { @@ -732,8 +766,10 @@ void ScriptDebuggerRemote::_poll_events() { debug(get_break_language()); } else if (command == "request_scene_tree") { - if (request_scene_tree) - request_scene_tree(request_scene_tree_ud); +#ifdef DEBUG_ENABLED + if (scene_tree) + scene_tree->_debugger_request_tree(); +#endif } else if (command == "request_video_mem") { _send_video_memory(); @@ -777,6 +813,40 @@ void ScriptDebuggerRemote::_poll_events() { multiplayer->profiling_end(); profiling_network = false; + } else if (command == "override_camera_2D:set") { + bool enforce = cmd[1]; + + if (scene_tree) { + scene_tree->get_root()->enable_canvas_transform_override(enforce); + } + } else if (command == "override_camera_2D:transform") { + Transform2D transform = cmd[1]; + + if (scene_tree) { + scene_tree->get_root()->set_canvas_transform_override(transform); + } + } else if (command == "override_camera_3D:set") { + bool enable = cmd[1]; + + if (scene_tree) { + scene_tree->get_root()->enable_camera_override(enable); + } + } else if (command == "override_camera_3D:transform") { + Transform transform = cmd[1]; + bool is_perspective = cmd[2]; + float size_or_fov = cmd[3]; + float near = cmd[4]; + float far = cmd[5]; + + if (scene_tree) { + if (is_perspective) { + scene_tree->get_root()->set_camera_override_perspective(size_or_fov, near, far); + } else { + scene_tree->get_root()->set_camera_override_orthogonal(size_or_fov, near, far); + } + scene_tree->get_root()->set_camera_override_transform(transform); + } + } else if (command == "reload_scripts") { reload_all_scripts = true; } else if (command == "breakpoint") { @@ -1106,17 +1176,6 @@ void ScriptDebuggerRemote::request_quit() { requested_quit = true; } -void ScriptDebuggerRemote::set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) { - - request_scene_tree = p_func; - request_scene_tree_ud = p_udata; -} - -void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) { - - live_edit_funcs = p_funcs; -} - void ScriptDebuggerRemote::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { multiplayer = p_multiplayer; } @@ -1195,8 +1254,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() : msec_count(0), locking(false), poll_every(0), - request_scene_tree(NULL), - live_edit_funcs(NULL) { + scene_tree(NULL) { packet_peer_stream->set_stream_peer(tcp_client); packet_peer_stream->set_output_buffer_max_size(1024 * 1024 * 8); //8mb should be way more than enough diff --git a/core/script_debugger_remote.h b/scene/debugger/script_debugger_remote.h index b6dd925181..13ad7ddbe3 100644 --- a/core/script_debugger_remote.h +++ b/scene/debugger/script_debugger_remote.h @@ -37,6 +37,8 @@ #include "core/os/os.h" #include "core/script_language.h" +class SceneTree; + class ScriptDebuggerRemote : public ScriptDebugger { struct Message { @@ -116,16 +118,14 @@ class ScriptDebuggerRemote : public ScriptDebugger { void _poll_events(); uint32_t poll_every; - bool _parse_live_edit(const Array &p_command); + SceneTree *scene_tree; - RequestSceneTreeMessageFunc request_scene_tree; - void *request_scene_tree_ud; + bool _parse_live_edit(const Array &p_command); void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value); void _send_object_id(ObjectID p_id); void _send_video_memory(); - LiveEditFuncs *live_edit_funcs; Ref<MultiplayerAPI> multiplayer; @@ -176,8 +176,6 @@ public: virtual void send_message(const String &p_message, const Array &p_args); virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info); - virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata); - virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs); virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer); virtual bool is_profiling() const; @@ -189,6 +187,8 @@ public: virtual void set_skip_breakpoints(bool p_skip_breakpoints); + void set_scene_tree(SceneTree *p_scene_tree) { scene_tree = p_scene_tree; }; + ScriptDebuggerRemote(); ~ScriptDebuggerRemote(); }; diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 6b3e89af6c..ca4c255855 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -174,17 +174,17 @@ void Button::_notification(int p_what) { _size.width -= get_constant("hseparation") + icon_ofs_region; if (!clip_text) _size.width -= get_font("font")->get_string_size(xl_text).width; - float icon_width = icon->get_width() * _size.height / icon->get_height(); + float icon_width = _icon->get_width() * _size.height / _icon->get_height(); float icon_height = _size.height; if (icon_width > _size.width) { icon_width = _size.width; - icon_height = icon->get_height() * icon_width / icon->get_width(); + icon_height = _icon->get_height() * icon_width / _icon->get_width(); } icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, (_size.height - icon_height) / 2), Size2(icon_width, icon_height)); } else { - icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, Math::floor((valign - _icon->get_height()) / 2.0)), icon->get_size()); + icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, Math::floor((valign - _icon->get_height()) / 2.0)), _icon->get_size()); } } @@ -221,7 +221,7 @@ void Button::_notification(int p_what) { font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1); if (!_icon.is_null() && icon_region.size.width > 0) { - draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), icon->get_size()), color_icon); + draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), _icon->get_size()), color_icon); } } break; } diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 9f853cf0c8..ba57be1686 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -101,26 +101,26 @@ void Slider::_gui_input(Ref<InputEvent> p_event) { if (!mm.is_valid() && !mb.is_valid()) { - if (p_event->is_action("ui_left") && p_event->is_pressed()) { + if (p_event->is_action_pressed("ui_left", true)) { if (orientation != HORIZONTAL) return; set_value(get_value() - (custom_step >= 0 ? custom_step : get_step())); accept_event(); - } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { + } else if (p_event->is_action_pressed("ui_right", true)) { if (orientation != HORIZONTAL) return; set_value(get_value() + (custom_step >= 0 ? custom_step : get_step())); accept_event(); - } else if (p_event->is_action("ui_up") && p_event->is_pressed()) { + } else if (p_event->is_action_pressed("ui_up", true)) { if (orientation != VERTICAL) return; set_value(get_value() + (custom_step >= 0 ? custom_step : get_step())); accept_event(); - } else if (p_event->is_action("ui_down") && p_event->is_pressed()) { + } else if (p_event->is_action_pressed("ui_down", true)) { if (orientation != VERTICAL) return; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c818633f48..8ddc31745e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -4585,7 +4585,7 @@ void TextEdit::_scroll_moved(double p_to_val) { int v_scroll_i = floor(get_v_scroll()); int sc = 0; int n_line; - for (n_line = 0; n_line < text.size() - 1; n_line++) { + for (n_line = 0; n_line < text.size(); n_line++) { if (!is_line_hidden(n_line)) { sc++; sc += times_line_wraps(n_line); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 38ad6886b1..5653049060 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -40,6 +40,7 @@ #include "core/project_settings.h" #include "main/input_default.h" #include "node.h" +#include "scene/debugger/script_debugger_remote.h" #include "scene/resources/dynamic_font.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" @@ -1094,27 +1095,6 @@ void SceneTree::get_nodes_in_group(const StringName &p_group, List<Node *> *p_li } } -static void _fill_array(Node *p_node, Array &array, int p_level) { - - array.push_back(p_node->get_child_count()); - array.push_back(p_node->get_name()); - array.push_back(p_node->get_class()); - array.push_back(p_node->get_instance_id()); - for (int i = 0; i < p_node->get_child_count(); i++) { - - _fill_array(p_node->get_child(i), array, p_level + 1); - } -} - -void SceneTree::_debugger_request_tree(void *self) { - - SceneTree *sml = (SceneTree *)self; - - Array arr; - _fill_array(sml->root, arr, 0); - ScriptDebugger::get_singleton()->send_message("scene_tree", arr); -} - void SceneTree::_flush_delete_queue() { _THREAD_SAFE_METHOD_ @@ -1337,6 +1317,25 @@ void SceneTree::add_current_scene(Node *p_current) { } #ifdef DEBUG_ENABLED +static void _fill_array(Node *p_node, Array &array, int p_level) { + + array.push_back(p_node->get_child_count()); + array.push_back(p_node->get_name()); + array.push_back(p_node->get_class()); + array.push_back(p_node->get_instance_id()); + for (int i = 0; i < p_node->get_child_count(); i++) { + + _fill_array(p_node->get_child(i), array, p_level + 1); + } +} + +void SceneTree::_debugger_request_tree() { + + Array arr; + _fill_array(root, arr, 0); + ScriptDebugger::get_singleton()->send_message("scene_tree", arr); +} + void SceneTree::_live_edit_node_path_func(const NodePath &p_path, int p_id) { live_edit_node_path_cache[p_id] = p_path; @@ -2117,7 +2116,11 @@ SceneTree::SceneTree() { _update_root_rect(); if (ScriptDebugger::get_singleton()) { - ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree, this); + if (ScriptDebugger::get_singleton()->is_remote()) { + ScriptDebuggerRemote *remote_debugger = static_cast<ScriptDebuggerRemote *>(ScriptDebugger::get_singleton()); + + remote_debugger->set_scene_tree(this); + } ScriptDebugger::get_singleton()->set_multiplayer(multiplayer); } @@ -2129,29 +2132,6 @@ SceneTree::SceneTree() { #ifdef DEBUG_ENABLED - live_edit_funcs.udata = this; - live_edit_funcs.node_path_func = _live_edit_node_path_funcs; - live_edit_funcs.res_path_func = _live_edit_res_path_funcs; - live_edit_funcs.node_set_func = _live_edit_node_set_funcs; - live_edit_funcs.node_set_res_func = _live_edit_node_set_res_funcs; - live_edit_funcs.node_call_func = _live_edit_node_call_funcs; - live_edit_funcs.res_set_func = _live_edit_res_set_funcs; - live_edit_funcs.res_set_res_func = _live_edit_res_set_res_funcs; - live_edit_funcs.res_call_func = _live_edit_res_call_funcs; - live_edit_funcs.root_func = _live_edit_root_funcs; - - live_edit_funcs.tree_create_node_func = _live_edit_create_node_funcs; - live_edit_funcs.tree_instance_node_func = _live_edit_instance_node_funcs; - live_edit_funcs.tree_remove_node_func = _live_edit_remove_node_funcs; - live_edit_funcs.tree_remove_and_keep_node_func = _live_edit_remove_and_keep_node_funcs; - live_edit_funcs.tree_restore_node_func = _live_edit_restore_node_funcs; - live_edit_funcs.tree_duplicate_node_func = _live_edit_duplicate_node_funcs; - live_edit_funcs.tree_reparent_node_func = _live_edit_reparent_node_funcs; - - if (ScriptDebugger::get_singleton()) { - ScriptDebugger::get_singleton()->set_live_edit_funcs(&live_edit_funcs); - } - live_edit_root = NodePath("/root"); #endif diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index ef847ebb5b..2cf6a117e7 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -211,7 +211,6 @@ private: Variant _call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error); Variant _call_group(const Variant **p_args, int p_argcount, Variant::CallError &r_error); - static void _debugger_request_tree(void *self); void _flush_delete_queue(); //optimization friend class CanvasItem; @@ -220,6 +219,7 @@ private: SelfList<Node>::List xform_change_list; + friend class ScriptDebuggerRemote; #ifdef DEBUG_ENABLED Map<int, NodePath> live_edit_node_path_cache; @@ -231,7 +231,7 @@ private: Map<String, Set<Node *> > live_scene_edit_cache; Map<Node *, Map<ObjectID, Node *> > live_edit_remove_list; - ScriptDebugger::LiveEditFuncs live_edit_funcs; + void _debugger_request_tree(); void _live_edit_node_path_func(const NodePath &p_path, int p_id); void _live_edit_res_path_func(const String &p_path, int p_id); @@ -252,25 +252,6 @@ private: void _live_edit_duplicate_node_func(const NodePath &p_at, const String &p_new_name); void _live_edit_reparent_node_func(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos); - static void _live_edit_node_path_funcs(void *self, const NodePath &p_path, int p_id) { reinterpret_cast<SceneTree *>(self)->_live_edit_node_path_func(p_path, p_id); } - static void _live_edit_res_path_funcs(void *self, const String &p_path, int p_id) { reinterpret_cast<SceneTree *>(self)->_live_edit_res_path_func(p_path, p_id); } - - static void _live_edit_node_set_funcs(void *self, int p_id, const StringName &p_prop, const Variant &p_value) { reinterpret_cast<SceneTree *>(self)->_live_edit_node_set_func(p_id, p_prop, p_value); } - static void _live_edit_node_set_res_funcs(void *self, int p_id, const StringName &p_prop, const String &p_value) { reinterpret_cast<SceneTree *>(self)->_live_edit_node_set_res_func(p_id, p_prop, p_value); } - static void _live_edit_node_call_funcs(void *self, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { reinterpret_cast<SceneTree *>(self)->_live_edit_node_call_func(p_id, p_method, VARIANT_ARG_PASS); } - static void _live_edit_res_set_funcs(void *self, int p_id, const StringName &p_prop, const Variant &p_value) { reinterpret_cast<SceneTree *>(self)->_live_edit_res_set_func(p_id, p_prop, p_value); } - static void _live_edit_res_set_res_funcs(void *self, int p_id, const StringName &p_prop, const String &p_value) { reinterpret_cast<SceneTree *>(self)->_live_edit_res_set_res_func(p_id, p_prop, p_value); } - static void _live_edit_res_call_funcs(void *self, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { reinterpret_cast<SceneTree *>(self)->_live_edit_res_call_func(p_id, p_method, VARIANT_ARG_PASS); } - static void _live_edit_root_funcs(void *self, const NodePath &p_scene_path, const String &p_scene_from) { reinterpret_cast<SceneTree *>(self)->_live_edit_root_func(p_scene_path, p_scene_from); } - - static void _live_edit_create_node_funcs(void *self, const NodePath &p_parent, const String &p_type, const String &p_name) { reinterpret_cast<SceneTree *>(self)->_live_edit_create_node_func(p_parent, p_type, p_name); } - static void _live_edit_instance_node_funcs(void *self, const NodePath &p_parent, const String &p_path, const String &p_name) { reinterpret_cast<SceneTree *>(self)->_live_edit_instance_node_func(p_parent, p_path, p_name); } - static void _live_edit_remove_node_funcs(void *self, const NodePath &p_at) { reinterpret_cast<SceneTree *>(self)->_live_edit_remove_node_func(p_at); } - static void _live_edit_remove_and_keep_node_funcs(void *self, const NodePath &p_at, ObjectID p_keep_id) { reinterpret_cast<SceneTree *>(self)->_live_edit_remove_and_keep_node_func(p_at, p_keep_id); } - static void _live_edit_restore_node_funcs(void *self, ObjectID p_id, const NodePath &p_at, int p_at_pos) { reinterpret_cast<SceneTree *>(self)->_live_edit_restore_node_func(p_id, p_at, p_at_pos); } - static void _live_edit_duplicate_node_funcs(void *self, const NodePath &p_at, const String &p_new_name) { reinterpret_cast<SceneTree *>(self)->_live_edit_duplicate_node_func(p_at, p_new_name); } - static void _live_edit_reparent_node_funcs(void *self, const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos) { reinterpret_cast<SceneTree *>(self)->_live_edit_reparent_node_func(p_at, p_new_place, p_new_name, p_at_pos); } - #endif enum { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d060ac273d..1af88171f6 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -779,10 +779,45 @@ bool Viewport::is_audio_listener_2d() const { return audio_listener_2d; } +void Viewport::enable_canvas_transform_override(bool p_enable) { + if (override_canvas_transform == p_enable) { + return; + } + + override_canvas_transform = p_enable; + if (p_enable) { + VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override); + } else { + VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform); + } +} + +bool Viewport::is_canvas_transform_override_enbled() const { + return override_canvas_transform; +} + +void Viewport::set_canvas_transform_override(const Transform2D &p_transform) { + if (canvas_transform_override == p_transform) { + return; + } + + canvas_transform_override = p_transform; + if (override_canvas_transform) { + VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override); + } +} + +Transform2D Viewport::get_canvas_transform_override() const { + return canvas_transform_override; +} + void Viewport::set_canvas_transform(const Transform2D &p_transform) { canvas_transform = p_transform; - VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform); + + if (!override_canvas_transform) { + VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform); + } } Transform2D Viewport::get_canvas_transform() const { @@ -890,10 +925,12 @@ void Viewport::_camera_set(Camera *p_camera) { camera->notification(Camera::NOTIFICATION_LOST_CURRENT); } camera = p_camera; - if (camera) - VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera()); - else - VisualServer::get_singleton()->viewport_attach_camera(viewport, RID()); + if (!camera_override) { + if (camera) + VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera()); + else + VisualServer::get_singleton()->viewport_attach_camera(viewport, RID()); + } if (camera) { camera->notification(Camera::NOTIFICATION_BECAME_CURRENT); @@ -1108,10 +1145,82 @@ Listener *Viewport::get_listener() const { } Camera *Viewport::get_camera() const { - return camera; } +void Viewport::enable_camera_override(bool p_enable) { + +#ifndef _3D_DISABLED + if (p_enable == camera_override) { + return; + } + + if (p_enable) { + camera_override.rid = VisualServer::get_singleton()->camera_create(); + } else { + VisualServer::get_singleton()->free(camera_override.rid); + camera_override.rid = RID(); + } + + if (p_enable) { + VisualServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid); + } else if (camera) { + VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera()); + } else { + VisualServer::get_singleton()->viewport_attach_camera(viewport, RID()); + } +#endif +} + +bool Viewport::is_camera_override_enabled() const { + return camera_override; +} + +void Viewport::set_camera_override_transform(const Transform &p_transform) { + if (camera_override) { + camera_override.transform = p_transform; + VisualServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform); + } +} + +Transform Viewport::get_camera_override_transform() const { + if (camera_override) { + return camera_override.transform; + } + + return Transform(); +} + +void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) { + if (camera_override) { + if (camera_override.fov == p_fovy_degrees && camera_override.z_near == p_z_near && + camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_PERSPECTIVE) + return; + + camera_override.fov = p_fovy_degrees; + camera_override.z_near = p_z_near; + camera_override.z_far = p_z_far; + camera_override.projection = CameraOverrideData::PROJECTION_PERSPECTIVE; + + VisualServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far); + } +} + +void Viewport::set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far) { + if (camera_override) { + if (camera_override.size == p_size && camera_override.z_near == p_z_near && + camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_ORTHOGONAL) + return; + + camera_override.size = p_size; + camera_override.z_near = p_z_near; + camera_override.z_far = p_z_far; + camera_override.projection = CameraOverrideData::PROJECTION_ORTHOGONAL; + + VisualServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far); + } +} + Transform2D Viewport::get_final_transform() const { return stretch_transform * global_canvas_transform; @@ -3180,6 +3289,7 @@ Viewport::Viewport() { parent = NULL; listener = NULL; camera = NULL; + override_canvas_transform = false; canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport) arvr = false; size_override = false; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 6393785b22..3c3b436ca1 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -160,6 +160,24 @@ private: bool arvr; + struct CameraOverrideData { + Transform transform; + enum Projection { + PROJECTION_PERSPECTIVE, + PROJECTION_ORTHOGONAL + }; + Projection projection; + float fov; + float size; + float z_near; + float z_far; + RID rid; + + operator bool() const { + return rid != RID(); + } + } camera_override; + Camera *camera; Set<Camera *> cameras; Set<CanvasLayer *> canvas_layers; @@ -173,6 +191,9 @@ private: bool audio_listener_2d; RID internal_listener_2d; + bool override_canvas_transform; + + Transform2D canvas_transform_override; Transform2D canvas_transform; Transform2D global_canvas_transform; Transform2D stretch_transform; @@ -394,6 +415,15 @@ public: Listener *get_listener() const; Camera *get_camera() const; + void enable_camera_override(bool p_enable); + bool is_camera_override_enabled() const; + + void set_camera_override_transform(const Transform &p_transform); + Transform get_camera_override_transform() const; + + void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far); + void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far); + void set_use_arvr(bool p_use_arvr); bool use_arvr(); @@ -418,6 +448,12 @@ public: Ref<World2D> get_world_2d() const; Ref<World2D> find_world_2d() const; + void enable_canvas_transform_override(bool p_enable); + bool is_canvas_transform_override_enbled() const; + + void set_canvas_transform_override(const Transform2D &p_transform); + Transform2D get_canvas_transform_override() const; + void set_canvas_transform(const Transform2D &p_transform); Transform2D get_canvas_transform() const; diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 969743f78c..c5956d9bc2 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -332,7 +332,7 @@ void ParticlesMaterial::_update_shader() { code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n"; code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle code += " CUSTOM.y = 0.0;\n"; // phase - code += " CUSTOM.w = LIFETIME * (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n"; + code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n"; code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1) switch (emission_shape) { diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index f1429a7d7b..c897365b21 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -44,8 +44,11 @@ PoolVector<String> Theme::_get_icon_list(const String &p_type) const { get_icon_list(p_type, &il); ilret.resize(il.size()); - for (List<StringName>::Element *E = il.front(); E; E = E->next()) { - ilret.push_back(E->get()); + + int i = 0; + PoolVector<String>::Write w = ilret.write(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); } return ilret; } @@ -57,8 +60,11 @@ PoolVector<String> Theme::_get_stylebox_list(const String &p_type) const { get_stylebox_list(p_type, &il); ilret.resize(il.size()); - for (List<StringName>::Element *E = il.front(); E; E = E->next()) { - ilret.push_back(E->get()); + + int i = 0; + PoolVector<String>::Write w = ilret.write(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); } return ilret; } @@ -70,8 +76,11 @@ PoolVector<String> Theme::_get_stylebox_types(void) const { get_stylebox_types(&il); ilret.resize(il.size()); - for (List<StringName>::Element *E = il.front(); E; E = E->next()) { - ilret.push_back(E->get()); + + int i = 0; + PoolVector<String>::Write w = ilret.write(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); } return ilret; } @@ -83,8 +92,11 @@ PoolVector<String> Theme::_get_font_list(const String &p_type) const { get_font_list(p_type, &il); ilret.resize(il.size()); - for (List<StringName>::Element *E = il.front(); E; E = E->next()) { - ilret.push_back(E->get()); + + int i = 0; + PoolVector<String>::Write w = ilret.write(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); } return ilret; } @@ -96,8 +108,11 @@ PoolVector<String> Theme::_get_color_list(const String &p_type) const { get_color_list(p_type, &il); ilret.resize(il.size()); - for (List<StringName>::Element *E = il.front(); E; E = E->next()) { - ilret.push_back(E->get()); + + int i = 0; + PoolVector<String>::Write w = ilret.write(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); } return ilret; } @@ -109,8 +124,11 @@ PoolVector<String> Theme::_get_constant_list(const String &p_type) const { get_constant_list(p_type, &il); ilret.resize(il.size()); - for (List<StringName>::Element *E = il.front(); E; E = E->next()) { - ilret.push_back(E->get()); + + int i = 0; + PoolVector<String>::Write w = ilret.write(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); } return ilret; } @@ -122,8 +140,11 @@ PoolVector<String> Theme::_get_type_list(const String &p_type) const { get_type_list(&il); ilret.resize(il.size()); - for (List<StringName>::Element *E = il.front(); E; E = E->next()) { - ilret.push_back(E->get()); + + int i = 0; + PoolVector<String>::Write w = ilret.write(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); } return ilret; } diff --git a/servers/audio/effects/eq.cpp b/servers/audio/effects/eq.cpp index e8f247d3bc..a9b576b1d9 100644 --- a/servers/audio/effects/eq.cpp +++ b/servers/audio/effects/eq.cpp @@ -103,7 +103,9 @@ void EQ::recalculate_band_coefficients() { //printf("band %i, precoefs = %f,%f,%f\n",i,c2a,c2b,c2c); - double r1, r2; //roots + // Default initializing to silence compiler warning about potential uninitialized use. + // Both variables are properly set in _solve_quadratic before use, or we continue if roots == 0. + double r1 = 0, r2 = 0; //roots int roots = solve_quadratic(c2a, c2b, c2c, &r1, &r2); ERR_CONTINUE(roots == 0); diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index f7cec6a378..c944e7016e 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -56,12 +56,12 @@ #include "audio_server.h" #include "camera/camera_feed.h" #include "camera_server.h" -#include "core/script_debugger_remote.h" #include "physics/physics_server_sw.h" #include "physics_2d/physics_2d_server_sw.h" #include "physics_2d/physics_2d_server_wrap_mt.h" #include "physics_2d_server.h" #include "physics_server.h" +#include "scene/debugger/script_debugger_remote.h" #include "visual/shader_types.h" #include "visual_server.h" diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 0df228457e..06096781fe 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -409,6 +409,8 @@ public: BIND2(particles_set_process_material, RID, RID) BIND2(particles_set_fixed_fps, RID, int) BIND2(particles_set_fractional_delta, RID, bool) + BIND1R(bool, particles_is_inactive, RID) + BIND1(particles_request_process, RID) BIND1(particles_restart, RID) BIND2(particles_set_draw_order, RID, VS::ParticlesDrawOrder) diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 273cf728c1..59df51ff19 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -343,6 +343,8 @@ public: FUNC2(particles_set_process_material, RID, RID) FUNC2(particles_set_fixed_fps, RID, int) FUNC2(particles_set_fractional_delta, RID, bool) + FUNC1R(bool, particles_is_inactive, RID) + FUNC1(particles_request_process, RID) FUNC1(particles_restart, RID) FUNC2(particles_set_draw_order, RID, VS::ParticlesDrawOrder) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 4bab9b76ba..b095f24212 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1844,6 +1844,8 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("particles_set_process_material", "particles", "material"), &VisualServer::particles_set_process_material); ClassDB::bind_method(D_METHOD("particles_set_fixed_fps", "particles", "fps"), &VisualServer::particles_set_fixed_fps); ClassDB::bind_method(D_METHOD("particles_set_fractional_delta", "particles", "enable"), &VisualServer::particles_set_fractional_delta); + ClassDB::bind_method(D_METHOD("particles_is_inactive", "particles"), &VisualServer::particles_is_inactive); + ClassDB::bind_method(D_METHOD("particles_request_process", "particles"), &VisualServer::particles_request_process); ClassDB::bind_method(D_METHOD("particles_restart", "particles"), &VisualServer::particles_restart); ClassDB::bind_method(D_METHOD("particles_set_draw_order", "particles", "order"), &VisualServer::particles_set_draw_order); ClassDB::bind_method(D_METHOD("particles_set_draw_passes", "particles", "count"), &VisualServer::particles_set_draw_passes); diff --git a/servers/visual_server.h b/servers/visual_server.h index 5e6c4d9b1e..1c1b04f198 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -560,6 +560,8 @@ public: virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; + virtual bool particles_is_inactive(RID p_particles) = 0; + virtual void particles_request_process(RID p_particles) = 0; virtual void particles_restart(RID p_particles) = 0; enum ParticlesDrawOrder { |