Merge pull request #56730 from akien-mga/3.x-cherrypicks

This commit is contained in:
Rémi Verschelde 2022-01-12 18:44:11 +01:00 committed by GitHub
commit 2d645edacc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 189 additions and 220 deletions

View File

@ -498,8 +498,9 @@ if selected_platform in platform_list:
if env["target"] == "release":
if env["tools"]:
print("Tools can only be built with targets 'debug' and 'release_debug'.")
sys.exit(255)
print("ERROR: The editor can only be built with `target=debug` or `target=release_debug`.")
print(" Use `tools=no target=release` to build a release export template.")
Exit(255)
suffix += ".opt"
env.Append(CPPDEFINES=["NDEBUG"])

View File

@ -82,11 +82,6 @@ bool AABB::create_from_points(const Vector<Vector3> &p_points) {
}
void AABB::merge_with(const AABB &p_aabb) {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
Vector3 beg_1, beg_2;
Vector3 end_1, end_2;
Vector3 min, max;
@ -113,11 +108,6 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const {
}
AABB AABB::intersection(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
Vector3 src_min = position;
Vector3 src_max = position + size;
Vector3 dst_min = p_aabb.position;
@ -150,11 +140,6 @@ AABB AABB::intersection(const AABB &p_aabb) const {
}
bool AABB::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip, Vector3 *r_normal) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
Vector3 c1, c2;
Vector3 end = position + size;
real_t near = -1e20;
@ -198,11 +183,6 @@ bool AABB::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *
}
bool AABB::intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip, Vector3 *r_normal) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
real_t min = 0, max = 1;
int axis = 0;
real_t sign = 0;

View File

@ -115,11 +115,6 @@ public:
};
inline bool AABB::intersects(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
if (position.x >= (p_aabb.position.x + p_aabb.size.x)) {
return false;
}
@ -143,11 +138,6 @@ inline bool AABB::intersects(const AABB &p_aabb) const {
}
inline bool AABB::intersects_inclusive(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
if (position.x > (p_aabb.position.x + p_aabb.size.x)) {
return false;
}
@ -171,11 +161,6 @@ inline bool AABB::intersects_inclusive(const AABB &p_aabb) const {
}
inline bool AABB::encloses(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
Vector3 src_min = position;
Vector3 src_max = position + size;
Vector3 dst_min = p_aabb.position;
@ -286,11 +271,6 @@ bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const {
}
bool AABB::has_point(const Vector3 &p_point) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
if (p_point.x < position.x) {
return false;
}
@ -314,11 +294,6 @@ bool AABB::has_point(const Vector3 &p_point) const {
}
inline void AABB::expand_to(const Vector3 &p_vector) {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
Vector3 begin = position;
Vector3 end = position + size;
@ -385,11 +360,6 @@ inline real_t AABB::get_shortest_axis_size() const {
}
bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
real_t divx = 1.0 / p_dir.x;
real_t divy = 1.0 / p_dir.y;
real_t divz = 1.0 / p_dir.z;

View File

@ -35,11 +35,6 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
}
bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
real_t min = 0, max = 1;
int axis = 0;
real_t sign = 0;
@ -100,11 +95,6 @@ bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2
}
bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
//SAT intersection between local and transformed rect2
Vector2 xf_points[4] = {

View File

@ -49,11 +49,6 @@ struct Rect2 {
_FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5); }
inline bool intersects(const Rect2 &p_rect, const bool p_include_borders = false) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
if (p_include_borders) {
if (position.x > (p_rect.position.x + p_rect.size.width)) {
return false;
@ -86,11 +81,6 @@ struct Rect2 {
}
inline real_t distance_to(const Vector2 &p_point) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
real_t dist = 0.0;
bool inside = true;
@ -127,11 +117,6 @@ struct Rect2 {
bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = nullptr, Point2 *r_normal = nullptr) const;
inline bool encloses(const Rect2 &p_rect) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
((p_rect.position.x + p_rect.size.x) <= (position.x + size.x)) &&
((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
@ -161,11 +146,7 @@ struct Rect2 {
}
inline Rect2 merge(const Rect2 &p_rect) const { ///< return a merged rect
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
Rect2 new_rect;
new_rect.position.x = MIN(p_rect.position.x, position.x);
@ -179,11 +160,6 @@ struct Rect2 {
return new_rect;
};
inline bool has_point(const Point2 &p_point) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
if (p_point.x < position.x) {
return false;
}
@ -206,11 +182,6 @@ struct Rect2 {
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
inline Rect2 grow(real_t p_by) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
Rect2 g = *this;
g.grow_by(p_by);
return g;
@ -233,11 +204,6 @@ struct Rect2 {
}
inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
Rect2 g = *this;
g.position.x -= p_left;
g.position.y -= p_top;
@ -254,11 +220,7 @@ struct Rect2 {
}
inline void expand_to(const Vector2 &p_vector) { //in place function for speed
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
Vector2 begin = position;
Vector2 end = position + size;
@ -311,11 +273,6 @@ struct Rect2i {
_FORCE_INLINE_ Vector2i get_center() const { return position + (size / 2); }
inline bool intersects(const Rect2i &p_rect) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
}
#endif
if (position.x > (p_rect.position.x + p_rect.size.width)) {
return false;
}
@ -333,11 +290,6 @@ struct Rect2i {
}
inline bool encloses(const Rect2i &p_rect) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
}
#endif
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) &&
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
@ -360,18 +312,14 @@ struct Rect2i {
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x;
new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y;
new_rect.size.x = (int)(MIN(p_rect_end.x, end.x) - new_rect.position.x);
new_rect.size.y = (int)(MIN(p_rect_end.y, end.y) - new_rect.position.y);
return new_rect;
}
inline Rect2i merge(const Rect2i &p_rect) const { ///< return a merged rect
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
}
#endif
Rect2i new_rect;
new_rect.position.x = MIN(p_rect.position.x, position.x);
@ -383,13 +331,8 @@ struct Rect2i {
new_rect.size = new_rect.size - new_rect.position; //make relative again
return new_rect;
}
};
bool has_point(const Point2 &p_point) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
}
#endif
if (p_point.x < position.x) {
return false;
}
@ -411,11 +354,6 @@ struct Rect2i {
bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; }
Rect2i grow(int p_by) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
}
#endif
Rect2i g = *this;
g.position.x -= p_by;
g.position.y -= p_by;
@ -434,11 +372,6 @@ struct Rect2i {
}
inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
}
#endif
Rect2i g = *this;
g.position.x -= p_left;
g.position.y -= p_top;
@ -455,11 +388,6 @@ struct Rect2i {
}
inline void expand_to(const Point2i &p_vector) {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size.");
}
#endif
Point2i begin = position;
Point2i end = position + size;

View File

@ -85,7 +85,7 @@ enum JoystickList {
JOY_BUTTON_20 = 20,
JOY_BUTTON_21 = 21,
JOY_BUTTON_22 = 22,
JOY_BUTTON_MAX = 23,
JOY_BUTTON_MAX = 128, // Android supports up to 36 buttons. DirectInput supports up to 128 buttons.
JOY_L = JOY_BUTTON_4,
JOY_R = JOY_BUTTON_5,

View File

@ -509,6 +509,9 @@ public:
}
Element *lower_bound(const T &p_value) const {
if (!_data._root) {
return nullptr;
}
return _lower_bound(p_value);
}

View File

@ -1015,8 +1015,11 @@
<constant name="JOY_BUTTON_22" value="22" enum="JoystickList">
Gamepad button 22.
</constant>
<constant name="JOY_BUTTON_MAX" value="23" enum="JoystickList">
Represents the maximum number of joystick buttons supported.
<constant name="JOY_BUTTON_MAX" value="128" enum="JoystickList">
The maximum number of game controller buttons supported by the engine. The actual limit may be lower on specific platforms:
- Android: Up to 36 buttons.
- Linux: Up to 80 buttons.
- Windows and macOS: Up to 128 buttons.
</constant>
<constant name="JOY_SONY_CIRCLE" value="1" enum="JoystickList">
DualShock circle button.

View File

@ -6,7 +6,6 @@
<description>
[AABB] consists of a position, a size, and several utility functions. It is typically used for fast overlap tests.
It uses floating-point coordinates. The 2D counterpart to [AABB] is [Rect2].
Negative values for [member size] are not supported and will not work for most methods. Use [method abs] to get an AABB with a positive size.
[b]Note:[/b] Unlike [Rect2], [AABB] does not have a variant that uses integer coordinates.
</description>
<tutorials>

View File

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioEffectRecord" inherits="AudioEffect" version="3.5">
<brief_description>
Audio effect used for recording sound from a microphone.
Audio effect used for recording the sound from an audio bus.
</brief_description>
<description>
Allows the user to record sound from a microphone. It sets and gets the format in which the audio file will be recorded (8-bit, 16-bit, or compressed). It checks whether or not the recording is active, and if it is, records the sound. It then returns the recorded sample.
Allows the user to record the sound from an audio bus. This can include all audio output by Godot when used on the "Master" audio bus.
Can be used (with an [AudioStreamMicrophone]) to record from a microphone.
It sets and gets the format in which the audio file will be recorded (8-bit, 16-bit, or compressed). It checks whether or not the recording is active, and if it is, records the sound. It then returns the recorded sample.
</description>
<tutorials>
<link title="Recording with microphone">$DOCS_URL/tutorials/audio/recording_with_microphone.html</link>

View File

@ -893,6 +893,12 @@
<description>
Emitted when the mouse leaves the control's [code]Rect[/code] area, provided its [member mouse_filter] lets the event reach it.
[b]Note:[/b] [signal mouse_exited] will be emitted if the mouse enters a child [Control] node, even if the mouse cursor is still inside the parent's [code]Rect[/code] area.
If you want to check whether the mouse truly left the area, ignoring any top nodes, you can use code like this:
[codeblock]
func _on_mouse_exited():
if not Rect2(Vector2(), rect_size).has_point(get_local_mouse_position()):
# Not hovering over area.
[/codeblock]
</description>
</signal>
<signal name="resized">

View File

@ -13,7 +13,9 @@
<return type="void" />
<argument index="0" name="filter" type="String" />
<description>
Adds [code]filter[/code] as a custom filter; [code]filter[/code] should be of the form [code]"filename.extension ; Description"[/code]. For example, [code]"*.png ; PNG Images"[/code].
Adds [code]filter[/code] to the list of filters, which restricts what files can be picked.
A [code]filter[/code] should be of the form [code]"filename.extension ; Description"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed.
Example filters: [code]"*.png ; PNG Images"[/code], [code]"project.godot ; Godot Project"[/code].
</description>
</method>
<method name="clear_filters">
@ -65,7 +67,7 @@
</member>
<member name="dialog_hide_on_ok" type="bool" setter="set_hide_on_ok" getter="get_hide_on_ok" overrides="AcceptDialog" default="false" />
<member name="filters" type="PoolStringArray" setter="set_filters" getter="get_filters" default="PoolStringArray( )">
The available file type filters. For example, this shows only [code].png[/code] and [code].gd[/code] files: [code]set_filters(PoolStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]))[/code].
The available file type filters. For example, this shows only [code].png[/code] and [code].gd[/code] files: [code]set_filters(PoolStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]))[/code]. Multiple file types can also be specified in a single filter. [code]"*.png, *.jpg, *.jpeg ; Supported Images"[/code] will show both PNG and JPEG files when selected.
</member>
<member name="mode" type="int" setter="set_mode" getter="get_mode" enum="FileDialog.Mode" default="4">
The dialog's open or save mode, which affects the selection behavior. See enum [code]Mode[/code] constants.

View File

@ -283,7 +283,7 @@
<theme_item name="port_grab_distance_horizontal" data_type="constant" type="int" default="24">
The horizontal range within which a port can be grabbed (on both sides).
</theme_item>
<theme_item name="port_grab_distance_vertical" data_type="constant" type="int" default="6">
<theme_item name="port_grab_distance_vertical" data_type="constant" type="int" default="26">
The vertical range within which a port can be grabbed (on both sides).
</theme_item>
<theme_item name="minimap" data_type="icon" type="Texture">

View File

@ -93,7 +93,7 @@
<argument index="1" name="edge" type="int" />
<description>
Returns specified edge associated with given face.
Edge argument must 2 or less because a face only has three edges.
Edge argument must be either 0, 1, or 2 because a face only has three edges.
</description>
</method>
<method name="get_face_meta" qualifiers="const">
@ -116,7 +116,7 @@
<argument index="1" name="vertex" type="int" />
<description>
Returns the specified vertex of the given face.
Vertex argument must be 2 or less because faces contain three vertices.
Vertex argument must be either 0, 1, or 2 because faces contain three vertices.
</description>
</method>
<method name="get_format" qualifiers="const">

View File

@ -17,7 +17,7 @@
</member>
<member name="normal_map" type="Texture" setter="set_normal_map" getter="get_normal_map">
The normal map that will be used if using the default [CanvasItemMaterial].
[b]Note:[/b] Godot expects the normal map to use X+, Y-, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
[b]Note:[/b] Godot expects the normal map to use X+, Y+, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
</member>
<member name="texture" type="Texture" setter="set_texture" getter="get_texture">
The [Texture] that will be used if using the default [CanvasItemMaterial]. Can be accessed as [code]TEXTURE[/code] in CanvasItem shader.

View File

@ -17,7 +17,7 @@
</member>
<member name="normal_map" type="Texture" setter="set_normal_map" getter="get_normal_map">
The normal map that will be used if using the default [CanvasItemMaterial].
[b]Note:[/b] Godot expects the normal map to use X+, Y-, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
[b]Note:[/b] Godot expects the normal map to use X+, Y+, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
</member>
<member name="texture" type="Texture" setter="set_texture" getter="get_texture">
The [Texture] that will be used if using the default [CanvasItemMaterial]. Can be accessed as [code]TEXTURE[/code] in CanvasItem shader.

View File

@ -163,6 +163,7 @@
[codeblock]
ProjectSettings.set_setting("application/config/name", "Example")
[/codeblock]
This can also be used to erase custom project settings. To do this change the setting value to [code]null[/code].
</description>
</method>
</methods>

View File

@ -122,7 +122,7 @@
The custom color to use to draw the shape in the editor and at run-time if [b]Visible Collision Shapes[/b] is enabled in the [b]Debug[/b] menu. This color will be highlighted at run-time if the [RayCast] is colliding with something.
If set to [code]Color(0.0, 0.0, 0.0)[/code] (by default), the color set in [member ProjectSettings.debug/shapes/collision/shape_color] is used.
</member>
<member name="debug_shape_thickness" type="float" setter="set_debug_shape_thickness" getter="get_debug_shape_thickness" default="2.0">
<member name="debug_shape_thickness" type="int" setter="set_debug_shape_thickness" getter="get_debug_shape_thickness" default="2">
If set to [code]1[/code], a line is used as the debug shape. Otherwise, a truncated pyramid is drawn to represent the [RayCast]. Requires [b]Visible Collision Shapes[/b] to be enabled in the [b]Debug[/b] menu for the debug shape to be visible at run-time.
</member>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="false">

View File

@ -7,7 +7,6 @@
[Rect2] consists of a position, a size, and several utility functions. It is typically used for fast overlap tests.
It uses floating-point coordinates.
The 3D counterpart to [Rect2] is [AABB].
Negative values for [member size] are not supported and will not work for most methods. Use [method abs] to get a Rect2 with a positive size.
</description>
<tutorials>
<link title="Math tutorial index">$DOCS_URL/tutorials/math/index.html</link>

View File

@ -27,6 +27,19 @@
If [code]true[/code], the slider will display ticks for minimum and maximum values.
</member>
</members>
<signals>
<signal name="drag_ended">
<argument index="0" name="value_changed" type="bool" />
<description>
Emitted when dragging stops. If [code]value_changed[/code] is true, [member Range.value] is different from the value when you started the dragging.
</description>
</signal>
<signal name="drag_started">
<description>
Emitted when dragging is started.
</description>
</signal>
</signals>
<constants>
</constants>
</class>

View File

@ -146,7 +146,7 @@
</member>
<member name="detail_normal" type="Texture" setter="set_texture" getter="get_texture">
Texture that specifies the per-pixel normal of the detail overlay.
[b]Note:[/b] Godot expects the normal map to use X+, Y-, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
[b]Note:[/b] Godot expects the normal map to use X+, Y+, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
</member>
<member name="detail_uv_layer" type="int" setter="set_detail_uv" getter="get_detail_uv" enum="SpatialMaterial.DetailUV">
Specifies whether to use [code]UV[/code] or [code]UV2[/code] for the detail layer. See [enum DetailUV] for options.
@ -239,7 +239,7 @@
<member name="normal_texture" type="Texture" setter="set_texture" getter="get_texture">
Texture used to specify the normal at a given pixel. The [code]normal_texture[/code] only uses the red and green channels; the blue and alpha channels are ignored. The normal read from [code]normal_texture[/code] is oriented around the surface normal provided by the [Mesh].
[b]Note:[/b] The mesh must have both normals and tangents defined in its vertex data. Otherwise, the normal map won't render correctly and will only appear to darken the whole surface. If creating geometry with [SurfaceTool], you can use [method SurfaceTool.generate_normals] and [method SurfaceTool.generate_tangents] to automatically generate normals and tangents respectively.
[b]Note:[/b] Godot expects the normal map to use X+, Y-, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
[b]Note:[/b] Godot expects the normal map to use X+, Y+, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
</member>
<member name="params_alpha_scissor_threshold" type="float" setter="set_alpha_scissor_threshold" getter="get_alpha_scissor_threshold">
Threshold at which the alpha scissor will discard values.

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SpriteFrames" inherits="Resource" version="3.5">
<brief_description>
Sprite frame library for AnimatedSprite.
Sprite frame library for AnimatedSprite and AnimatedSprite3D.
</brief_description>
<description>
Sprite frame library for [AnimatedSprite]. Contains frames and animation data for playback.
Sprite frame library for an [AnimatedSprite] or [AnimatedSprite3D] node. Contains frames and animation data for playback.
[b]Note:[/b] You can associate a set of normal maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] suffix. For example, having 2 [SpriteFrames] resources [code]run[/code] and [code]run_normal[/code] will make it so the [code]run[/code] animation uses the normal map.
</description>
<tutorials>

View File

@ -86,7 +86,9 @@
<return type="float" />
<argument index="0" name="with" type="Vector2" />
<description>
Returns the cross product of this vector and [code]with[/code].
Returns the 2D analog of the cross product for this vector and [code]with[/code].
This is the signed area of the parallelogram formed by the two vectors. If the second vector is clockwise from the first vector, then the cross product is the positive area. If counter-clockwise, the cross product is the negative area.
[b]Note:[/b] Cross product is not defined in 2D mathematically. This method embeds the 2D vectors in the XY plane of 3D space and uses their cross product's Z component as the analog.
</description>
</method>
<method name="cubic_interpolate">

View File

@ -2665,8 +2665,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
}
} break;
case RUN_PROJECT_DATA_FOLDER: {
// ensure_user_data_dir() to prevent the edge case: "Open Project Data Folder" won't work after the project was renamed in ProjectSettingsEditor unless the project is saved
case RUN_USER_DATA_FOLDER: {
// ensure_user_data_dir() to prevent the edge case: "Open User Data Folder" won't work after the project was renamed in ProjectSettingsEditor unless the project is saved
OS::get_singleton()->ensure_user_data_dir();
OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir());
} break;
@ -6333,7 +6333,7 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_shortcut(ED_SHORTCUT("editor/export", TTR("Export...")), FILE_EXPORT_PROJECT);
p->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE);
p->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER);
p->add_item(TTR("Open User Data Folder"), RUN_USER_DATA_FOLDER);
plugin_config_dialog = memnew(PluginConfigDialog);
plugin_config_dialog->connect("plugin_ready", this, "_on_plugin_ready");

View File

@ -163,7 +163,7 @@ private:
RUN_PLAY_CUSTOM_SCENE,
RUN_SCENE_SETTINGS,
RUN_SETTINGS,
RUN_PROJECT_DATA_FOLDER,
RUN_USER_DATA_FOLDER,
RUN_RELOAD_CURRENT_PROJECT,
RUN_PROJECT_MANAGER,
RUN_FILE_SERVER,

View File

@ -775,7 +775,8 @@ InputDefault::InputDefault() {
void InputDefault::joy_button(int p_device, int p_button, bool p_pressed) {
_THREAD_SAFE_METHOD_;
Joypad &joy = joy_names[p_device];
//printf("got button %i, mapping is %i\n", p_button, joy.mapping);
ERR_FAIL_INDEX(p_button, JOY_BUTTON_MAX);
if (joy.last_buttons[p_button] == p_pressed) {
return;
}

View File

@ -1104,7 +1104,7 @@ HashMap<int, R> FBXMeshData::extract_per_vertex_data(
const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index);
ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR05");
ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file corrupted: #ERR06");
const int index_to_direct = p_mapping_data.index[polygon_vertex_index];
const int index_to_direct = get_vertex_from_polygon_vertex(p_mapping_data.index, polygon_vertex_index);
T value = p_mapping_data.data[index_to_direct];
aggregate_vertex_data[vertex_index].push_back({ polygon_id, value });
}
@ -1309,7 +1309,7 @@ HashMap<int, T> FBXMeshData::extract_per_polygon(
} else {
ERR_FAIL_INDEX_V_MSG(polygon_index, (int)p_fbx_data.index.size(), (HashMap<int, T>()), "FBX file is corrupted: #ERR62");
const int index_to_direct = p_fbx_data.index[polygon_index];
const int index_to_direct = get_vertex_from_polygon_vertex(p_fbx_data.index, polygon_index);
T value = p_fbx_data.data[index_to_direct];
aggregate_polygon_data[polygon_index].push_back(value);
}

View File

@ -6586,103 +6586,110 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar
state->major_version = version.get_slice(".", 0).to_int();
state->minor_version = version.get_slice(".", 1).to_int();
/* STEP 0 PARSE SCENE */
/* PARSE EXTENSIONS */
err = _parse_gltf_extensions(state);
if (err != OK) {
return Error::FAILED;
}
/* PARSE SCENE */
err = _parse_scenes(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 1 PARSE NODES */
/* PARSE NODES */
err = _parse_nodes(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 2 PARSE BUFFERS */
/* PARSE BUFFERS */
err = _parse_buffers(state, p_path.get_base_dir());
if (err != OK) {
return Error::FAILED;
}
/* STEP 3 PARSE BUFFER VIEWS */
/* PARSE BUFFER VIEWS */
err = _parse_buffer_views(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 4 PARSE ACCESSORS */
/* PARSE ACCESSORS */
err = _parse_accessors(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 5 PARSE IMAGES */
/* PARSE IMAGES */
err = _parse_images(state, p_path.get_base_dir());
if (err != OK) {
return Error::FAILED;
}
/* STEP 6 PARSE TEXTURES */
/* PARSE TEXTURES */
err = _parse_textures(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 7 PARSE TEXTURES */
/* PARSE TEXTURES */
err = _parse_materials(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 9 PARSE SKINS */
/* PARSE SKINS */
err = _parse_skins(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 10 DETERMINE SKELETONS */
/* DETERMINE SKELETONS */
err = _determine_skeletons(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 11 CREATE SKELETONS */
/* CREATE SKELETONS */
err = _create_skeletons(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 12 CREATE SKINS */
/* CREATE SKINS */
err = _create_skins(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 13 PARSE MESHES (we have enough info now) */
/* PARSE MESHES (we have enough info now) */
err = _parse_meshes(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 14 PARSE LIGHTS */
/* PARSE LIGHTS */
err = _parse_lights(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 15 PARSE CAMERAS */
/* PARSE CAMERAS */
err = _parse_cameras(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 16 PARSE ANIMATIONS */
/* PARSE ANIMATIONS */
err = _parse_animations(state);
if (err != OK) {
return Error::FAILED;
}
/* STEP 17 ASSIGN SCENE NAMES */
/* ASSIGN SCENE NAMES */
_assign_scene_names(state);
return OK;
@ -6802,3 +6809,15 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
}
return err;
}
Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) {
ERR_FAIL_COND_V(!state.is_valid(), ERR_PARSE_ERROR);
if (state->json.has("extensionsRequired") && state->json["extensionsRequired"].get_type() == Variant::ARRAY) {
Array extensions_required = state->json["extensionsRequired"];
if (extensions_required.find("KHR_draco_mesh_compression") != -1) {
ERR_PRINT("glTF2 extension KHR_draco_mesh_compression is not supported.");
return ERR_UNAVAILABLE;
}
}
return OK;
}

View File

@ -373,6 +373,8 @@ public:
String _sanitize_scene_name(Ref<GLTFState> state, const String &p_name);
String _legacy_validate_node_name(const String &p_name);
Error _parse_gltf_extensions(Ref<GLTFState> state);
void _process_mesh_instances(Ref<GLTFState> state, Node *scene_root);
void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent,
Spatial *scene_root,

View File

@ -67,7 +67,7 @@ void WebSocketServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_handshake_timeout"), &WebSocketServer::get_handshake_timeout);
ClassDB::bind_method(D_METHOD("set_handshake_timeout", "timeout"), &WebSocketServer::set_handshake_timeout);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handshake_timeout"), "set_handshake_timeout", "get_handshake_timeout");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "handshake_timeout"), "set_handshake_timeout", "get_handshake_timeout");
ADD_SIGNAL(MethodInfo("client_close_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason")));
ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::BOOL, "was_clean_close")));

View File

@ -170,9 +170,9 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
@implementation GodotApplicationDelegate
- (void)forceUnbundledWindowActivationHackStep1 {
// Step1: Switch focus to macOS Dock.
// Step 1: Switch focus to macOS SystemUIServer process.
// Required to perform step 2, TransformProcessType will fail if app is already the in focus.
for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.systemuiserver"]) {
[app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
break;
}
@ -194,8 +194,8 @@ static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
- (void)applicationDidFinishLaunching:(NSNotification *)notice {
NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
if (nsappname == nil) {
// If executable is not a bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO)) {
// If the executable is started from terminal or is not bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
[self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
}
}

View File

@ -137,12 +137,8 @@ void OS_UWP::initialize_core() {
NetSocketPosix::make_default();
// We need to know how often the clock is updated
if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second))
ticks_per_second = 1000;
// If timeAtGameStart is 0 then we get the time since
// the start of the computer when we call GetGameTime()
ticks_start = 0;
ticks_start = get_ticks_usec();
QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second);
QueryPerformanceCounter((LARGE_INTEGER *)&ticks_start);
IP_Unix::make_default();
@ -564,6 +560,9 @@ uint64_t OS_UWP::get_ticks_usec() const {
// This is the number of clock ticks since start
QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
// Subtract the ticks at game start to get
// the ticks since the game started
ticks -= ticks_start;
// Divide by frequency to get the time in seconds
// original calculation shown below is subject to overflow
@ -583,9 +582,6 @@ uint64_t OS_UWP::get_ticks_usec() const {
// seconds
time += seconds * 1000000L;
// Subtract the time at game start to get
// the time since the game started
time -= ticks_start;
return time;
}

View File

@ -174,12 +174,8 @@ void OS_Windows::initialize_core() {
NetSocketPosix::make_default();
// We need to know how often the clock is updated
if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second))
ticks_per_second = 1000;
// If timeAtGameStart is 0 then we get the time since
// the start of the computer when we call GetGameTime()
ticks_start = 0;
ticks_start = get_ticks_usec();
QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second);
QueryPerformanceCounter((LARGE_INTEGER *)&ticks_start);
// set minimum resolution for periodic timers, otherwise Sleep(n) may wait at least as
// long as the windows scheduler resolution (~16-30ms) even for calls like Sleep(1)
@ -2460,8 +2456,10 @@ uint64_t OS_Windows::get_ticks_usec() const {
uint64_t ticks;
// This is the number of clock ticks since start
if (!QueryPerformanceCounter((LARGE_INTEGER *)&ticks))
ticks = (UINT64)timeGetTime();
QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
// Subtract the ticks at game start to get
// the ticks since the game started
ticks -= ticks_start;
// Divide by frequency to get the time in seconds
// original calculation shown below is subject to overflow
@ -2481,9 +2479,6 @@ uint64_t OS_Windows::get_ticks_usec() const {
// seconds
time += seconds * 1000000L;
// Subtract the time at game start to get
// the time since the game started
time -= ticks_start;
return time;
}

View File

@ -94,6 +94,10 @@ void Path2D::_notification(int p_what) {
return;
}
if (curve->get_point_count() < 2) {
return;
}
#ifdef TOOLS_ENABLED
const float line_width = 2 * EDSCALE;
#else

View File

@ -636,7 +636,7 @@ void Polygon2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "uv"), "set_uv", "get_uv");
ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "vertex_colors"), "set_vertex_colors", "get_vertex_colors");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons"), "set_polygons", "get_polygons");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_bones", "_get_bones");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_bones", "_get_bones");
ADD_PROPERTY(PropertyInfo(Variant::INT, "internal_vertex_count", PROPERTY_HINT_RANGE, "0,1000"), "set_internal_vertex_count", "get_internal_vertex_count");
}

View File

@ -332,7 +332,7 @@ void RayCast::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_shape_thickness", PROPERTY_HINT_RANGE, "1,5"), "set_debug_shape_thickness", "get_debug_shape_thickness");
}
float RayCast::get_debug_shape_thickness() const {
int RayCast::get_debug_shape_thickness() const {
return debug_shape_thickness;
}
@ -361,7 +361,7 @@ void RayCast::_update_debug_shape_vertices() {
}
}
void RayCast::set_debug_shape_thickness(const float p_debug_shape_thickness) {
void RayCast::set_debug_shape_thickness(const int p_debug_shape_thickness) {
debug_shape_thickness = p_debug_shape_thickness;
update_gizmo();

View File

@ -100,8 +100,8 @@ public:
Ref<SpatialMaterial> get_debug_material();
float get_debug_shape_thickness() const;
void set_debug_shape_thickness(const float p_debug_thickness);
int get_debug_shape_thickness() const;
void set_debug_shape_thickness(const int p_debug_thickness);
void force_raycast_update();
bool is_colliding() const;

View File

@ -567,6 +567,7 @@ void FileDialog::clear_filters() {
invalidate();
}
void FileDialog::add_filter(const String &p_filter) {
ERR_FAIL_COND_MSG(p_filter.begins_with("."), "Filter must be \"filename.extension\", can't start with dot.");
filters.push_back(p_filter);
update_filters();
invalidate();

View File

@ -1667,6 +1667,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
_remove_item(p_item->subitems.front()->get(), p_line, p_subitem_line);
}
}
memdelete(p_item);
}
void RichTextLabel::add_image(const Ref<Texture> &p_image, const int p_width, const int p_height) {
@ -2164,6 +2165,12 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
push_strikethrough();
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "lb") {
add_text("[");
pos = brk_end + 1;
} else if (tag == "rb") {
add_text("]");
pos = brk_end + 1;
} else if (tag == "center") {
push_align(ALIGN_CENTER);
pos = brk_end + 1;

View File

@ -68,8 +68,13 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
}
grab.active = true;
grab.uvalue = get_as_ratio();
emit_signal("drag_started");
} else {
grab.active = false;
const bool value_changed = !Math::is_equal_approx((double)grab.uvalue, get_as_ratio());
emit_signal("drag_ended", value_changed);
}
} else if (scrollable) {
if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
@ -263,6 +268,9 @@ void Slider::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_scrollable", "scrollable"), &Slider::set_scrollable);
ClassDB::bind_method(D_METHOD("is_scrollable"), &Slider::is_scrollable);
ADD_SIGNAL(MethodInfo("drag_started"));
ADD_SIGNAL(MethodInfo("drag_ended", PropertyInfo(Variant::BOOL, "value_changed")));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrollable"), "set_scrollable", "is_scrollable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tick_count", PROPERTY_HINT_RANGE, "0,4096,1"), "set_ticks", "get_ticks");

View File

@ -382,6 +382,7 @@ void TextEdit::_update_scrollbars() {
cursor.line_ofs = 0;
cursor.wrap_ofs = 0;
v_scroll->set_value(0);
v_scroll->set_max(0);
v_scroll->hide();
}
@ -399,6 +400,7 @@ void TextEdit::_update_scrollbars() {
} else {
cursor.x_ofs = 0;
h_scroll->set_value(0);
h_scroll->set_max(0);
h_scroll->hide();
}

View File

@ -168,6 +168,12 @@ void TextureButton::_notification(int p_what) {
Point2 ofs;
Size2 size;
bool draw_focus = (has_focus() && focused.is_valid());
// If no other texture is valid, try using focused texture.
if (!texdraw.is_valid() && draw_focus) {
texdraw = focused;
}
if (texdraw.is_valid()) {
size = texdraw->get_size();
@ -224,7 +230,9 @@ void TextureButton::_notification(int p_what) {
size.width *= hflip ? -1.0f : 1.0f;
size.height *= vflip ? -1.0f : 1.0f;
if (_tile) {
if (texdraw == focused) {
// Do nothing, we only needed to calculate the rectangle.
} else if (_tile) {
draw_texture_rect(texdraw, Rect2(ofs, size), _tile);
} else {
draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region);
@ -233,7 +241,7 @@ void TextureButton::_notification(int p_what) {
_position_rect = Rect2();
}
if (has_focus() && focused.is_valid()) {
if (draw_focus) {
draw_texture_rect(focused, Rect2(ofs, size), false);
};
} break;

View File

@ -109,10 +109,37 @@ Variant PropertyUtils::get_property_default_value(const Object *p_object, const
}
// Fall back to the default from the native class
{
if (r_is_class_default) {
*r_is_class_default = true;
}
return ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property, r_is_valid);
bool valid = false;
Variant value = ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property, &valid);
if (valid) {
if (r_is_valid) {
*r_is_valid = true;
}
return value;
} else {
// Heuristically check if this is a synthetic property (whatever/0, whatever/1, etc.)
// because they are not in the class DB yet must have a default (null).
String prop_str = String(p_property);
int p = prop_str.rfind("/");
if (p != -1 && p < prop_str.length() - 1) {
bool all_digits = true;
for (int i = p + 1; i < prop_str.length(); i++) {
if (prop_str[i] < '0' || prop_str[i] > '9') {
all_digits = false;
break;
}
}
if (r_is_valid) {
*r_is_valid = all_digits;
}
}
return Variant();
}
}
}
// Like SceneState::PackState, but using a raw pointer to avoid the cost of

View File

@ -903,7 +903,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Visual Node Ports
theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 24 * scale);
theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale);
theme->set_constant("port_grab_distance_vertical", "GraphEdit", 26 * scale);
theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0);