summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/image.cpp151
-rw-r--r--core/image.h1
-rw-r--r--core/math/math_funcs.h6
-rw-r--r--core/object.cpp12
-rw-r--r--core/os/input_event.cpp13
-rw-r--r--doc/classes/@GDScript.xml6
-rw-r--r--doc/classes/AnimationNodeStateMachine.xml2
-rw-r--r--doc/classes/BaseButton.xml6
-rw-r--r--doc/classes/CanvasItem.xml42
-rw-r--r--doc/classes/CheckButton.xml4
-rw-r--r--doc/classes/Font.xml10
-rw-r--r--doc/classes/FuncRef.xml6
-rw-r--r--doc/classes/Image.xml2
-rw-r--r--doc/classes/MultiMesh.xml2
-rw-r--r--doc/classes/OptionButton.xml4
-rw-r--r--doc/classes/PopupMenu.xml4
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--doc/classes/String.xml1
-rw-r--r--doc/classes/VisualServer.xml22
-rwxr-xr-xdoc/tools/makerst.py15
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp5
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h1
-rw-r--r--drivers/gles2/shaders/scene.glsl30
-rw-r--r--drivers/gles3/shaders/scene.glsl27
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/editor_settings.cpp5
-rw-r--r--editor/editor_themes.cpp2
-rw-r--r--editor/scene_tree_dock.cpp2
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj4
-rw-r--r--modules/bullet/rigid_body_bullet.cpp10
-rw-r--r--modules/bullet/shape_bullet.cpp8
-rw-r--r--modules/gdnative/gdnative_library_singleton_editor.cpp134
-rw-r--r--modules/gdnative/gdnative_library_singleton_editor.h12
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp2
-rw-r--r--modules/gdnative/register_types.cpp122
-rw-r--r--platform/javascript/os_javascript.cpp2
-rw-r--r--platform/javascript/os_javascript.h2
-rw-r--r--platform/uwp/os_uwp.cpp2
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--scene/gui/line_edit.cpp4
-rw-r--r--scene/gui/text_edit.cpp5
-rw-r--r--servers/visual/shader_types.cpp2
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp19
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp420
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h21
45 files changed, 902 insertions, 258 deletions
diff --git a/core/image.cpp b/core/image.cpp
index 99d5eab864..30af724de9 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -725,6 +725,131 @@ static void _scale_nearest(const uint8_t *__restrict p_src, uint8_t *__restrict
}
}
+#define LANCZOS_TYPE 3
+
+static float _lanczos(float p_x) {
+ return Math::abs(p_x) >= LANCZOS_TYPE ? 0 : Math::sincn(p_x) * Math::sincn(p_x / LANCZOS_TYPE);
+}
+
+template <int CC, class T>
+static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
+
+ int32_t src_width = p_src_width;
+ int32_t src_height = p_src_height;
+ int32_t dst_height = p_dst_height;
+ int32_t dst_width = p_dst_width;
+
+ uint32_t buffer_size = src_height * dst_width * CC;
+ float *buffer = memnew_arr(float, buffer_size); // Store the first pass in a buffer
+
+ { // FIRST PASS (horizontal)
+
+ float x_scale = float(src_width) / float(dst_width);
+
+ float scale_factor = MAX(x_scale, 1); // A larger kernel is required only when downscaling
+ int32_t half_kernel = LANCZOS_TYPE * scale_factor;
+
+ float *kernel = memnew_arr(float, half_kernel * 2 - 1);
+
+ for (int32_t buffer_x = 0; buffer_x < dst_width; buffer_x++) {
+
+ float src_real_x = buffer_x * x_scale;
+ int32_t src_x = src_real_x;
+
+ int32_t start_x = MAX(0, src_x - half_kernel + 1);
+ int32_t end_x = MIN(src_width - 1, src_x + half_kernel);
+
+ // Create the kernel used by all the pixels of the column
+ for (int32_t target_x = start_x; target_x <= end_x; target_x++)
+ kernel[target_x - start_x] = _lanczos((src_real_x - target_x) / scale_factor);
+
+ for (int32_t buffer_y = 0; buffer_y < src_height; buffer_y++) {
+
+ float pixel[CC] = { 0 };
+ float weight = 0;
+
+ for (int32_t target_x = start_x; target_x <= end_x; target_x++) {
+
+ float lanczos_val = kernel[target_x - start_x];
+ weight += lanczos_val;
+
+ const T *__restrict src_data = ((const T *)p_src) + (buffer_y * src_width + target_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++) {
+ if (sizeof(T) == 2) //half float
+ pixel[i] += Math::half_to_float(src_data[i]) * lanczos_val;
+ else
+ pixel[i] += src_data[i] * lanczos_val;
+ }
+ }
+
+ float *dst_data = ((float *)buffer) + (buffer_y * dst_width + buffer_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++)
+ dst_data[i] = pixel[i] / weight; // Normalize the sum of all the samples
+ }
+ }
+
+ memdelete_arr(kernel);
+ } // End of first pass
+
+ { // SECOND PASS (vertical + result)
+
+ float y_scale = float(src_height) / float(dst_height);
+
+ float scale_factor = MAX(y_scale, 1);
+ int32_t half_kernel = LANCZOS_TYPE * scale_factor;
+
+ float *kernel = memnew_arr(float, half_kernel * 2 - 1);
+
+ for (int32_t dst_y = 0; dst_y < dst_height; dst_y++) {
+
+ float buffer_real_y = dst_y * y_scale;
+ int32_t buffer_y = buffer_real_y;
+
+ int32_t start_y = MAX(0, buffer_y - half_kernel + 1);
+ int32_t end_y = MIN(src_height - 1, buffer_y + half_kernel);
+
+ for (int32_t target_y = start_y; target_y <= end_y; target_y++)
+ kernel[target_y - start_y] = _lanczos((buffer_real_y - target_y) / scale_factor);
+
+ for (int32_t dst_x = 0; dst_x < dst_width; dst_x++) {
+
+ float pixel[CC] = { 0 };
+ float weight = 0;
+
+ for (int32_t target_y = start_y; target_y <= end_y; target_y++) {
+
+ float lanczos_val = kernel[target_y - start_y];
+ weight += lanczos_val;
+
+ float *buffer_data = ((float *)buffer) + (target_y * dst_width + dst_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++)
+ pixel[i] += buffer_data[i] * lanczos_val;
+ }
+
+ T *dst_data = ((T *)p_dst) + (dst_y * dst_width + dst_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++) {
+ pixel[i] /= weight;
+
+ if (sizeof(T) == 1) //byte
+ dst_data[i] = CLAMP(Math::fast_ftoi(pixel[i]), 0, 255);
+ else if (sizeof(T) == 2) //half float
+ dst_data[i] = Math::make_half_float(pixel[i]);
+ else // float
+ dst_data[i] = pixel[i];
+ }
+ }
+ }
+
+ memdelete_arr(kernel);
+ } // End of second pass
+
+ memdelete_arr(buffer);
+}
+
static void _overlay(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, float p_alpha, uint32_t p_width, uint32_t p_height, uint32_t p_pixel_size) {
uint16_t alpha = CLAMP((uint16_t)(p_alpha * 256.0f), 0, 256);
@@ -939,6 +1064,31 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
}
}
} break;
+ case INTERPOLATE_LANCZOS: {
+
+ if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
+ switch (get_format_pixel_size(format)) {
+ case 1: _scale_lanczos<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 2: _scale_lanczos<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 3: _scale_lanczos<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 4: _scale_lanczos<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
+ switch (get_format_pixel_size(format)) {
+ case 4: _scale_lanczos<1, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 8: _scale_lanczos<2, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 12: _scale_lanczos<3, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 16: _scale_lanczos<4, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
+ switch (get_format_pixel_size(format)) {
+ case 2: _scale_lanczos<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 4: _scale_lanczos<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 6: _scale_lanczos<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 8: _scale_lanczos<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ }
+ } break;
}
r = PoolVector<uint8_t>::Read();
@@ -2685,6 +2835,7 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(INTERPOLATE_BILINEAR);
BIND_ENUM_CONSTANT(INTERPOLATE_CUBIC);
BIND_ENUM_CONSTANT(INTERPOLATE_TRILINEAR);
+ BIND_ENUM_CONSTANT(INTERPOLATE_LANCZOS);
BIND_ENUM_CONSTANT(ALPHA_NONE);
BIND_ENUM_CONSTANT(ALPHA_BIT);
diff --git a/core/image.h b/core/image.h
index 69a42f169a..752ef20208 100644
--- a/core/image.h
+++ b/core/image.h
@@ -109,6 +109,7 @@ public:
INTERPOLATE_BILINEAR,
INTERPOLATE_CUBIC,
INTERPOLATE_TRILINEAR,
+ INTERPOLATE_LANCZOS,
/* INTERPOLATE_TRICUBIC, */
/* INTERPOLATE GAUSS */
};
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index a75f2fb4ab..82b5b56c01 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -61,6 +61,12 @@ public:
static _ALWAYS_INLINE_ double sinh(double p_x) { return ::sinh(p_x); }
static _ALWAYS_INLINE_ float sinh(float p_x) { return ::sinhf(p_x); }
+ static _ALWAYS_INLINE_ float sinc(float p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
+ static _ALWAYS_INLINE_ double sinc(double p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
+
+ static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc(Math_PI * p_x); }
+ static _ALWAYS_INLINE_ double sincn(double p_x) { return sinc(Math_PI * p_x); }
+
static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); }
static _ALWAYS_INLINE_ float cosh(float p_x) { return ::coshf(p_x); }
diff --git a/core/object.cpp b/core/object.cpp
index 937aa3c745..2a4ab93a6d 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -608,18 +608,16 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
}
bool valid = false;
- Variant current_value = get(p_names[0]);
+ Variant current_value = get(p_names[0], &valid);
for (int i = 1; i < p_names.size(); i++) {
current_value = current_value.get_named(p_names[i], &valid);
- if (!valid) {
- if (r_valid)
- *r_valid = false;
- return Variant();
- }
+ if (!valid)
+ break;
}
if (r_valid)
- *r_valid = true;
+ *r_valid = valid;
+
return current_value;
}
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index 25a5c2afeb..a072017353 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -717,8 +717,17 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *
bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false;
if (p_pressed != NULL)
*p_pressed = pressed;
- if (p_strength != NULL)
- *p_strength = pressed ? CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f) : 0.0f;
+ if (p_strength != NULL) {
+ if (pressed) {
+ if (p_deadzone == 1.0f) {
+ *p_strength = 1.0f;
+ } else {
+ *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f);
+ }
+ } else {
+ *p_strength = 0.0f;
+ }
+ }
}
return match;
}
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index 2f7f05b2e4..63b9ef13fd 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -259,12 +259,12 @@
</description>
</method>
<method name="decimals">
- <return type="float">
+ <return type="int">
</return>
<argument index="0" name="step" type="float">
</argument>
<description>
- Deprecated alias for "[method step_decimals]".
+ Deprecated alias for "[method step_decimals]".
</description>
</method>
<method name="dectime">
@@ -1020,7 +1020,7 @@
</description>
</method>
<method name="step_decimals">
- <return type="float">
+ <return type="int">
</return>
<argument index="0" name="step" type="float">
</argument>
diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml
index b80069095b..e46a40c4de 100644
--- a/doc/classes/AnimationNodeStateMachine.xml
+++ b/doc/classes/AnimationNodeStateMachine.xml
@@ -7,7 +7,7 @@
[codeblock]
var state_machine = anim_tree["parameters/StateMachine/playback"]
state_machine.travel("SomeState")
- [codeblock]
+ [/codeblock]
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index c65d545f3e..7bd346ed5a 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -57,6 +57,9 @@
<member name="group" type="ButtonGroup" setter="set_button_group" getter="get_button_group">
[ButtonGroup] associated to the button.
</member>
+ <member name="keep_pressed_outside" type="bool" setter="set_keep_pressed_outside" getter="is_keep_pressed_outside">
+ If [code]true[/code], the button stays pressed when moving the cursor outside the button while pressing it. Default value: [code]false[/code].
+ </member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed">
If [code]true[/code], the button's state is pressed. Means the button is pressed down or toggled (if toggle_mode is active).
</member>
@@ -69,9 +72,6 @@
<member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode">
If [code]true[/code], the button is in toggle mode. Makes the button flip state between pressed and unpressed each time its area is clicked.
</member>
- <member name="keep_pressed_outside" type="bool" setter="set_keep_pressed_outside" getter="is_keep_pressed_outside">
- If [code]true[/code], the button stays pressed when moving the cursor outside the button while pressing it. Default value: [code]false[/code].
- </member>
</members>
<signals>
<signal name="button_down">
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 82a5679172..8ba3990933 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -4,10 +4,10 @@
Base class of anything 2D.
</brief_description>
<description>
- Base class of anything 2D. Canvas items are laid out in a tree and children inherit and extend the transform of their parent. CanvasItem is extended by [Control], for anything GUI related, and by [Node2D] for anything 2D engine related.
- Any CanvasItem can draw. For this, the "update" function must be called, then NOTIFICATION_DRAW will be received on idle time to request redraw. Because of this, canvas items don't need to be redraw on every frame, improving the performance significantly. Several functions for drawing on the CanvasItem are provided (see draw_* functions). They can only be used inside the notification, signal or _draw() overrides function, though.
- Canvas items are draw in tree order. By default, children are on top of their parents so a root CanvasItem will be drawn behind everything (this can be changed per item though).
- Canvas items can also be hidden (hiding also their subtree). They provide many means for changing standard parameters such as opacity (for it and the subtree) and self opacity, blend mode.
+ Base class of anything 2D. Canvas items are laid out in a tree; children inherit and extend their parent's transform. CanvasItem is extended by [Control] for anything GUI-related, and by [Node2D] for anything related to the 2D engine.
+ Any CanvasItem can draw. For this, [method update] must be called, then [constant NOTIFICATION_DRAW] will be received on idle time to request redraw. Because of this, canvas items don't need to be redrawn on every frame, improving the performance significantly. Several functions for drawing on the CanvasItem are provided (see [code]draw_*[/code] functions). However, they can only be used inside the [method Object._notification], signal or [method _draw] virtual functions.
+ Canvas items are drawn in tree order. By default, children are on top of their parents so a root CanvasItem will be drawn behind everything. This behavior can be changed on a per-item basis.
+ A CanvasItem can also be hidden, which will also hide its children. It provides many ways to change parameters such as modulation (for itself and its children) and self modulation (only for itself), as well as its blend mode.
Ultimately, a transform notification can be requested, which will notify the node that its global position changed in case the parent tree changed.
</description>
<tutorials>
@@ -36,7 +36,7 @@
<argument index="4" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<description>
- Draws a string character using a custom font. Returns the advance, depending on the char width and kerning with an optional next char.
+ Draws a string character using a custom font. Returns the advance, depending on the character width and kerning with an optional next character.
</description>
</method>
<method name="draw_circle">
@@ -116,7 +116,7 @@
<argument index="3" name="antialiased" type="bool" default="false">
</argument>
<description>
- Draws multiple, parallel lines with a uniform [code]color[/code] and [code]width[/code] and optional antialiasing.
+ Draws multiple, parallel lines with a uniform [code]color[/code]. [code]width[/code] and [code]antialiased[/code] are currently not implemented and have no effect.
</description>
</method>
<method name="draw_multiline_colors">
@@ -211,7 +211,7 @@
<argument index="5" name="normal_map" type="Texture" default="null">
</argument>
<description>
- Draws a custom primitive, 1 point for a point, 2 points for a line, 3 points for a triangle and 4 points for a quad.
+ Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points for a triangle and 4 points for a quad.
</description>
</method>
<method name="draw_rect">
@@ -308,7 +308,7 @@
<argument index="5" name="normal_map" type="Texture" default="null">
</argument>
<description>
- Draws a textured rectangle at a given position, optionally modulated by a color. Transpose swaps the x and y coordinates when reading the texture.
+ Draws a textured rectangle at a given position, optionally modulated by a color. If [code]transpose[/code] is [code]true[/code], the texture will have its X and Y coordinates swapped.
</description>
</method>
<method name="draw_texture_rect_region">
@@ -329,7 +329,7 @@
<argument index="6" name="clip_uv" type="bool" default="true">
</argument>
<description>
- Draws a textured rectangle region at a given position, optionally modulated by a color. Transpose swaps the x and y coordinates when reading the texture.
+ Draws a textured rectangle region at a given position, optionally modulated by a color. If [code]transpose[/code] is [code]true[/code], the texture will have its X and Y coordinates swapped.
</description>
</method>
<method name="force_update_transform">
@@ -419,7 +419,7 @@
<return type="void">
</return>
<description>
- Hide the CanvasItem currently visible.
+ Hide the CanvasItem if it's currently visible.
</description>
</method>
<method name="is_local_transform_notification_enabled" qualifiers="const">
@@ -433,7 +433,7 @@
<return type="bool">
</return>
<description>
- Return if set as toplevel. See [method set_as_toplevel].
+ Returns [code]true[/code] if the node is set as top-level. See [method set_as_toplevel].
</description>
</method>
<method name="is_transform_notification_enabled" qualifiers="const">
@@ -474,7 +474,7 @@
<argument index="0" name="enable" type="bool">
</argument>
<description>
- Sets as top level. This means that it will not inherit transform from parent canvas items.
+ If [code]enable[/code] is [code]true[/code], the node won't inherit its transform from parent canvas items.
</description>
</method>
<method name="set_notify_local_transform">
@@ -499,14 +499,14 @@
<return type="void">
</return>
<description>
- Show the CanvasItem currently hidden. For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple popup*() functions instead.
+ Show the CanvasItem if it's currently hidden. For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead.
</description>
</method>
<method name="update">
<return type="void">
</return>
<description>
- Queue the CanvasItem for update. [code]NOTIFICATION_DRAW[/code] will be called on idle time to request redraw.
+ Queue the CanvasItem for update. [constant NOTIFICATION_DRAW] will be called on idle time to request redraw.
</description>
</method>
</methods>
@@ -533,7 +533,7 @@
If [code]true[/code], the parent [CanvasItem]'s [member material] property is used as this one's material. Default value: [code]false[/code].
</member>
<member name="visible" type="bool" setter="set_visible" getter="is_visible">
- If [code]true[/code], this [CanvasItem] is drawn. Default value: [code]true[/code]. For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple popup*() functions instead.
+ If [code]true[/code], this [CanvasItem] is drawn. Default value: [code]true[/code]. For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead.
</member>
</members>
<signals>
@@ -575,22 +575,22 @@
Mix blending mode. Colors are assumed to be premultiplied by the alpha (opacity) value.
</constant>
<constant name="BLEND_MODE_DISABLED" value="5" enum="BlendMode">
- Disable blending mode. Colors including alpha are written as is. Only applicable for render targets with a transparent background. No lighting will be applied.
+ Disable blending mode. Colors including alpha are written as-is. Only applicable for render targets with a transparent background. No lighting will be applied.
</constant>
<constant name="NOTIFICATION_TRANSFORM_CHANGED" value="2000">
- Canvas item transform has changed. Notification is only received if enabled by [method set_notify_transform] or [method set_notify_local_transform].
+ The CanvasItem's transform has changed. This notification is only received if enabled by [method set_notify_transform] or [method set_notify_local_transform].
</constant>
<constant name="NOTIFICATION_DRAW" value="30">
- CanvasItem is requested to draw.
+ The CanvasItem is requested to draw.
</constant>
<constant name="NOTIFICATION_VISIBILITY_CHANGED" value="31">
- Canvas item visibility has changed.
+ The CanvasItem's visibility has changed.
</constant>
<constant name="NOTIFICATION_ENTER_CANVAS" value="32">
- Canvas item has entered the canvas.
+ The CanvasItem has entered the canvas.
</constant>
<constant name="NOTIFICATION_EXIT_CANVAS" value="33">
- Canvas item has exited the canvas.
+ The CanvasItem has exited the canvas.
</constant>
</constants>
</class>
diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml
index 94e4eececd..04344c1834 100644
--- a/doc/classes/CheckButton.xml
+++ b/doc/classes/CheckButton.xml
@@ -41,8 +41,12 @@
</theme_item>
<theme_item name="off" type="Texture">
</theme_item>
+ <theme_item name="off_disabled" type="Texture">
+ </theme_item>
<theme_item name="on" type="Texture">
</theme_item>
+ <theme_item name="on_disabled" type="Texture">
+ </theme_item>
<theme_item name="pressed" type="StyleBox">
</theme_item>
</theme_items>
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index bd189928b0..5792b539e0 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -77,6 +77,16 @@
Return the size of a string, taking kerning and advance into account.
</description>
</method>
+ <method name="get_wordwrap_string_size" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="string" type="String">
+ </argument>
+ <argument index="1" name="p_width" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="has_outline" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/FuncRef.xml b/doc/classes/FuncRef.xml
index 3f84316503..e35d7a68c5 100644
--- a/doc/classes/FuncRef.xml
+++ b/doc/classes/FuncRef.xml
@@ -17,6 +17,12 @@
Calls the referenced function previously set by [method set_function] or [method @GDScript.funcref].
</description>
</method>
+ <method name="is_valid" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="set_function">
<return type="void">
</return>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index 641bd64599..8dfabdd884 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -603,6 +603,8 @@
If the image does not have mipmaps, they will be generated and used internally, but no mipmaps will be generated on the resulting image. (Note that if you intend to scale multiple copies of the original image, it's better to call [code]generate_mipmaps[/code] on it in advance, to avoid wasting processing power in generating them again and again.)
On the other hand, if the image already has mipmaps, they will be used, and a new set will be generated for the resulting image.
</constant>
+ <constant name="INTERPOLATE_LANCZOS" value="4" enum="Interpolation">
+ </constant>
<constant name="ALPHA_NONE" value="0" enum="AlphaMode">
</constant>
<constant name="ALPHA_BIT" value="1" enum="AlphaMode">
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index 0e6b5ef1cb..1532fac206 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -59,7 +59,7 @@
<method name="set_as_bulk_array">
<return type="void">
</return>
- <argument index="0" name="arg0" type="PoolRealArray">
+ <argument index="0" name="array" type="PoolRealArray">
</argument>
<description>
Set all data related to the instances in one go. This is especially useful when loading the data from disk or preparing the data from GDNative.
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index 51d2cbc867..06b4cb165e 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -202,14 +202,14 @@
</members>
<signals>
<signal name="item_focused">
- <argument index="0" name="ID" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
This signal is emitted when user navigated to an item using [code]ui_up[/code] or [code]ui_down[/code] action. ID of the item selected is passed as argument.
</description>
</signal>
<signal name="item_selected">
- <argument index="0" name="ID" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
This signal is emitted when the current item was changed by the user. Index of the item selected is passed as argument.
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 4924175b6e..a91f765d41 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -527,14 +527,14 @@
</members>
<signals>
<signal name="id_focused">
- <argument index="0" name="ID" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
This event is emitted when user navigated to an item of some id using [code]ui_up[/code] or [code]ui_down[/code] action.
</description>
</signal>
<signal name="id_pressed">
- <argument index="0" name="ID" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
This event is emitted when an item of some id is pressed or its accelerator is activated.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 46a4a70a9b..4b5500d077 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -281,7 +281,7 @@
If [code]true[/code], enables warnings when using a property as if it was a function.
</member>
<member name="debug/gdscript/warnings/return_value_discarded" type="bool" setter="" getter="">
- If [code]true[/code], enables warnings when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [Error] type.
+ If [code]true[/code], enables warnings when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum.
</member>
<member name="debug/gdscript/warnings/shadowed_variable" type="bool" setter="" getter="">
If [code]true[/code], enables warnings when defining a local or subclass member variable that would shadow a variable at an upper level (such as a member variable).
@@ -717,7 +717,7 @@
Shaders have a time variable that constantly increases. At some point, it needs to be rolled back to zero to avoid precision errors on shader animations. This setting specifies when (in seconds).
</member>
<member name="rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround" type="bool" setter="" getter="">
- Some NVIDIA GPU drivers have a bug which produces flickering issues for the [code]draw_rect[/code] method, especially as used in [TileMap]. Refer to [url]https://github.com/godotengine/godot/issues/9913[/url] for details.
+ Some NVIDIA GPU drivers have a bug which produces flickering issues for the [code]draw_rect[/code] method, especially as used in [TileMap]. Refer to [url=https://github.com/godotengine/godot/issues/9913][/url] for details.
If [code]true[/code], this option enables a "safe" code path for such NVIDIA GPUs at the cost of performance. This option only impacts the GLES2 rendering backend (so the bug stays if you use GLES3), and only desktop platforms.
</member>
<member name="rendering/quality/2d/use_pixel_snap" type="bool" setter="" getter="">
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 526a9427dc..e06f0738b8 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -7,6 +7,7 @@
This is the built-in string class (and the one used by GDScript). It supports Unicode and provides all necessary means for string handling. Strings are reference counted and use a copy-on-write approach, so passing them around is cheap in resources.
</description>
<tutorials>
+ <link>https://docs.godotengine.org/en/stable/getting_started/scripting/gdscript/gdscript_format_string.html</link>
</tutorials>
<methods>
<method name="String">
diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml
index c85a2c4b38..dae120f09b 100644
--- a/doc/classes/VisualServer.xml
+++ b/doc/classes/VisualServer.xml
@@ -2003,17 +2003,6 @@
<description>
</description>
</method>
- <method name="light_set_use_gi">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Sets whether GI probes capture light information from this light.
- </description>
- </method>
<method name="light_set_color">
<return type="void">
</return>
@@ -2096,6 +2085,17 @@
<description>
</description>
</method>
+ <method name="light_set_use_gi">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Sets whether GI probes capture light information from this light.
+ </description>
+ </method>
<method name="lightmap_capture_create">
<return type="RID">
</return>
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index e81b4db13e..c3e15b2f9a 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -683,10 +683,16 @@ def rstize_text(text, state): # type: (str, State) -> str
# Handle [tags]
inside_code = False
+ inside_url = False
+ url_has_name = False
+ url_link = ""
pos = 0
tag_depth = 0
+ previous_pos = 0
while True:
pos = text.find('[', pos)
+ if inside_url and (pos > previous_pos):
+ url_has_name = True
if pos == -1:
break
@@ -795,12 +801,16 @@ def rstize_text(text, state): # type: (str, State) -> str
elif cmd.find('image=') == 0:
tag_text = "" # '![](' + cmd[6:] + ')'
elif cmd.find('url=') == 0:
- tag_text = ':ref:`' + cmd[4:] + '<' + cmd[4:] + ">`"
+ url_link = cmd[4:]
+ tag_text = ':ref:`'
tag_depth += 1
+ url_has_name = False
+ inside_url = True
elif cmd == '/url':
- tag_text = ''
+ tag_text = ('' if url_has_name else url_link) + '<' + url_link + ">`"
tag_depth -= 1
escape_post = True
+ inside_url = False
elif cmd == 'center':
tag_depth += 1
tag_text = ''
@@ -871,6 +881,7 @@ def rstize_text(text, state): # type: (str, State) -> str
text = pre_text + tag_text + post_text
pos = len(pre_text) + len(tag_text)
+ previous_pos = pos
if tag_depth > 0:
print_error("Tag depth mismatch: too many/little open/close tags, file: {}".format(state.current_class), state)
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 55257ab1c5..3b3fbf9ed5 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -2469,6 +2469,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
if (p_env) {
state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy);
+ state.scene_shader.set_uniform(SceneShaderGLES2::BG_COLOR, p_env->bg_color);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color);
@@ -2476,6 +2477,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
} else {
state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, 1.0);
+ state.scene_shader.set_uniform(SceneShaderGLES2::BG_COLOR, state.default_bg);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, 1.0);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, state.default_ambient);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0);
@@ -2578,7 +2580,6 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, false);
state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, false);
state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, false);
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, false);
}
@@ -2829,6 +2830,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
}
state.default_ambient = Color(clear_color.r, clear_color.g, clear_color.b, 1.0);
+ state.default_bg = Color(clear_color.r, clear_color.g, clear_color.b, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -2868,6 +2870,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (probe_interior) {
env_radiance_tex = 0; //do not use radiance texture on interiors
state.default_ambient = Color(0, 0, 0, 1); //black as default ambient for interior
+ state.default_bg = Color(0, 0, 0, 1); //black as default background for interior
}
// render opaque things first
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index e5f0bbcbbb..d805984dca 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -104,6 +104,7 @@ public:
GLuint immediate_buffer;
Color default_ambient;
+ Color default_bg;
// ResolveShaderGLES3 resolve_shader;
// ScreenSpaceReflectionShaderGLES3 ssr_shader;
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index e7e84c4091..0fa290e57c 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -424,9 +424,12 @@ void main() {
#endif
+ mat4 local_projection_matrix = projection_matrix;
+
mat4 modelview = camera_inverse_matrix * world_matrix;
float roughness = 1.0;
+#define projection_matrix local_projection_matrix
#define world_transform world_matrix
{
@@ -911,6 +914,7 @@ uniform mat4 radiance_inverse_xform;
#endif
+uniform vec4 bg_color;
uniform float bg_energy;
uniform float ambient_sky_contribution;
@@ -1558,7 +1562,6 @@ FRAGMENT_SHADER_CODE
ref_vec.z *= -1.0;
specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy;
-
{
vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz);
vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).xyz * bg_energy;
@@ -1569,6 +1572,7 @@ FRAGMENT_SHADER_CODE
#else
ambient_light = ambient_color.rgb;
+ specular_light = bg_color.rgb * bg_energy;
#endif
@@ -1628,6 +1632,19 @@ FRAGMENT_SHADER_CODE
#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
+ // scales the specular reflections, needs to be be computed before lighting happens,
+ // but after environment and reflection probes are added
+ //TODO: this curve is not really designed for gammaspace, should be adjusted
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
+ vec4 r = roughness * c0 + c1;
+ float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
+
+ vec3 f0 = F0(metallic, specular, albedo);
+ specular_light *= env.x * f0 + env.y;
+
#ifdef USE_LIGHTMAP
//ambient light will come entirely from lightmap is lightmap is used
ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy;
@@ -2077,17 +2094,6 @@ FRAGMENT_SHADER_CODE
#if defined(DIFFUSE_TOON)
//simplify for toon, as
specular_light *= specular * metallic * albedo * 2.0;
-#else
- //TODO: this curve is not really designed for gammaspace, should be adjusted
- const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
- const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
- vec4 r = roughness * c0 + c1;
- float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
- float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
- vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
-
- vec3 f0 = F0(metallic, specular, albedo);
- specular_light *= env.x * f0 + env.y;
#endif
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 630e1c2089..def924cd49 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1802,6 +1802,7 @@ FRAGMENT_SHADER_CODE
ambient_light = vec3(0.0, 0.0, 0.0);
#else
ambient_light = ambient_light_color.rgb;
+ env_reflection_light = bg_color.rgb * bg_energy;
#endif //AMBIENT_LIGHT_DISABLED
#endif
@@ -1813,6 +1814,20 @@ FRAGMENT_SHADER_CODE
specular_blob_intensity *= specular * 2.0;
#endif
+ // scales the specular reflections, needs to be be computed before lighting happens,
+ // but after environment and reflection probes are added
+ // Environment brdf approximation (Lazarov 2013)
+ // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
+ vec4 r = roughness * c0 + c1;
+ float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
+
+ vec3 f0 = F0(metallic, specular, albedo);
+ env_reflection_light *= env.x * f0 + env.y;
+
#if defined(USE_LIGHT_DIRECTIONAL)
vec3 light_attenuation = vec3(1.0);
@@ -2063,18 +2078,6 @@ FRAGMENT_SHADER_CODE
#if defined(DIFFUSE_TOON)
//simplify for toon, as
specular_light *= specular * metallic * albedo * 2.0;
-#else
- // Environment brdf approximation (Lazarov 2013)
- // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
- const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
- const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
- vec4 r = roughness * c0 + c1;
- float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0);
- float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
- vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
-
- vec3 f0 = F0(metallic, specular, albedo);
- specular_light *= env.x * f0 + env.y;
#endif
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index fed1f6b4fa..40e05940a7 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1015,8 +1015,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
y = (img->get_height() - size) / 2;
img->crop_from_point(x, y, size, size);
- // We could get better pictures with better filters
- img->resize(preview_size, preview_size, Image::INTERPOLATE_CUBIC);
+ img->resize(preview_size, preview_size, Image::INTERPOLATE_LANCZOS);
}
img->convert(Image::FORMAT_RGB8);
@@ -5997,7 +5996,6 @@ EditorNode::EditorNode() {
node_dock = memnew(NodeDock);
filesystem_dock = memnew(FileSystemDock(this));
- filesystem_dock->connect("open", this, "open_request");
filesystem_dock->connect("inherit", this, "_inherit_request");
filesystem_dock->connect("instance", this, "_instance_request");
filesystem_dock->connect("display_mode_changed", this, "_save_docks");
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index e80d3e1b37..8f26663f81 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -651,7 +651,7 @@ void EditorSettings::_load_default_text_editor_theme() {
_initial_set("text_editor/highlighting/executing_line_color", Color(0.2, 0.8, 0.2, 0.4));
_initial_set("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
_initial_set("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
- _initial_set("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1));
+ _initial_set("text_editor/highlighting/search_result_border_color", Color(0.41, 0.61, 0.91, 0.38));
}
bool EditorSettings::_save_text_editor_theme(String p_file) {
@@ -973,6 +973,9 @@ void EditorSettings::setup_network() {
// link-local IPv6 addresses don't work, skipping them
if (ip.begins_with("fe80:0:0:0:")) // fe80::/64
continue;
+ // Same goes for IPv4 link-local (APIPA) addresses.
+ if (ip.begins_with("169.254.")) // 169.254.0.0/16
+ continue;
if (ip == current)
lip = current; //so it saves
if (hint != "")
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index f74e913208..e1addaa532 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1121,7 +1121,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color executing_line_color = Color(0.2, 0.8, 0.2, 0.4);
const Color code_folding_color = alpha3;
const Color search_result_color = alpha1;
- const Color search_result_border_color = alpha3;
+ const Color search_result_border_color = Color(0.41, 0.61, 0.91, 0.38);
EditorSettings *setting = EditorSettings::get_singleton();
String text_editor_color_theme = setting->get("text_editor/theme/color_theme");
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index a41f10607b..1f5300e351 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1602,6 +1602,8 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
Ref<Script> existing = E->get()->get_script();
editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script.get_ref_ptr());
editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing);
+ editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
}
editor_data->get_undo_redo().commit_action();
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
index 569033d93c..b375293ca6 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
@@ -352,7 +352,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_debug";
COPY_PHASE_STRIP = NO;
ENABLE_BITCODE = NO;
- "FRAMEWORK_SEARCH_PATHS[arch=*]" = "$binary";
+ "FRAMEWORK_SEARCH_PATHS[arch=*]" = "$binary/**";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
@@ -395,7 +395,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_release";
COPY_PHASE_STRIP = YES;
ENABLE_BITCODE = NO;
- "FRAMEWORK_SEARCH_PATHS[arch=*]" = "$binary";
+ "FRAMEWORK_SEARCH_PATHS[arch=*]" = "$binary/**";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index e5f70a0b34..733a900396 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -741,22 +741,20 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) {
if (p_enable) {
// This threshold enable CCD if the object moves more than
// 1 meter in one simulation frame
- btBody->setCcdMotionThreshold(0.1);
+ btBody->setCcdMotionThreshold(1e-7);
/// Calculate using the rule writte below the CCD swept sphere radius
/// CCD works on an embedded sphere of radius, make sure this radius
/// is embedded inside the convex objects, preferably smaller:
/// for an object of dimensions 1 meter, try 0.2
- btScalar radius;
+ btScalar radius(1.0);
if (btBody->getCollisionShape()) {
btVector3 center;
btBody->getCollisionShape()->getBoundingSphere(center, radius);
- } else {
- radius = 0;
}
btBody->setCcdSweptSphereRadius(radius * 0.2);
} else {
- btBody->setCcdMotionThreshold(0.);
+ btBody->setCcdMotionThreshold(10000.0);
btBody->setCcdSweptSphereRadius(0.);
}
}
@@ -834,7 +832,7 @@ void RigidBodyBullet::reload_shapes() {
btBody->updateInertiaTensor();
reload_kinematic_shapes();
-
+ set_continuous_collision_detection(btBody->getCcdMotionThreshold() < 9998.0);
reload_body();
}
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index b590d63167..f15bcec914 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -148,7 +148,13 @@ btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(PoolVector<rea
const bool flipQuadEdges = false;
const void *heightsPtr = p_heights.read().ptr();
- return bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, p_min_height, p_max_height, YAxis, PHY_FLOAT, flipQuadEdges));
+ btHeightfieldTerrainShape *heightfield = bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, p_min_height, p_max_height, YAxis, PHY_FLOAT, flipQuadEdges));
+
+ // The shape can be created without params when you do PhysicsServer.shape_create(PhysicsServer.SHAPE_HEIGHTMAP)
+ if (heightsPtr)
+ heightfield->buildAccelerator(16);
+
+ return heightfield;
}
btRayShape *ShapeBullet::create_shape_ray(real_t p_length, bool p_slips_on_slope) {
diff --git a/modules/gdnative/gdnative_library_singleton_editor.cpp b/modules/gdnative/gdnative_library_singleton_editor.cpp
index 55bc16fccc..389b353a51 100644
--- a/modules/gdnative/gdnative_library_singleton_editor.cpp
+++ b/modules/gdnative/gdnative_library_singleton_editor.cpp
@@ -32,11 +32,16 @@
#include "gdnative_library_singleton_editor.h"
#include "gdnative.h"
-void GDNativeLibrarySingletonEditor::_find_gdnative_singletons(EditorFileSystemDirectory *p_dir, const Set<String> &enabled_list) {
+#include "editor/editor_node.h"
+
+Set<String> GDNativeLibrarySingletonEditor::_find_singletons_recursive(EditorFileSystemDirectory *p_dir) {
+
+ Set<String> file_paths;
// check children
for (int i = 0; i < p_dir->get_file_count(); i++) {
+ String file_name = p_dir->get_file(i);
String file_type = p_dir->get_file_type(i);
if (file_type != "GDNativeLibrary") {
@@ -45,23 +50,57 @@ void GDNativeLibrarySingletonEditor::_find_gdnative_singletons(EditorFileSystemD
Ref<GDNativeLibrary> lib = ResourceLoader::load(p_dir->get_file_path(i));
if (lib.is_valid() && lib->is_singleton()) {
- String path = p_dir->get_file_path(i);
- TreeItem *ti = libraries->create_item(libraries->get_root());
- ti->set_text(0, path.get_file());
- ti->set_tooltip(0, path);
- ti->set_metadata(0, path);
- ti->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
- ti->set_text(1, "Disabled,Enabled");
- bool enabled = enabled_list.has(path) ? true : false;
-
- ti->set_range(1, enabled ? 1 : 0);
- ti->set_custom_color(1, enabled ? Color(0, 1, 0) : Color(1, 0, 0));
+ file_paths.insert(p_dir->get_file_path(i));
}
}
// check subdirectories
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
- _find_gdnative_singletons(p_dir->get_subdir(i), enabled_list);
+ Set<String> paths = _find_singletons_recursive(p_dir->get_subdir(i));
+
+ for (Set<String>::Element *E = paths.front(); E; E = E->next()) {
+ file_paths.insert(E->get());
+ }
+ }
+
+ return file_paths;
+}
+
+void GDNativeLibrarySingletonEditor::_discover_singletons() {
+
+ EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->get_filesystem();
+
+ Set<String> file_paths = _find_singletons_recursive(dir);
+
+ bool changed = false;
+ Array current_files;
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
+ current_files = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ }
+ Array files;
+ for (Set<String>::Element *E = file_paths.front(); E; E = E->next()) {
+ if (!current_files.has(E->get())) {
+ changed = true;
+ }
+ files.append(E->get());
+ }
+
+ // Check for removed files
+ if (!changed) {
+ // Removed singleton
+ for (int j = 0; j < current_files.size(); j++) {
+ if (!files.has(current_files[j])) {
+ changed = true;
+ break;
+ }
+ }
+ }
+
+ if (changed) {
+
+ ProjectSettings::get_singleton()->set("gdnative/singletons", files);
+ _update_libraries(); // So singleton options (i.e. disabled) updates too
+ ProjectSettings::get_singleton()->save();
}
}
@@ -69,22 +108,40 @@ void GDNativeLibrarySingletonEditor::_update_libraries() {
updating = true;
libraries->clear();
- libraries->create_item(); //rppt
+ libraries->create_item(); // root item
- Vector<String> enabled_paths;
+ Array singletons;
if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
- enabled_paths = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
}
- Set<String> enabled_list;
- for (int i = 0; i < enabled_paths.size(); i++) {
- enabled_list.insert(enabled_paths[i]);
+ Array singletons_disabled;
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons_disabled")) {
+ singletons_disabled = ProjectSettings::get_singleton()->get("gdnative/singletons_disabled");
}
- EditorFileSystemDirectory *fs = EditorFileSystem::get_singleton()->get_filesystem();
- if (fs) {
- _find_gdnative_singletons(fs, enabled_list);
+ Array updated_disabled;
+ for (int i = 0; i < singletons.size(); i++) {
+ bool enabled = true;
+ String path = singletons[i];
+ if (singletons_disabled.has(path)) {
+ enabled = false;
+ updated_disabled.push_back(path);
+ }
+ TreeItem *ti = libraries->create_item(libraries->get_root());
+ ti->set_text(0, path.get_file());
+ ti->set_tooltip(0, path);
+ ti->set_metadata(0, path);
+ ti->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
+ ti->set_text(1, "Disabled,Enabled");
+ ti->set_range(1, enabled ? 1 : 0);
+ ti->set_custom_color(1, enabled ? Color(0, 1, 0) : Color(1, 0, 0));
+ ti->set_editable(1, true);
}
+ // The singletons list changed, we must update the settings
+ if (updated_disabled.size() != singletons_disabled.size())
+ ProjectSettings::get_singleton()->set("gdnative/singletons_disabled", updated_disabled);
+
updating = false;
}
@@ -99,24 +156,29 @@ void GDNativeLibrarySingletonEditor::_item_edited() {
bool enabled = item->get_range(1);
String path = item->get_metadata(0);
- Vector<String> enabled_paths;
- if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
- enabled_paths = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ Array disabled_paths;
+ Array undo_paths;
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons_disabled")) {
+ disabled_paths = ProjectSettings::get_singleton()->get("gdnative/singletons_disabled");
+ // Duplicate so redo works (not a reference)
+ disabled_paths = disabled_paths.duplicate();
+ // For undo, so we can reset the property.
+ undo_paths = disabled_paths.duplicate();
}
if (enabled) {
- if (enabled_paths.find(path) == -1) {
- enabled_paths.push_back(path);
- }
+ disabled_paths.erase(path);
} else {
- enabled_paths.erase(path);
+ if (disabled_paths.find(path) == -1)
+ disabled_paths.push_back(path);
}
- if (enabled_paths.size()) {
- ProjectSettings::get_singleton()->set("gdnative/singletons", enabled_paths);
- } else {
- ProjectSettings::get_singleton()->set("gdnative/singletons", Variant());
- }
+ undo_redo->create_action(enabled ? TTR("Enabled GDNative Singleton") : TTR("Disabled GDNative Singleton"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "gdnative/singletons_disabled", disabled_paths);
+ undo_redo->add_do_method(this, "_update_libraries");
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "gdnative/singletons_disabled", undo_paths);
+ undo_redo->add_undo_method(this, "_update_libraries");
+ undo_redo->commit_action();
}
void GDNativeLibrarySingletonEditor::_notification(int p_what) {
@@ -131,9 +193,12 @@ void GDNativeLibrarySingletonEditor::_notification(int p_what) {
void GDNativeLibrarySingletonEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_item_edited"), &GDNativeLibrarySingletonEditor::_item_edited);
+ ClassDB::bind_method(D_METHOD("_discover_singletons"), &GDNativeLibrarySingletonEditor::_discover_singletons);
+ ClassDB::bind_method(D_METHOD("_update_libraries"), &GDNativeLibrarySingletonEditor::_update_libraries);
}
GDNativeLibrarySingletonEditor::GDNativeLibrarySingletonEditor() {
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
libraries = memnew(Tree);
libraries->set_columns(2);
libraries->set_column_titles_visible(true);
@@ -143,6 +208,7 @@ GDNativeLibrarySingletonEditor::GDNativeLibrarySingletonEditor() {
add_margin_child(TTR("Libraries: "), libraries, true);
updating = false;
libraries->connect("item_edited", this, "_item_edited");
+ EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_discover_singletons");
}
#endif // TOOLS_ENABLED
diff --git a/modules/gdnative/gdnative_library_singleton_editor.h b/modules/gdnative/gdnative_library_singleton_editor.h
index cf5ab23501..b43080dfdb 100644
--- a/modules/gdnative/gdnative_library_singleton_editor.h
+++ b/modules/gdnative/gdnative_library_singleton_editor.h
@@ -36,18 +36,24 @@
#include "editor/project_settings_editor.h"
class GDNativeLibrarySingletonEditor : public VBoxContainer {
+ GDCLASS(GDNativeLibrarySingletonEditor, VBoxContainer);
+
+private:
Tree *libraries;
+ UndoRedo *undo_redo;
bool updating;
- void _update_libraries();
- void _find_gdnative_singletons(EditorFileSystemDirectory *p_dir, const Set<String> &enabled_list);
- void _item_edited();
+ static Set<String> _find_singletons_recursive(EditorFileSystemDirectory *p_dir);
protected:
void _notification(int p_what);
static void _bind_methods();
+ void _discover_singletons();
+ void _item_edited();
+ void _update_libraries();
+
public:
GDNativeLibrarySingletonEditor();
};
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 5cf144d4fe..04ba28dc68 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -1309,7 +1309,7 @@ void NativeScriptLanguage::unregister_binding_functions(int p_idx) {
for (Set<Vector<void *> *>::Element *E = binding_instances.front(); E; E = E->next()) {
Vector<void *> &binding_data = *E->get();
- if (binding_data[p_idx] && binding_functions[p_idx].second.free_instance_binding_data)
+ if (p_idx < binding_data.size() && binding_data[p_idx] && binding_functions[p_idx].second.free_instance_binding_data)
binding_functions[p_idx].second.free_instance_binding_data(binding_functions[p_idx].second.data, binding_data[p_idx]);
}
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index 2094dca6e4..55d44ceec8 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -50,97 +50,6 @@
#include "editor/editor_node.h"
#include "gdnative_library_editor_plugin.h"
#include "gdnative_library_singleton_editor.h"
-// Class used to discover singleton gdnative files
-
-static void actual_discoverer_handler();
-
-class GDNativeSingletonDiscover : public Object {
- // GDCLASS(GDNativeSingletonDiscover, Object)
-
- virtual String get_class() const {
- // okay, this is a really dirty hack.
- // We're overriding get_class so we can connect it to a signal
- // This works because get_class is a virtual method, so we don't
- // need to register a new class to ClassDB just for this one
- // little signal.
-
- actual_discoverer_handler();
-
- return "Object";
- }
-};
-
-static Set<String> get_gdnative_singletons(EditorFileSystemDirectory *p_dir) {
-
- Set<String> file_paths;
-
- // check children
-
- for (int i = 0; i < p_dir->get_file_count(); i++) {
- String file_name = p_dir->get_file(i);
- String file_type = p_dir->get_file_type(i);
-
- if (file_type != "GDNativeLibrary") {
- continue;
- }
-
- Ref<GDNativeLibrary> lib = ResourceLoader::load(p_dir->get_file_path(i));
- if (lib.is_valid() && lib->is_singleton()) {
- file_paths.insert(p_dir->get_file_path(i));
- }
- }
-
- // check subdirectories
- for (int i = 0; i < p_dir->get_subdir_count(); i++) {
- Set<String> paths = get_gdnative_singletons(p_dir->get_subdir(i));
-
- for (Set<String>::Element *E = paths.front(); E; E = E->next()) {
- file_paths.insert(E->get());
- }
- }
-
- return file_paths;
-}
-
-static void actual_discoverer_handler() {
-
- EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->get_filesystem();
-
- Set<String> file_paths = get_gdnative_singletons(dir);
-
- bool changed = false;
- Array current_files;
- if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
- current_files = ProjectSettings::get_singleton()->get("gdnative/singletons");
- }
- Array files;
- files.resize(file_paths.size());
- int i = 0;
- for (Set<String>::Element *E = file_paths.front(); E; i++, E = E->next()) {
- if (!current_files.has(E->get())) {
- changed = true;
- }
- files.set(i, E->get());
- }
-
- // Check for removed files
- if (!changed) {
- for (int j = 0; j < current_files.size(); j++) {
- if (!file_paths.has(current_files[j])) {
- changed = true;
- break;
- }
- }
- }
-
- if (changed) {
-
- ProjectSettings::get_singleton()->set("gdnative/singletons", files);
- ProjectSettings::get_singleton()->save();
- }
-}
-
-static GDNativeSingletonDiscover *discoverer = NULL;
class GDNativeExportPlugin : public EditorExportPlugin {
@@ -275,9 +184,6 @@ static void editor_init_callback() {
library_editor->set_name(TTR("GDNative"));
ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(library_editor);
- discoverer = memnew(GDNativeSingletonDiscover);
- EditorFileSystem::get_singleton()->connect("filesystem_changed", discoverer, "get_class");
-
Ref<GDNativeExportPlugin> export_plugin;
export_plugin.instance();
@@ -335,30 +241,36 @@ void register_gdnative_types() {
if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
}
-
- singleton_gdnatives.resize(singletons.size());
+ Array excluded = Array();
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons_disabled")) {
+ excluded = ProjectSettings::get_singleton()->get("gdnative/singletons_disabled");
+ }
for (int i = 0; i < singletons.size(); i++) {
String path = singletons[i];
- Ref<GDNativeLibrary> lib = ResourceLoader::load(path);
+ if (excluded.has(path))
+ continue;
- singleton_gdnatives.write[i].instance();
- singleton_gdnatives.write[i]->set_library(lib);
+ Ref<GDNativeLibrary> lib = ResourceLoader::load(path);
+ Ref<GDNative> singleton;
+ singleton.instance();
+ singleton->set_library(lib);
- if (!singleton_gdnatives.write[i]->initialize()) {
+ if (!singleton->initialize()) {
// Can't initialize. Don't make a native_call then
continue;
}
void *proc_ptr;
- Error err = singleton_gdnatives[i]->get_symbol(
+ Error err = singleton->get_symbol(
lib->get_symbol_prefix() + "gdnative_singleton",
proc_ptr);
if (err != OK) {
- ERR_PRINT((String("No godot_gdnative_singleton in \"" + singleton_gdnatives[i]->get_library()->get_current_library_path()) + "\" found").utf8().get_data());
+ ERR_PRINT((String("No godot_gdnative_singleton in \"" + singleton->get_library()->get_current_library_path()) + "\" found").utf8().get_data());
} else {
+ singleton_gdnatives.push_back(singleton);
((void (*)())proc_ptr)();
}
}
@@ -388,12 +300,6 @@ void unregister_gdnative_types() {
memdelete(GDNativeCallRegistry::singleton);
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && discoverer != NULL) {
- memdelete(discoverer);
- }
-#endif
-
ResourceLoader::remove_resource_format_loader(resource_loader_gdnlib);
resource_loader_gdnlib.unref();
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 34781ce365..2e3e10e222 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -1035,7 +1035,7 @@ void OS_JavaScript::finalize() {
// Miscellaneous
-Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
+Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
ERR_EXPLAIN("OS::execute() is not available on the HTML5 platform");
ERR_FAIL_V(ERR_UNAVAILABLE);
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index a9f9e23463..f7ce28e660 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -137,7 +137,7 @@ public:
void run_async();
bool main_loop_iterate();
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
virtual Error kill(const ProcessID &p_pid);
virtual int get_process_id() const;
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 82f09032f5..1678d351b3 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -713,7 +713,7 @@ void OS_UWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c
// TODO
}
-Error OS_UWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
+Error OS_UWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
return FAILED;
};
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 00f79efb04..7b00224017 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -208,7 +208,7 @@ public:
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
virtual Error kill(const ProcessID &p_pid);
virtual bool has_environment(const String &p_var) const;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index d889c8d8b8..2d18a80833 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -613,9 +613,7 @@ void LineEdit::_notification(int p_what) {
#endif
case NOTIFICATION_RESIZED: {
- if (expand_to_text_length) {
- window_pos = 0; //force scroll back since it's expanding to text length
- }
+ window_pos = 0;
set_cursor_position(get_cursor_position());
} break;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 10bd9e2a8b..86b99b3c6d 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1072,10 +1072,7 @@ void TextEdit::_notification(int p_what) {
}
if ((char_ofs + char_margin + char_w) >= xmargin_end) {
- if (syntax_coloring)
- continue;
- else
- break;
+ break;
}
bool in_search_result = false;
diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp
index 7a42bc475e..8fd5dfc738 100644
--- a/servers/visual/shader_types.cpp
+++ b/servers/visual/shader_types.cpp
@@ -76,7 +76,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4;
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
index 782e9efaf1..b30ce03164 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
@@ -19,9 +19,10 @@ subject to the following restrictions:
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
-#include "BulletCollision/CollisionShapes/btSphereShape.h" //for raycasting
-#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" //for raycasting
-#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" //for raycasting
+#include "BulletCollision/CollisionShapes/btSphereShape.h" //for raycasting
+#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" //for raycasting
+#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" //for raycasting
+#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h" //for raycasting
#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h"
#include "BulletCollision/CollisionShapes/btCompoundShape.h"
#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
@@ -413,6 +414,18 @@ void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans, co
rcb.m_hitFraction = resultCallback.m_closestHitFraction;
triangleMesh->performRaycast(&rcb, rayFromLocalScaled, rayToLocalScaled);
}
+ else if (collisionShape->getShapeType()==TERRAIN_SHAPE_PROXYTYPE)
+ {
+ ///optimized version for btHeightfieldTerrainShape
+ btHeightfieldTerrainShape* heightField = (btHeightfieldTerrainShape*)collisionShape;
+ btTransform worldTocollisionObject = colObjWorldTransform.inverse();
+ btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin();
+ btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin();
+
+ BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObjectWrap->getCollisionObject(),heightField,colObjWorldTransform);
+ rcb.m_hitFraction = resultCallback.m_closestHitFraction;
+ heightField->performRaycast(&rcb, rayFromLocal, rayToLocal);
+ }
else
{
//generic (slower) case
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp b/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
index c85ce2498e..4adf27e6bb 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
@@ -73,6 +73,10 @@ void btHeightfieldTerrainShape::initialize(
m_useZigzagSubdivision = false;
m_upAxis = upAxis;
m_localScaling.setValue(btScalar(1.), btScalar(1.), btScalar(1.));
+ m_vboundsGrid = NULL;
+ m_vboundsChunkSize = 0;
+ m_vboundsGridWidth = 0;
+ m_vboundsGridLength = 0;
// determine min/max axis-aligned bounding box (aabb) values
switch (m_upAxis)
@@ -108,6 +112,7 @@ void btHeightfieldTerrainShape::initialize(
btHeightfieldTerrainShape::~btHeightfieldTerrainShape()
{
+ clearAccelerator();
}
void btHeightfieldTerrainShape::getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const
@@ -323,6 +328,8 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
}
}
+ // TODO If m_vboundsGrid is available, use it to determine if we really need to process this area
+
for (int j = startJ; j < endJ; j++)
{
for (int x = startX; x < endX; x++)
@@ -373,3 +380,416 @@ const btVector3& btHeightfieldTerrainShape::getLocalScaling() const
{
return m_localScaling;
}
+
+
+
+struct GridRaycastState
+{
+ int x; // Next quad coords
+ int z;
+ int prev_x; // Previous quad coords
+ int prev_z;
+ btScalar param; // Exit param for previous quad
+ btScalar prevParam; // Enter param for previous quad
+ btScalar maxDistanceFlat;
+ btScalar maxDistance3d;
+};
+
+
+// TODO Does it really need to take 3D vectors?
+/// Iterates through a virtual 2D grid of unit-sized square cells,
+/// and executes an action on each cell intersecting the given segment, ordered from begin to end.
+/// Initially inspired by http://www.cse.yorku.ca/~amana/research/grid.pdf
+template <typename Action_T>
+void gridRaycast(Action_T &quadAction, const btVector3 &beginPos, const btVector3 &endPos)
+{
+ GridRaycastState rs;
+ rs.maxDistance3d = beginPos.distance(endPos);
+ if (rs.maxDistance3d < 0.0001)
+ // Consider the ray is too small to hit anything
+ return;
+
+ btScalar rayDirectionFlatX = endPos[0] - beginPos[0];
+ btScalar rayDirectionFlatZ = endPos[2] - beginPos[2];
+ rs.maxDistanceFlat = btSqrt(rayDirectionFlatX * rayDirectionFlatX + rayDirectionFlatZ * rayDirectionFlatZ);
+
+ if(rs.maxDistanceFlat < 0.0001)
+ {
+ // Consider the ray vertical
+ rayDirectionFlatX = 0;
+ rayDirectionFlatZ = 0;
+ }
+ else
+ {
+ rayDirectionFlatX /= rs.maxDistanceFlat;
+ rayDirectionFlatZ /= rs.maxDistanceFlat;
+ }
+
+ const int xiStep = rayDirectionFlatX > 0 ? 1 : rayDirectionFlatX < 0 ? -1 : 0;
+ const int ziStep = rayDirectionFlatZ > 0 ? 1 : rayDirectionFlatZ < 0 ? -1 : 0;
+
+ const float infinite = 9999999;
+ const btScalar paramDeltaX = xiStep != 0 ? 1.f / btFabs(rayDirectionFlatX) : infinite;
+ const btScalar paramDeltaZ = ziStep != 0 ? 1.f / btFabs(rayDirectionFlatZ) : infinite;
+
+ // pos = param * dir
+ btScalar paramCrossX; // At which value of `param` we will cross a x-axis lane?
+ btScalar paramCrossZ; // At which value of `param` we will cross a z-axis lane?
+
+ // paramCrossX and paramCrossZ are initialized as being the first cross
+ // X initialization
+ if (xiStep != 0)
+ {
+ if (xiStep == 1)
+ paramCrossX = (ceil(beginPos[0]) - beginPos[0]) * paramDeltaX;
+ else
+ paramCrossX = (beginPos[0] - floor(beginPos[0])) * paramDeltaX;
+ }
+ else
+ paramCrossX = infinite; // Will never cross on X
+
+ // Z initialization
+ if (ziStep != 0)
+ {
+ if (ziStep == 1)
+ paramCrossZ = (ceil(beginPos[2]) - beginPos[2]) * paramDeltaZ;
+ else
+ paramCrossZ = (beginPos[2] - floor(beginPos[2])) * paramDeltaZ;
+ }
+ else
+ paramCrossZ = infinite; // Will never cross on Z
+
+ rs.x = static_cast<int>(floor(beginPos[0]));
+ rs.z = static_cast<int>(floor(beginPos[2]));
+
+ // Workaround cases where the ray starts at an integer position
+ if (paramCrossX == 0.0)
+ {
+ paramCrossX += paramDeltaX;
+ // If going backwards, we should ignore the position we would get by the above flooring,
+ // because the ray is not heading in that direction
+ if (xiStep == -1)
+ rs.x -= 1;
+ }
+
+ if (paramCrossZ == 0.0)
+ {
+ paramCrossZ += paramDeltaZ;
+ if (ziStep == -1)
+ rs.z -= 1;
+ }
+
+ rs.prev_x = rs.x;
+ rs.prev_z = rs.z;
+ rs.param = 0;
+
+ while (true)
+ {
+ rs.prev_x = rs.x;
+ rs.prev_z = rs.z;
+ rs.prevParam = rs.param;
+
+ if (paramCrossX < paramCrossZ)
+ {
+ // X lane
+ rs.x += xiStep;
+ // Assign before advancing the param,
+ // to be in sync with the initialization step
+ rs.param = paramCrossX;
+ paramCrossX += paramDeltaX;
+ }
+ else
+ {
+ // Z lane
+ rs.z += ziStep;
+ rs.param = paramCrossZ;
+ paramCrossZ += paramDeltaZ;
+ }
+
+ if (rs.param > rs.maxDistanceFlat)
+ {
+ rs.param = rs.maxDistanceFlat;
+ quadAction(rs);
+ break;
+ }
+ else
+ quadAction(rs);
+ }
+}
+
+
+struct ProcessTrianglesAction
+{
+ const btHeightfieldTerrainShape *shape;
+ bool flipQuadEdges;
+ bool useDiamondSubdivision;
+ int width;
+ int length;
+ btTriangleCallback* callback;
+
+ void exec(int x, int z) const
+ {
+ if(x < 0 || z < 0 || x >= width || z >= length)
+ return;
+
+ btVector3 vertices[3];
+
+ // Check quad
+ if (flipQuadEdges || (useDiamondSubdivision && (((z + x) & 1) > 0)))
+ {
+ // First triangle
+ shape->getVertex(x, z, vertices[0]);
+ shape->getVertex(x + 1, z, vertices[1]);
+ shape->getVertex(x + 1, z + 1, vertices[2]);
+ callback->processTriangle(vertices, x, z);
+
+ // Second triangle
+ shape->getVertex(x, z, vertices[0]);
+ shape->getVertex(x + 1, z + 1, vertices[1]);
+ shape->getVertex(x, z + 1, vertices[2]);
+ callback->processTriangle(vertices, x, z);
+ }
+ else
+ {
+ // First triangle
+ shape->getVertex(x, z, vertices[0]);
+ shape->getVertex(x, z + 1, vertices[1]);
+ shape->getVertex(x + 1, z, vertices[2]);
+ callback->processTriangle(vertices, x, z);
+
+ // Second triangle
+ shape->getVertex(x + 1, z, vertices[0]);
+ shape->getVertex(x, z + 1, vertices[1]);
+ shape->getVertex(x + 1, z + 1, vertices[2]);
+ callback->processTriangle(vertices, x, z);
+ }
+ }
+
+ void operator ()(const GridRaycastState &bs) const
+ {
+ exec(bs.prev_x, bs.prev_z);
+ }
+};
+
+
+struct ProcessVBoundsAction
+{
+ const btHeightfieldTerrainShape::Range *vbounds;
+ int width;
+ int length;
+ int chunkSize;
+
+ btVector3 rayBegin;
+ btVector3 rayEnd;
+ btVector3 rayDir;
+
+ ProcessTrianglesAction processTriangles;
+
+ void operator ()(const GridRaycastState &rs) const
+ {
+ int x = rs.prev_x;
+ int z = rs.prev_z;
+
+ if(x < 0 || z < 0 || x >= width || z >= length)
+ return;
+
+ const btHeightfieldTerrainShape::Range chunk = vbounds[x + z * width];
+
+ btVector3 enterPos;
+ btVector3 exitPos;
+
+ if (rs.maxDistanceFlat > 0.0001)
+ {
+ btScalar flatTo3d = chunkSize * rs.maxDistance3d / rs.maxDistanceFlat;
+ btScalar enterParam3d = rs.prevParam * flatTo3d;
+ btScalar exitParam3d = rs.param * flatTo3d;
+ enterPos = rayBegin + rayDir * enterParam3d;
+ exitPos = rayBegin + rayDir * exitParam3d;
+
+ // We did enter the flat projection of the AABB,
+ // but we have to check if we intersect it on the vertical axis
+ if (enterPos[1] > chunk.max && exitPos[1] > chunk.max)
+ return;
+ if (enterPos[1] < chunk.min && exitPos[1] < chunk.min)
+ return;
+ }
+ else
+ {
+ // Consider the ray vertical
+ // (though we shouldn't reach this often because there is an early check up-front)
+ enterPos = rayBegin;
+ exitPos = rayEnd;
+ }
+
+ gridRaycast(processTriangles, enterPos, exitPos);
+ // Note: it could be possible to have more than one grid at different levels,
+ // to do this there would be a branch using a pointer to another ProcessVBoundsAction
+ }
+};
+
+
+// TODO How do I interrupt the ray when there is a hit? `callback` does not return any result
+/// Performs a raycast using a hierarchical Bresenham algorithm.
+/// Does not allocate any memory by itself.
+void btHeightfieldTerrainShape::performRaycast(btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget) const
+{
+ // Transform to cell-local
+ btVector3 beginPos = raySource / m_localScaling;
+ btVector3 endPos = rayTarget / m_localScaling;
+ beginPos += m_localOrigin;
+ endPos += m_localOrigin;
+
+ ProcessTrianglesAction processTriangles;
+ processTriangles.shape = this;
+ processTriangles.flipQuadEdges = m_flipQuadEdges;
+ processTriangles.useDiamondSubdivision = m_useDiamondSubdivision;
+ processTriangles.callback = callback;
+ processTriangles.width = m_heightStickWidth - 1;
+ processTriangles.length = m_heightStickLength - 1;
+
+ // TODO Transform vectors to account for m_upAxis
+ int iBeginX = static_cast<int>(floor(beginPos[0]));
+ int iBeginZ = static_cast<int>(floor(beginPos[2]));
+ int iEndX = static_cast<int>(floor(endPos[0]));
+ int iEndZ = static_cast<int>(floor(endPos[2]));
+
+ if (iBeginX == iEndX && iBeginZ == iEndZ)
+ {
+ // The ray will never cross quads within the plane,
+ // so directly process triangles within one quad
+ // (typically, vertical rays should end up here)
+ processTriangles.exec(iBeginX, iEndZ);
+ return;
+ }
+
+ if (m_vboundsGrid == NULL)
+ {
+ // Process all quads intersecting the flat projection of the ray
+ gridRaycast(processTriangles, beginPos, endPos);
+ }
+ else
+ {
+ btVector3 rayDiff = endPos - beginPos;
+ btScalar flatDistance2 = rayDiff[0] * rayDiff[0] + rayDiff[2] * rayDiff[2];
+ if (flatDistance2 < m_vboundsChunkSize * m_vboundsChunkSize)
+ {
+ // Don't use chunks, the ray is too short in the plane
+ gridRaycast(processTriangles, beginPos, endPos);
+ }
+
+ ProcessVBoundsAction processVBounds;
+ processVBounds.width = m_vboundsGridWidth;
+ processVBounds.length = m_vboundsGridLength;
+ processVBounds.vbounds = m_vboundsGrid;
+ processVBounds.rayBegin = beginPos;
+ processVBounds.rayEnd = endPos;
+ processVBounds.rayDir = rayDiff.normalized();
+ processVBounds.processTriangles = processTriangles;
+ processVBounds.chunkSize = m_vboundsChunkSize;
+ // The ray is long, run raycast on a higher-level grid
+ gridRaycast(processVBounds, beginPos / m_vboundsChunkSize, endPos / m_vboundsChunkSize);
+ }
+}
+
+
+/// Builds a grid data structure storing the min and max heights of the terrain in chunks.
+/// if chunkSize is zero, that accelerator is removed.
+/// If you modify the heights, you need to rebuild this accelerator.
+void btHeightfieldTerrainShape::buildAccelerator(int chunkSize)
+{
+ if (chunkSize <= 0)
+ {
+ clearAccelerator();
+ return;
+ }
+
+ m_vboundsChunkSize = chunkSize;
+ int nChunksX = m_heightStickWidth / chunkSize;
+ int nChunksZ = m_heightStickLength / chunkSize;
+
+ if (m_heightStickWidth % chunkSize > 0)
+ ++nChunksX; // In case terrain size isn't dividable by chunk size
+ if (m_heightStickLength % chunkSize > 0)
+ ++nChunksZ;
+
+ if(m_vboundsGridWidth != nChunksX || m_vboundsGridLength != nChunksZ)
+ {
+ clearAccelerator();
+ m_vboundsGridWidth = nChunksX;
+ m_vboundsGridLength = nChunksZ;
+ }
+
+ if (nChunksX == 0 || nChunksZ == 0)
+ return;
+
+ // TODO What is the recommended way to allocate this?
+ // This data structure is only reallocated if the required size changed
+ if (m_vboundsGrid == NULL)
+ m_vboundsGrid = new Range[nChunksX * nChunksZ];
+
+ // Compute min and max height for all chunks
+ for (int cz = 0; cz < nChunksZ; ++cz)
+ {
+ int z0 = cz * chunkSize;
+
+ for (int cx = 0; cx < nChunksX; ++cx)
+ {
+ int x0 = cx * chunkSize;
+
+ Range r;
+
+ r.min = getRawHeightFieldValue(x0, z0);
+ r.max = r.min;
+
+ // Compute min and max height for this chunk.
+ // We have to include one extra cell to account for neighbors.
+ // Here is why:
+ // Say we have a flat terrain, and a plateau that fits a chunk perfectly.
+ //
+ // Left Right
+ // 0---0---0---1---1---1
+ // | | | | | |
+ // 0---0---0---1---1---1
+ // | | | | | |
+ // 0---0---0---1---1---1
+ // x
+ //
+ // If the AABB for the Left chunk did not share vertices with the Right,
+ // then we would fail collision tests at x due to a gap.
+ //
+ for (int z = z0; z < z0 + chunkSize + 1; ++z)
+ {
+ if (z >= m_heightStickLength)
+ continue;
+
+ for (int x = x0; x < x0 + chunkSize + 1; ++x)
+ {
+ if (x >= m_heightStickWidth)
+ continue;
+
+ btScalar height = getRawHeightFieldValue(x, z);
+
+ if (height < r.min)
+ r.min = height;
+ else if (height > r.max)
+ r.max = height;
+ }
+ }
+
+ m_vboundsGrid[cx + cz * nChunksX] = r;
+ }
+ }
+}
+
+
+void btHeightfieldTerrainShape::clearAccelerator()
+{
+ if (m_vboundsGrid)
+ {
+ // TODO What is the recommended way to deallocate this?
+ delete[] m_vboundsGrid;
+ m_vboundsGrid = 0;
+ }
+}
+
+
diff --git a/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h b/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h
index 8a50a57e31..e23b548cb2 100644
--- a/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h
+++ b/thirdparty/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h
@@ -18,6 +18,7 @@ subject to the following restrictions:
#include "btConcaveShape.h"
+
///btHeightfieldTerrainShape simulates a 2D heightfield terrain
/**
The caller is responsible for maintaining the heightfield array; this
@@ -71,6 +72,12 @@ subject to the following restrictions:
ATTRIBUTE_ALIGNED16(class)
btHeightfieldTerrainShape : public btConcaveShape
{
+public:
+ struct Range {
+ btScalar min;
+ btScalar max;
+ };
+
protected:
btVector3 m_localAabbMin;
btVector3 m_localAabbMax;
@@ -100,9 +107,14 @@ protected:
btVector3 m_localScaling;
+ // Accelerator
+ Range *m_vboundsGrid;
+ int m_vboundsGridWidth;
+ int m_vboundsGridLength;
+ int m_vboundsChunkSize;
+
virtual btScalar getRawHeightFieldValue(int x, int y) const;
void quantizeWithClamp(int* out, const btVector3& point, int isMax) const;
- void getVertex(int x, int y, btVector3& vertex) const;
/// protected initialization
/**
@@ -154,6 +166,13 @@ public:
virtual void setLocalScaling(const btVector3& scaling);
virtual const btVector3& getLocalScaling() const;
+
+ void getVertex(int x,int y,btVector3& vertex) const;
+
+ void performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget) const;
+
+ void buildAccelerator(int chunkSize=16);
+ void clearAccelerator();
//debugging
virtual const char* getName() const { return "HEIGHTFIELD"; }