summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/image.cpp151
-rw-r--r--core/image.h1
-rw-r--r--core/io/multiplayer_api.cpp16
-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/Array.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/EditorPlugin.xml1
-rw-r--r--doc/classes/Font.xml10
-rw-r--r--doc/classes/FuncRef.xml6
-rw-r--r--doc/classes/HeightMapShape.xml2
-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/TextEdit.xml3
-rw-r--r--doc/classes/VisualServer.xml22
-rwxr-xr-xdoc/tools/makerst.py15
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp4
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp92
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h2
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp279
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h12
-rw-r--r--drivers/gles2/shaders/scene.glsl42
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp5
-rw-r--r--drivers/gles3/shaders/scene.glsl27
-rw-r--r--editor/code_editor.cpp1
-rw-r--r--editor/editor_node.cpp22
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_settings.cpp6
-rw-r--r--editor/editor_themes.cpp3
-rw-r--r--editor/filesystem_dock.cpp32
-rw-r--r--editor/filesystem_dock.h1
-rw-r--r--editor/icons/icon_GUI_space.svg71
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp27
-rw-r--r--editor/plugins/animation_player_editor_plugin.h1
-rw-r--r--editor/plugins/script_text_editor.cpp5
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp47
-rw-r--r--editor/plugins/theme_editor_plugin.cpp1
-rw-r--r--editor/scene_tree_dock.cpp2
-rw-r--r--editor/script_editor_debugger.cpp20
-rw-r--r--editor/script_editor_debugger.h1
-rw-r--r--editor/spatial_editor_gizmos.cpp6
-rw-r--r--main/tests/test_string.cpp18
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj4
-rw-r--r--modules/bullet/collision_object_bullet.cpp24
-rw-r--r--modules/bullet/collision_object_bullet.h1
-rw-r--r--modules/bullet/rigid_body_bullet.cpp10
-rw-r--r--modules/bullet/shape_bullet.cpp8
-rw-r--r--modules/gdnative/gdnative.cpp2
-rw-r--r--modules/gdnative/gdnative.h4
-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--modules/recast/navigation_mesh_generator.cpp5
-rw-r--r--modules/regex/doc_classes/RegEx.xml2
-rw-r--r--platform/android/detect.py2
-rw-r--r--platform/javascript/os_javascript.cpp2
-rw-r--r--platform/javascript/os_javascript.h2
-rw-r--r--platform/osx/export/export.cpp22
-rw-r--r--platform/uwp/os_uwp.cpp2
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--scene/3d/camera.cpp7
-rw-r--r--scene/3d/collision_shape.cpp4
-rw-r--r--scene/3d/navigation_mesh.cpp24
-rw-r--r--scene/gui/item_list.cpp1
-rw-r--r--scene/gui/line_edit.cpp4
-rw-r--r--scene/gui/text_edit.cpp25
-rw-r--r--scene/gui/text_edit.h4
-rw-r--r--scene/resources/default_theme/default_theme.cpp1
-rw-r--r--scene/resources/default_theme/space.pngbin0 -> 122 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h4
-rw-r--r--scene/resources/height_map_shape.cpp48
-rw-r--r--scene/resources/texture.cpp17
-rw-r--r--servers/audio/effects/audio_effect_record.cpp4
-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
-rw-r--r--thirdparty/glad/glad.c24
-rw-r--r--thirdparty/glad/glad/glad.h29
89 files changed, 1630 insertions, 455 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/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index f6a1cd7616..2779837190 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -634,7 +634,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED);
int node_id = network_peer->get_unique_id();
- bool skip_rpc = false;
+ bool skip_rpc = node_id == p_peer_id;
bool call_local_native = false;
bool call_local_script = false;
bool is_master = p_node->is_network_master();
@@ -688,6 +688,9 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
return;
}
}
+
+ ERR_EXPLAIN("RPC '" + p_method + "' on yourself is not allowed by selected mode");
+ ERR_FAIL_COND(skip_rpc && !(call_local_native || call_local_script));
}
void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
@@ -701,13 +704,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
int node_id = network_peer->get_unique_id();
bool is_master = p_node->is_network_master();
- bool skip_rset = false;
+ bool skip_rset = node_id == p_peer_id;
+ bool set_local = false;
if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) {
// Check that send mode can use local call.
-
- bool set_local = false;
-
const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_property);
if (E) {
@@ -749,8 +750,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
}
- if (skip_rset)
+ if (skip_rset) {
+ ERR_EXPLAIN("RSET for '" + p_property + "' on yourself is not allowed by selected mode");
+ ERR_FAIL_COND(!set_local);
return;
+ }
const Variant *vptr = &p_value;
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/Array.xml b/doc/classes/Array.xml
index ecafc3514c..75194fbf76 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -291,7 +291,7 @@
</method>
<method name="shuffle">
<description>
- Shuffles the array such that the items will have a random order.
+ Shuffles the array such that the items will have a random order. This method uses the global random number generator common to methods such as [method @GDScript.randi]. Call [method @GDScript.randomize] to ensure that a new seed will be used each time if you want non-reproducible shuffling.
</description>
</method>
<method name="size">
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/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 7981c90f86..5763d26561 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -471,6 +471,7 @@
<return type="int">
</return>
<description>
+ Updates the overlays of the editor (2D/3D) viewport.
</description>
</method>
</methods>
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/HeightMapShape.xml b/doc/classes/HeightMapShape.xml
index 5ffeda1c10..22896535b9 100644
--- a/doc/classes/HeightMapShape.xml
+++ b/doc/classes/HeightMapShape.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="HeightMapShape" inherits="Shape" category="Core" version="3.2">
<brief_description>
- Height map shape for 3D physics (bullet only)
+ Height map shape for 3D physics (Bullet only).
</brief_description>
<description>
Height map shape resource, which can be added to a [PhysicsBody] or [Area].
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/TextEdit.xml b/doc/classes/TextEdit.xml
index 0210815d75..dd0461f4db 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -385,6 +385,9 @@
<member name="draw_tabs" type="bool" setter="set_draw_tabs" getter="is_drawing_tabs">
If [code]true[/code], the "tab" character will have a visible representation.
</member>
+ <member name="draw_spaces" type="bool" setter="set_draw_spaces" getter="is_drawing_spaces">
+ If [code]true[/code], the "space" character will have a visible representation.
+ </member>
<member name="fold_gutter" type="bool" setter="set_fold_gutter_enabled" getter="is_fold_gutter_enabled">
If [code]true[/code], the fold gutter is visible. This enables folding groups of indented lines.
</member>
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_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index d3c6b041a8..f49f52e47b 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -202,6 +202,10 @@ Error RasterizerGLES2::is_viable() {
return ERR_UNAVAILABLE;
}
}
+
+ if (GLAD_GL_EXT_framebuffer_multisample) {
+ glRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT;
+ }
#endif // GLES_OVER_GL
#endif // GLAD_ENABLED
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 99eb0665d6..3b3fbf9ed5 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -42,6 +42,16 @@
#define glClearDepth glClearDepthf
#endif
+#ifndef GLES_OVER_GL
+#ifdef IPHONE_ENABLED
+#include <OpenGLES/ES2/glext.h>
+//void *glResolveMultisampleFramebufferAPPLE;
+
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+#endif
+
static const GLenum _cube_side_enum[6] = {
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
@@ -1148,6 +1158,30 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
}
}
+void RasterizerSceneGLES2::_copy_texture_to_front_buffer(GLuint p_texture) {
+
+ //copy to front buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL);
+ glColorMask(1, 1, 1, 1);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, p_texture);
+
+ glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
+
+ storage->shaders.copy.bind();
+
+ storage->bind_quad_array();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass) {
render_pass++;
@@ -2435,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);
@@ -2442,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);
@@ -2544,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);
}
@@ -2689,7 +2724,11 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (storage->frame.current_rt->external.fbo != 0) {
current_fb = storage->frame.current_rt->external.fbo;
} else {
- current_fb = storage->frame.current_rt->fbo;
+ if (storage->frame.current_rt->multisample_active) {
+ current_fb = storage->frame.current_rt->multisample_fbo;
+ } else {
+ current_fb = storage->frame.current_rt->fbo;
+ }
}
env = environment_owner.getornull(p_environment);
@@ -2791,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);
@@ -2830,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
@@ -2838,7 +2879,38 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (storage->frame.current_rt && state.used_screen_texture) {
//copy screen texture
+
+ if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) {
+ // Resolve framebuffer to front buffer before copying
+#ifdef GLES_OVER_GL
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+#elif IPHONE_ENABLED
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glResolveMultisampleFramebufferAPPLE();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+#else
+ // In GLES2 Blit is not available, so just copy color texture manually
+ _copy_texture_to_front_buffer(storage->frame.current_rt->multisample_color);
+#endif
+ }
+
storage->canvas->_copy_screen(Rect2());
+
+ if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) {
+ // Rebind the current framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, current_fb);
+ glViewport(0, 0, viewport_width, viewport_height);
+ }
}
// alpha pass
@@ -2851,6 +2923,22 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glDisable(GL_DEPTH_TEST);
+ if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) {
+#ifdef GLES_OVER_GL
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+#else
+ // In GLES2 Blit is not available, so just copy color texture manually
+ _copy_texture_to_front_buffer(storage->frame.current_rt->multisample_color);
+#endif
+ }
+
//#define GLES2_SHADOW_ATLAS_DEBUG_VIEW
#ifdef GLES2_SHADOW_ATLAS_DEBUG_VIEW
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index 48672991d1..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;
@@ -670,6 +671,7 @@ public:
void _add_geometry(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass);
void _add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass);
+ void _copy_texture_to_front_buffer(GLuint texture);
void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass);
void _render_render_list(RenderList::Element **p_elements, int p_element_count,
const Transform &p_view_transform,
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 13fdd1db73..d709056709 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -81,6 +81,28 @@ GLuint RasterizerStorageGLES2::system_fbo = 0;
#define _DEPTH_COMPONENT24_OES 0x81A6
+#ifndef GLES_OVER_GL
+// enable extensions manually for android and ios
+#include <dlfcn.h> // needed to load extensions
+
+#ifdef IPHONE_ENABLED
+
+#include <OpenGLES/ES2/glext.h>
+//void *glRenderbufferStorageMultisampleAPPLE;
+//void *glResolveMultisampleFramebufferAPPLE;
+#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE
+#else
+
+#include <GLES2/gl2ext.h>
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
+PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT;
+#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT
+#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT
+#endif
+
+#define GL_MAX_SAMPLES 0x8D57
+#endif //!GLES_OVER_GL
+
void RasterizerStorageGLES2::bind_quad_array() const {
glBindBuffer(GL_ARRAY_BUFFER, resources.quadie);
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
@@ -774,10 +796,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
for (int i = 0; i < texture->mipmaps; i++) {
- int ofs = 0;
- if (i > 0) {
- ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1);
- }
+ int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i);
if (texture->compressed) {
glPixelStorei(GL_PACK_ALIGNMENT, 4);
@@ -4552,95 +4571,174 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
if (rt->width <= 0 || rt->height <= 0)
return;
- Texture *texture = texture_owner.getornull(rt->texture);
- ERR_FAIL_COND(!texture);
-
- // create fbo
-
- glGenFramebuffers(1, &rt->fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
-
- // color
-
- glGenTextures(1, &rt->color);
- glBindTexture(GL_TEXTURE_2D, rt->color);
+ GLuint color_internal_format;
+ GLuint color_format;
+ GLuint color_type = GL_UNSIGNED_BYTE;
if (rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ color_internal_format = GL_RGBA;
+ color_format = GL_RGBA;
} else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->width, rt->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ color_internal_format = GL_RGB;
+ color_format = GL_RGB;
}
- if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+ {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- } else {
+ /* Front FBO */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- }
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ Texture *texture = texture_owner.getornull(rt->texture);
+ ERR_FAIL_COND(!texture);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ // framebuffer
+ glGenFramebuffers(1, &rt->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
- // depth
+ // color
+ glGenTextures(1, &rt->color);
+ glBindTexture(GL_TEXTURE_2D, rt->color);
- if (config.support_depth_texture) {
- glGenTextures(1, &rt->depth);
- glBindTexture(GL_TEXTURE_2D, rt->depth);
- glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
- } else {
- glGenRenderbuffers(1, &rt->depth);
- glBindRenderbuffer(GL_RENDERBUFFER, rt->depth);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
- glRenderbufferStorage(GL_RENDERBUFFER, config.depth_internalformat, rt->width, rt->height);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
- }
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
- if (status != GL_FRAMEBUFFER_COMPLETE) {
+ // depth
- glDeleteFramebuffers(1, &rt->fbo);
if (config.support_depth_texture) {
- glDeleteTextures(1, &rt->depth);
+
+ glGenTextures(1, &rt->depth);
+ glBindTexture(GL_TEXTURE_2D, rt->depth);
+ glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
} else {
- glDeleteRenderbuffers(1, &rt->depth);
+
+ glGenRenderbuffers(1, &rt->depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, rt->depth);
+
+ glRenderbufferStorage(GL_RENDERBUFFER, config.depth_internalformat, rt->width, rt->height);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
}
- glDeleteTextures(1, &rt->color);
- rt->fbo = 0;
- rt->width = 0;
- rt->height = 0;
- rt->color = 0;
- rt->depth = 0;
- texture->tex_id = 0;
- texture->active = false;
- WARN_PRINT("Could not create framebuffer!!");
- return;
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+
+ glDeleteFramebuffers(1, &rt->fbo);
+ if (config.support_depth_texture) {
+
+ glDeleteTextures(1, &rt->depth);
+ } else {
+
+ glDeleteRenderbuffers(1, &rt->depth);
+ }
+
+ glDeleteTextures(1, &rt->color);
+ rt->fbo = 0;
+ rt->width = 0;
+ rt->height = 0;
+ rt->color = 0;
+ rt->depth = 0;
+ texture->tex_id = 0;
+ texture->active = false;
+ WARN_PRINT("Could not create framebuffer!!");
+ return;
+ }
+
+ texture->format = Image::FORMAT_RGBA8;
+ texture->gl_format_cache = GL_RGBA;
+ texture->gl_type_cache = GL_UNSIGNED_BYTE;
+ texture->gl_internal_format_cache = GL_RGBA;
+ texture->tex_id = rt->color;
+ texture->width = rt->width;
+ texture->alloc_width = rt->width;
+ texture->height = rt->height;
+ texture->alloc_height = rt->height;
+ texture->active = true;
+
+ texture_set_flags(rt->texture, texture->flags);
}
- texture->format = Image::FORMAT_RGBA8;
- texture->gl_format_cache = GL_RGBA;
- texture->gl_type_cache = GL_UNSIGNED_BYTE;
- texture->gl_internal_format_cache = GL_RGBA;
- texture->tex_id = rt->color;
- texture->width = rt->width;
- texture->alloc_width = rt->width;
- texture->height = rt->height;
- texture->alloc_height = rt->height;
- texture->active = true;
+ /* BACK FBO */
+ /* For MSAA */
+
+ if (rt->msaa != VS::VIEWPORT_MSAA_DISABLED && config.multisample_supported) {
+
+ rt->multisample_active = true;
+
+ static const int msaa_value[] = { 0, 2, 4, 8, 16 };
+ int msaa = msaa_value[rt->msaa];
+
+ int max_samples = 0;
+ glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
+ if (msaa > max_samples) {
+ WARN_PRINTS("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples));
+ msaa = max_samples;
+ }
- texture_set_flags(rt->texture, texture->flags);
+ //regular fbo
+ glGenFramebuffers(1, &rt->multisample_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->multisample_fbo);
+
+ glGenRenderbuffers(1, &rt->multisample_depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_depth);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_internalformat, rt->width, rt->height);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->multisample_depth);
+
+#if defined(GLES_OVER_GL) || defined(IPHONE_ENABLED)
+
+ glGenRenderbuffers(1, &rt->multisample_color);
+ glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_color);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color);
+#else
+ // Render to a texture in android
+ glGenTextures(1, &rt->multisample_color);
+ glBindTexture(GL_TEXTURE_2D, rt->multisample_color);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL);
+
+ // multisample buffer is same size as front buffer, so just use nearest
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glFramebufferTexture2DMultisample(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0, msaa);
+#endif
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("err status: %x\n", status);
+ _render_target_clear(rt);
+ ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
+ }
+
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ } else {
+ rt->multisample_active = false;
+ }
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -4669,7 +4767,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
- status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
_render_target_clear(rt);
ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
@@ -4728,6 +4826,20 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) {
glDeleteTextures(1, &rt->copy_screen_effect.color);
rt->copy_screen_effect.color = 0;
}
+
+ if (rt->multisample_active) {
+ glDeleteFramebuffers(1, &rt->multisample_fbo);
+ rt->multisample_fbo = 0;
+
+ glDeleteRenderbuffers(1, &rt->multisample_depth);
+ rt->multisample_depth = 0;
+#ifdef GLES_OVER_GL
+ glDeleteRenderbuffers(1, &rt->multisample_color);
+#else
+ glDeleteTextures(1, &rt->multisample_color);
+#endif
+ rt->multisample_color = 0;
+ }
}
RID RasterizerStorageGLES2::render_target_create() {
@@ -4929,6 +5041,11 @@ void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, VS::Vie
if (rt->msaa == p_msaa)
return;
+ if (!config.multisample_supported) {
+ ERR_PRINT("MSAA not supported on this hardware.");
+ return;
+ }
+
_render_target_clear(rt);
rt->msaa = p_msaa;
_render_target_allocate(rt);
@@ -5452,6 +5569,26 @@ void RasterizerStorageGLES2::initialize() {
config.support_npot_repeat_mipmap = config.extensions.has("GL_OES_texture_npot");
#endif
+
+#ifndef GLES_OVER_GL
+ //Manually load extensions for android and ios
+
+#ifdef IPHONE_ENABLED
+
+ //void *gles2_lib = dlopen(NULL, RTLD_LAZY);
+ //glRenderbufferStorageMultisampleAPPLE = dlsym(gles2_lib, "glRenderbufferStorageMultisampleAPPLE");
+ //glResolveMultisampleFramebufferAPPLE = dlsym(gles2_lib, "glResolveMultisampleFramebufferAPPLE");
+#else
+
+ void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY);
+ glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT");
+ glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glFramebufferTexture2DMultisampleEXT");
+#endif
+#endif
+
+ // Check for multisample support
+ config.multisample_supported = config.extensions.has("GL_EXT_framebuffer_multisample") || config.extensions.has("GL_EXT_multisampled_render_to_texture") || config.extensions.has("GL_APPLE_framebuffer_multisample");
+
#ifdef GLES_OVER_GL
config.use_rgba_2d_shadows = false;
config.support_depth_texture = true;
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index d6130849fb..3134082e2a 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -92,6 +92,8 @@ public:
bool support_shadow_cubemaps;
+ bool multisample_supported;
+
GLuint depth_internalformat;
GLuint depth_type;
@@ -1132,10 +1134,14 @@ public:
struct RenderTarget : public RID_Data {
GLuint fbo;
-
GLuint color;
GLuint depth;
+ GLuint multisample_fbo;
+ GLuint multisample_color;
+ GLuint multisample_depth;
+ bool multisample_active;
+
// TODO post processing effects?
// TODO HDR?
@@ -1182,6 +1188,10 @@ public:
fbo(0),
color(0),
depth(0),
+ multisample_fbo(0),
+ multisample_color(0),
+ multisample_depth(0),
+ multisample_active(false),
width(0),
height(0),
used_in_frame(false),
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 1c35b455c4..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;
@@ -1699,6 +1716,8 @@ FRAGMENT_SHADER_CODE
#endif
+#if !defined(SHADOWS_DISABLED)
+
#ifdef USE_SHADOW
{
highp vec4 splane = shadow_coord;
@@ -1729,6 +1748,8 @@ FRAGMENT_SHADER_CODE
}
#endif
+#endif //SHADOWS_DISABLED
+
#endif //type omni
#ifdef LIGHT_MODE_DIRECTIONAL
@@ -1739,6 +1760,8 @@ FRAGMENT_SHADER_CODE
#endif
float depth_z = -vertex.z;
+#if !defined(SHADOWS_DISABLED)
+
#ifdef USE_SHADOW
#ifdef USE_VERTEX_LIGHTING
@@ -1957,6 +1980,8 @@ FRAGMENT_SHADER_CODE
#endif //use shadow
+#endif // SHADOWS_DISABLED
+
#endif
#ifdef LIGHT_MODE_SPOT
@@ -1993,6 +2018,8 @@ FRAGMENT_SHADER_CODE
#endif
+#if !defined(SHADOWS_DISABLED)
+
#ifdef USE_SHADOW
{
highp vec4 splane = shadow_coord;
@@ -2002,6 +2029,8 @@ FRAGMENT_SHADER_CODE
}
#endif
+#endif // SHADOWS_DISABLED
+
#endif // LIGHT_MODE_SPOT
#ifdef USE_VERTEX_LIGHTING
@@ -2065,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/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 95d4bec611..661be28e6b 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -1210,10 +1210,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer)
for (int i = 0; i < texture->mipmaps; i++) {
- int ofs = 0;
- if (i > 0) {
- ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1);
- }
+ int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i);
if (texture->compressed) {
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/code_editor.cpp b/editor/code_editor.cpp
index ec984e480a..7fd7b8dac3 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -755,6 +755,7 @@ void CodeTextEditor::update_editor_settings() {
text_editor->set_indent_size(EditorSettings::get_singleton()->get("text_editor/indent/size"));
text_editor->set_auto_indent(EditorSettings::get_singleton()->get("text_editor/indent/auto_indent"));
text_editor->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/indent/draw_tabs"));
+ text_editor->set_draw_spaces(EditorSettings::get_singleton()->get("text_editor/indent/draw_spaces"));
text_editor->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_line_numbers"));
text_editor->set_line_numbers_zero_padded(EditorSettings::get_singleton()->get("text_editor/line_numbers/line_numbers_zero_padded"));
text_editor->set_show_line_length_guideline(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_line_length_guideline"));
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 23d1f25641..907d43b26f 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);
@@ -1956,6 +1955,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
_scene_tab_closed(editor_data.get_edited_scene());
}
+ if (p_confirmed)
+ _menu_option_confirm(SCENE_TAB_CLOSE, true);
+
} break;
case FILE_CLOSE_ALL_AND_QUIT:
case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
@@ -2288,10 +2290,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
project_settings->popup_project_settings();
} break;
- case RUN_PROJECT_DATA_FOLDER: {
-
- OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir());
- } break;
case FILE_INSTALL_ANDROID_SOURCE: {
if (p_confirmed) {
@@ -2528,6 +2526,9 @@ void EditorNode::_tool_menu_option(int p_idx) {
case TOOLS_ORPHAN_RESOURCES: {
orphan_resources->show();
} break;
+ case RUN_PROJECT_DATA_FOLDER: {
+ OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir());
+ } break;
case TOOLS_CUSTOM: {
if (tool_menu->get_item_submenu(p_idx) == "") {
Array params = tool_menu->get_item_metadata(p_idx);
@@ -3250,6 +3251,12 @@ InspectorDock *EditorNode::get_inspector_dock() {
return inspector_dock;
}
+void EditorNode::_inherit_request(String p_file) {
+
+ current_option = FILE_NEW_INHERITED_SCENE;
+ _dialog_action(p_file);
+}
+
void EditorNode::_instance_request(const Vector<String> &p_files) {
request_instance_scenes(p_files);
@@ -5023,6 +5030,7 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("_get_scene_metadata", &EditorNode::_get_scene_metadata);
ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene);
ClassDB::bind_method("open_request", &EditorNode::open_request);
+ ClassDB::bind_method("_inherit_request", &EditorNode::_inherit_request);
ClassDB::bind_method("_instance_request", &EditorNode::_instance_request);
ClassDB::bind_method("_close_messages", &EditorNode::_close_messages);
ClassDB::bind_method("_show_messages", &EditorNode::_show_messages);
@@ -5990,7 +5998,7 @@ 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_node.h b/editor/editor_node.h
index 0084d421f9..cfe8bf9ec4 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -474,6 +474,7 @@ private:
int _next_unsaved_scene(bool p_valid_filename, int p_start = 0);
void _discard_changes(const String &p_str = String());
+ void _inherit_request(String p_file);
void _instance_request(const Vector<String> &p_files);
void _display_top_editors(bool p_display);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index e80d3e1b37..193b2b7a88 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -425,6 +425,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/indent/auto_indent", true);
_initial_set("text_editor/indent/convert_indent_on_save", false);
_initial_set("text_editor/indent/draw_tabs", true);
+ _initial_set("text_editor/indent/draw_spaces", false);
// Line numbers
_initial_set("text_editor/line_numbers/show_line_numbers", true);
@@ -651,7 +652,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 +974,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..ba4dd9d7e2 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -833,6 +833,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("read_only", "TextEdit", style_widget_disabled);
theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons"));
+ theme->set_icon("space", "TextEdit", theme->get_icon("GuiSpace", "EditorIcons"));
theme->set_icon("folded", "TextEdit", theme->get_icon("GuiTreeArrowRight", "EditorIcons"));
theme->set_icon("fold", "TextEdit", theme->get_icon("GuiTreeArrowDown", "EditorIcons"));
theme->set_color("font_color", "TextEdit", font_color);
@@ -1121,7 +1122,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/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 6248680a52..5ce22154e0 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -462,6 +462,7 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa
_update_tree(_compute_uncollapsed_paths(), false, p_select_in_favorites);
if (display_mode == DISPLAY_MODE_SPLIT) {
_update_file_list(false);
+ files->get_v_scroll()->set_value(0);
}
String file_name = p_path.get_file();
@@ -1489,12 +1490,28 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> p_selected)
} break;
case FILE_OPEN: {
+ // Open folders
+ TreeItem *selected = tree->get_root();
+ selected = tree->get_next_selected(selected);
+ while (selected) {
+ if (p_selected.find(selected->get_metadata(0)) >= 0) {
+ selected->set_collapsed(false);
+ }
+ selected = tree->get_next_selected(selected);
+ }
// Open the file
for (int i = 0; i < p_selected.size(); i++) {
_select_file(p_selected[i]);
}
} break;
+ case FILE_INHERIT: {
+ // Create a new scene inherited from the selected one
+ if (p_selected.size() == 1) {
+ emit_signal("inherit", p_selected[0]);
+ }
+ } break;
+
case FILE_INSTANCE: {
// Instance all selected scenes
Vector<String> paths;
@@ -2061,13 +2078,16 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
if (all_files) {
- if (all_files_scenes && filenames.size() >= 1) {
- p_popup->add_item(TTR("Open Scene(s)"), FILE_OPEN);
+ if (all_files_scenes) {
+ if (filenames.size() == 1) {
+ p_popup->add_item(TTR("Open Scene"), FILE_OPEN);
+ p_popup->add_item(TTR("New Inherited Scene"), FILE_INHERIT);
+ } else {
+ p_popup->add_item(TTR("Open Scenes"), FILE_OPEN);
+ }
p_popup->add_item(TTR("Instance"), FILE_INSTANCE);
p_popup->add_separator();
- }
-
- if (!all_files_scenes && filenames.size() == 1) {
+ } else if (filenames.size() == 1) {
p_popup->add_item(TTR("Open"), FILE_OPEN);
p_popup->add_separator();
}
@@ -2368,8 +2388,8 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_feature_profile_changed"), &FileSystemDock::_feature_profile_changed);
+ ADD_SIGNAL(MethodInfo("inherit", PropertyInfo(Variant::STRING, "file")));
ADD_SIGNAL(MethodInfo("instance", PropertyInfo(Variant::POOL_STRING_ARRAY, "files")));
- ADD_SIGNAL(MethodInfo("open"));
ADD_SIGNAL(MethodInfo("file_removed", PropertyInfo(Variant::STRING, "file")));
ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder")));
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 8b27938c8a..9d20544ac2 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -73,6 +73,7 @@ public:
private:
enum FileMenu {
FILE_OPEN,
+ FILE_INHERIT,
FILE_INSTANCE,
FILE_ADD_FAVORITE,
FILE_REMOVE_FAVORITE,
diff --git a/editor/icons/icon_GUI_space.svg b/editor/icons/icon_GUI_space.svg
new file mode 100644
index 0000000000..caa4565f4a
--- /dev/null
+++ b/editor/icons/icon_GUI_space.svg
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="8"
+ height="8"
+ version="1.1"
+ viewBox="0 0 8 7.9999993"
+ id="svg98"
+ sodipodi:docname="icon_GUI_space.svg"
+ inkscape:version="0.92.4 (unknown)">
+ <metadata
+ id="metadata104">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs102">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 3.9999996 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="8 : 3.9999996 : 1"
+ inkscape:persp3d-origin="4 : 2.6666664 : 1"
+ id="perspective992" />
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1853"
+ inkscape:window-height="1025"
+ id="namedview100"
+ showgrid="false"
+ inkscape:zoom="70.333333"
+ inkscape:cx="3.4905213"
+ inkscape:cy="6"
+ inkscape:window-x="67"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg98"
+ inkscape:pagecheckerboard="true" />
+ <g
+ transform="matrix(0.5,0,0,-0.5,1,527.20001)"
+ id="g96"
+ style="fill:#ffffff;fill-opacity:0.19607843">
+ <circle
+ cx="6"
+ cy="1046.4"
+ r="3"
+ id="circle94"
+ style="fill:#ffffff;fill-opacity:0.19607843" />
+ </g>
+</svg>
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 7c075b5635..0a9436952b 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -129,8 +129,10 @@ void AnimationPlayerEditor::_notification(int p_what) {
autoplay_icon = get_icon("AutoPlay", "EditorIcons");
stop->set_icon(get_icon("Stop", "EditorIcons"));
+ onion_toggle->set_icon(get_icon("Onion", "EditorIcons"));
+ onion_skinning->set_icon(get_icon("GuiMiniTabMenu", "EditorIcons"));
+
pin->set_icon(get_icon("Pin", "EditorIcons"));
- onion_skinning->set_icon(get_icon("Onion", "EditorIcons"));
tool_anim->add_style_override("normal", get_stylebox("normal", "Button"));
track_editor->get_edit_menu()->add_style_override("normal", get_stylebox("normal", "Button"));
@@ -1229,7 +1231,6 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) {
case ONION_SKINNING_ENABLE: {
onion.enabled = !onion.enabled;
- menu->set_item_checked(idx, onion.enabled);
if (onion.enabled)
_start_onion_skinning();
@@ -1708,19 +1709,21 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
hb->add_child(track_editor->get_edit_menu());
+ hb->add_child(memnew(VSeparator));
+
+ onion_toggle = memnew(ToolButton);
+ onion_toggle->set_toggle_mode(true);
+ onion_toggle->set_tooltip(TTR("Enable Onion Skinning"));
+ onion_toggle->connect("pressed", this, "_onion_skinning_menu", varray(ONION_SKINNING_ENABLE));
+ hb->add_child(onion_toggle);
+
onion_skinning = memnew(MenuButton);
- //onion_skinning->set_flat(false);
- onion_skinning->set_tooltip(TTR("Onion Skinning"));
- onion_skinning->get_popup()->add_check_shortcut(ED_SHORTCUT("animation_player_editor/onion_skinning", TTR("Enable Onion Skinning")), ONION_SKINNING_ENABLE);
- onion_skinning->get_popup()->add_separator();
- onion_skinning->get_popup()->add_item(TTR("Directions"), -1);
- onion_skinning->get_popup()->set_item_disabled(onion_skinning->get_popup()->get_item_count() - 1, true);
+ onion_skinning->set_tooltip(TTR("Onion Skinning Options"));
+ onion_skinning->get_popup()->add_separator(TTR("Directions"));
onion_skinning->get_popup()->add_check_item(TTR("Past"), ONION_SKINNING_PAST);
onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true);
onion_skinning->get_popup()->add_check_item(TTR("Future"), ONION_SKINNING_FUTURE);
- onion_skinning->get_popup()->add_separator();
- onion_skinning->get_popup()->add_item(TTR("Depth"), -1);
- onion_skinning->get_popup()->set_item_disabled(onion_skinning->get_popup()->get_item_count() - 1, true);
+ onion_skinning->get_popup()->add_separator(TTR("Depth"));
onion_skinning->get_popup()->add_radio_check_item(TTR("1 step"), ONION_SKINNING_1_STEP);
onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true);
onion_skinning->get_popup()->add_radio_check_item(TTR("2 steps"), ONION_SKINNING_2_STEPS);
@@ -1731,6 +1734,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
onion_skinning->get_popup()->add_check_item(TTR("Include Gizmos (3D)"), ONION_SKINNING_INCLUDE_GIZMOS);
hb->add_child(onion_skinning);
+ hb->add_child(memnew(VSeparator));
+
pin = memnew(ToolButton);
pin->set_toggle_mode(true);
pin->set_tooltip(TTR("Pin AnimationPlayer"));
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 9085c70410..c6ab6c5e30 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -102,6 +102,7 @@ class AnimationPlayerEditor : public VBoxContainer {
Button *autoplay;
MenuButton *tool_anim;
+ ToolButton *onion_toggle;
MenuButton *onion_skinning;
ToolButton *pin;
SpinBox *frame;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index d40e67cc8c..eaba48fa05 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1266,7 +1266,8 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_
Dictionary d = p_data;
if (d.has("type") && (String(d["type"]) == "resource" ||
String(d["type"]) == "files" ||
- String(d["type"]) == "nodes")) {
+ String(d["type"]) == "nodes" ||
+ String(d["type"]) == "files_and_dirs")) {
return true;
}
@@ -1328,7 +1329,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
te->insert_text_at_cursor(res->get_path());
}
- if (d.has("type") && String(d["type"]) == "files") {
+ if (d.has("type") && (String(d["type"]) == "files" || String(d["type"]) == "files_and_dirs")) {
Array files = d["files"];
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 6edd19901b..c509202a88 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -51,32 +51,42 @@ void SpriteFramesEditor::_open_sprite_sheet() {
}
void SpriteFramesEditor::_sheet_preview_draw() {
+
Size2i size = split_sheet_preview->get_size();
int h = split_sheet_h->get_value();
int v = split_sheet_v->get_value();
+ int width = size.width / h;
+ int height = size.height / v;
const float a = 0.3;
for (int i = 1; i < h; i++) {
- for (int j = 1; j < v; j++) {
- int x = i * size.width / h;
- int y = j * size.height / v;
+ int x = i * width;
+ split_sheet_preview->draw_line(Point2(x, 0), Point2(x, size.height), Color(1, 1, 1, a));
+ split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, size.height), Color(0, 0, 0, a));
- split_sheet_preview->draw_line(Point2(x, 0), Point2(x, size.height), Color(1, 1, 1, a));
- split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, size.height), Color(0, 0, 0, a));
+ for (int j = 1; j < v; j++) {
+
+ int y = j * height;
split_sheet_preview->draw_line(Point2(0, y), Point2(size.width, y), Color(1, 1, 1, a));
split_sheet_preview->draw_line(Point2(0, y + 1), Point2(size.width, y + 1), Color(0, 0, 0, a));
}
}
+ if (frames_selected.size() == 0) {
+ split_sheet_dialog->get_ok()->set_disabled(true);
+ split_sheet_dialog->get_ok()->set_text(TTR("No Frames Selected"));
+ return;
+ }
+
Color accent = get_color("accent_color", "Editor");
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
int idx = E->get();
- int x = (idx % h) * size.width / h;
- int y = (idx / v) * size.height / v;
- int width = size.width / h;
- int height = size.height / v;
+ int xp = idx % h;
+ int yp = (idx - xp) / h;
+ int x = xp * width;
+ int y = yp * height;
split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 0.35), true);
split_sheet_preview->draw_rect(Rect2(x + 0, y + 0, width - 0, height - 0), Color(0, 0, 0, 1), false);
@@ -87,13 +97,8 @@ void SpriteFramesEditor::_sheet_preview_draw() {
split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 1), false);
}
- if (frames_selected.size() == 0) {
- split_sheet_dialog->get_ok()->set_disabled(true);
- split_sheet_dialog->get_ok()->set_text(TTR("No Frames Selected"));
- } else {
- split_sheet_dialog->get_ok()->set_disabled(false);
- split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d Frame(s)"), frames_selected.size()));
- }
+ split_sheet_dialog->get_ok()->set_disabled(false);
+ split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d Frame(s)"), frames_selected.size()));
}
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
@@ -149,10 +154,12 @@ void SpriteFramesEditor::_sheet_add_frames() {
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
int idx = E->get();
- int x = (idx % h) * size.width / h;
- int y = (idx / v) * size.height / v;
int width = size.width / h;
int height = size.height / v;
+ int xp = idx % h;
+ int yp = (idx - xp) / h;
+ int x = xp * width;
+ int y = yp * height;
Ref<AtlasTexture> at;
at.instance();
@@ -456,6 +463,10 @@ void SpriteFramesEditor::_animation_select() {
if (updating)
return;
+ double value = anim_speed->get_line_edit()->get_text().to_double();
+ if (!Math::is_equal_approx(value, frames->get_animation_speed(edited_anim)))
+ _animation_fps_changed(value);
+
TreeItem *selected = animations->get_selected();
ERR_FAIL_COND(!selected);
edited_anim = selected->get_text(0);
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 80e2e99685..85743c96d6 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -683,7 +683,6 @@ ThemeEditor::ThemeEditor() {
CheckButton *cb = memnew(CheckButton);
cb->set_text("CheckButton");
first_vb->add_child(cb);
- cb = memnew(CheckButton);
CheckBox *cbx = memnew(CheckBox);
cbx->set_text("CheckBox");
first_vb->add_child(cbx);
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/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index 1da8bf874c..a661c2cfc3 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -299,6 +299,7 @@ void ScriptEditorDebugger::_scene_tree_rmb_selected(const Vector2 &p_position) {
item_menu->clear();
item_menu->add_icon_item(get_icon("CreateNewSceneFrom", "EditorIcons"), TTR("Save Branch as Scene"), ITEM_MENU_SAVE_REMOTE_NODE);
+ item_menu->add_icon_item(get_icon("CopyNodePath", "EditorIcons"), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH);
item_menu->set_global_position(get_global_mouse_position());
item_menu->popup();
}
@@ -396,6 +397,7 @@ Size2 ScriptEditorDebugger::get_minimum_size() const {
ms.y = MAX(ms.y, 250 * EDSCALE);
return ms;
}
+
void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) {
if (p_msg == "debug_enter") {
@@ -1930,6 +1932,24 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
file_dialog->popup_centered_ratio();
} break;
+ case ITEM_MENU_COPY_NODE_PATH: {
+
+ TreeItem *ti = inspect_scene_tree->get_selected();
+ String text = ti->get_text(0);
+
+ if (ti->get_parent() == NULL) {
+ text = ".";
+ } else if (ti->get_parent()->get_parent() == NULL) {
+ text = ".";
+ } else {
+ while (ti->get_parent()->get_parent() != inspect_scene_tree->get_root()) {
+ ti = ti->get_parent();
+ text = ti->get_text(0) + "/" + text;
+ }
+ }
+
+ OS::get_singleton()->set_clipboard(text);
+ } break;
}
}
diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h
index f7afe6bf72..05dcab0f80 100644
--- a/editor/script_editor_debugger.h
+++ b/editor/script_editor_debugger.h
@@ -66,6 +66,7 @@ class ScriptEditorDebugger : public Control {
enum ItemMenu {
ITEM_MENU_COPY_ERROR,
ITEM_MENU_SAVE_REMOTE_NODE,
+ ITEM_MENU_COPY_NODE_PATH,
};
AcceptDialog *msgdialog;
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index f540b386aa..104bac190e 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -571,9 +571,11 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
Transform orig_camera_transform = p_camera->get_camera_transform();
- if (orig_camera_transform.origin.distance_squared_to(t.origin) > 0.01) {
+ if (orig_camera_transform.origin.distance_squared_to(t.origin) > 0.01 &&
+ ABS(orig_camera_transform.basis.get_axis(Vector3::AXIS_Z).dot(Vector3(0, 1, 0))) < 0.99) {
p_camera->look_at(t.origin, Vector3(0, 1, 0));
}
+
Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale);
Vector3 c1 = t.xform(Vector3(-selectable_icon_size, -selectable_icon_size, 0) * scale);
@@ -582,7 +584,7 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
p_camera->set_global_transform(orig_camera_transform);
- Rect2 rect(p0, p1 - p0);
+ Rect2 rect(p0, (p1 - p0).abs());
rect.set_position(center - rect.get_size() / 2.0);
diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp
index dcbb930d1b..531887a452 100644
--- a/main/tests/test_string.cpp
+++ b/main/tests/test_string.cpp
@@ -33,6 +33,7 @@
//#include "core/math/math_funcs.h"
#include "core/io/ip_address.h"
#include "core/os/os.h"
+#include "modules/regex/regex.h"
#include <stdio.h>
#include "test_string.h"
@@ -429,9 +430,20 @@ bool test_25() {
bool test_26() {
- //TODO: Do replacement RegEx test
- return true;
-};
+ OS::get_singleton()->print("\n\nTest 26: RegEx substitution\n");
+
+ String s = "Double all the vowels.";
+
+ OS::get_singleton()->print("\tString: %ls\n", s.c_str());
+ OS::get_singleton()->print("\tRepeating instances of 'aeiou' once\n");
+
+ RegEx re("(?<vowel>[aeiou])");
+ s = re.sub(s, "$0$vowel", true);
+
+ OS::get_singleton()->print("\tResult: %ls\n", s.c_str());
+
+ return (s == "Doouublee aall thee vooweels.");
+}
struct test_27_data {
char const *data;
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/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index eb87901c24..166d7e6158 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -59,6 +59,25 @@ void CollisionObjectBullet::ShapeWrapper::set_transform(const btTransform &p_tra
transform = p_transform;
}
+btTransform CollisionObjectBullet::ShapeWrapper::get_adjusted_transform() const {
+ if (shape->get_type() == PhysicsServer::SHAPE_HEIGHTMAP) {
+ const HeightMapShapeBullet *hm_shape = (const HeightMapShapeBullet *)shape; // should be safe to cast now
+ btTransform adjusted_transform;
+
+ // Bullet centers our heightmap:
+ // https://github.com/bulletphysics/bullet3/blob/master/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h#L33
+ // This is really counter intuitive so we're adjusting for it
+
+ adjusted_transform.setIdentity();
+ adjusted_transform.setOrigin(btVector3(0.0, hm_shape->min_height + ((hm_shape->max_height - hm_shape->min_height) * 0.5), 0.0));
+ adjusted_transform *= transform;
+
+ return adjusted_transform;
+ } else {
+ return transform;
+ }
+}
+
void CollisionObjectBullet::ShapeWrapper::claim_bt_shape(const btVector3 &body_scale) {
if (!bt_shape) {
if (active)
@@ -345,7 +364,8 @@ void RigidCollisionObjectBullet::reload_shapes() {
// Try to optimize by not using compound
if (1 == shape_count) {
shpWrapper = &shapes.write[0];
- if (shpWrapper->transform.getOrigin().isZero() && shpWrapper->transform.getBasis() == shpWrapper->transform.getBasis().getIdentity()) {
+ btTransform transform = shpWrapper->get_adjusted_transform();
+ if (transform.getOrigin().isZero() && transform.getBasis() == transform.getBasis().getIdentity()) {
shpWrapper->claim_bt_shape(body_scale);
mainShape = shpWrapper->bt_shape;
main_shape_changed();
@@ -359,7 +379,7 @@ void RigidCollisionObjectBullet::reload_shapes() {
for (int i(0); i < shape_count; ++i) {
shpWrapper = &shapes.write[i];
shpWrapper->claim_bt_shape(body_scale);
- btTransform scaled_shape_transform(shpWrapper->transform);
+ btTransform scaled_shape_transform(shpWrapper->get_adjusted_transform());
scaled_shape_transform.getOrigin() *= body_scale;
compoundShape->addChildShape(scaled_shape_transform, shpWrapper->bt_shape);
}
diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h
index e65bc52caf..c9430bec18 100644
--- a/modules/bullet/collision_object_bullet.h
+++ b/modules/bullet/collision_object_bullet.h
@@ -109,6 +109,7 @@ public:
void set_transform(const Transform &p_transform);
void set_transform(const btTransform &p_transform);
+ btTransform get_adjusted_transform() const;
void claim_bt_shape(const btVector3 &body_scale);
};
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.cpp b/modules/gdnative/gdnative.cpp
index e8278825bc..c8e17e8dc5 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -243,7 +243,7 @@ void GDNativeLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_symbol_prefix", "symbol_prefix"), &GDNativeLibrary::set_symbol_prefix);
ClassDB::bind_method(D_METHOD("set_reloadable", "reloadable"), &GDNativeLibrary::set_reloadable);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"), "set_config_file", "get_config_file");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile", 0), "set_config_file", "get_config_file");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton");
diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h
index 492dc5beaa..ef57387059 100644
--- a/modules/gdnative/gdnative.h
+++ b/modules/gdnative/gdnative.h
@@ -99,16 +99,20 @@ public:
}
_FORCE_INLINE_ void set_load_once(bool p_load_once) {
+ config_file->set_value("general", "load_once", p_load_once);
load_once = p_load_once;
}
_FORCE_INLINE_ void set_singleton(bool p_singleton) {
+ config_file->set_value("general", "singleton", p_singleton);
singleton = p_singleton;
}
_FORCE_INLINE_ void set_symbol_prefix(String p_symbol_prefix) {
+ config_file->set_value("general", "symbol_prefix", p_symbol_prefix);
symbol_prefix = p_symbol_prefix;
}
_FORCE_INLINE_ void set_reloadable(bool p_reloadable) {
+ config_file->set_value("general", "reloadable", p_reloadable);
reloadable = p_reloadable;
}
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/modules/recast/navigation_mesh_generator.cpp b/modules/recast/navigation_mesh_generator.cpp
index 80e98a13a5..79ccbbb030 100644
--- a/modules/recast/navigation_mesh_generator.cpp
+++ b/modules/recast/navigation_mesh_generator.cpp
@@ -126,9 +126,10 @@ void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(con
for (unsigned int j = 0; j < ntris; j++) {
Vector<int> nav_indices;
nav_indices.resize(3);
+ // Polygon order in recast is opposite than godot's
nav_indices.write[0] = ((int)(bverts + tris[j * 4 + 0]));
- nav_indices.write[1] = ((int)(bverts + tris[j * 4 + 1]));
- nav_indices.write[2] = ((int)(bverts + tris[j * 4 + 2]));
+ nav_indices.write[1] = ((int)(bverts + tris[j * 4 + 2]));
+ nav_indices.write[2] = ((int)(bverts + tris[j * 4 + 1]));
p_nav_mesh->add_polygon(nav_indices);
}
}
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 0538753a47..cc8205e400 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -123,7 +123,7 @@
<argument index="4" name="end" type="int" default="-1">
</argument>
<description>
- Searches the text for the compiled pattern and replaces it with the specified string. Escapes and backreferences such as [code]\1[/code] and [code]\g&lt;name&gt;[/code] expanded and resolved. By default only the first instance is replaced but it can be changed for all instances (global replacement). The region to search within can be specified without modifying where the start and end anchor would be.
+ Searches the text for the compiled pattern and replaces it with the specified string. Escapes and backreferences such as [code]$1[/code] and [code]$name[/code] are expanded and resolved. By default only the first instance is replaced but it can be changed for all instances (global replacement). The region to search within can be specified without modifying where the start and end anchor would be.
</description>
</method>
</methods>
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 8d35617d20..ea70fefbc5 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -301,7 +301,7 @@ def configure(env):
env.Prepend(CPPPATH=['#platform/android'])
env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL'])
- env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z', 'dl'])
+ env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'GLESv2', 'android', 'log', 'z', 'dl'])
# Return NDK version string in source.properties (adapted from the Chromium project).
def get_ndk_version(path):
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/osx/export/export.cpp b/platform/osx/export/export.cpp
index 89212b0e5e..d0e39d1638 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -121,7 +121,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
@@ -542,11 +542,21 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
iconpath = ProjectSettings::get_singleton()->get("application/config/icon");
if (iconpath != "") {
- Ref<Image> icon;
- icon.instance();
- icon->load(iconpath);
- if (!icon->empty()) {
- _make_icon(icon, data);
+ if (iconpath.get_extension() == "icns") {
+ FileAccess *icon = FileAccess::open(iconpath, FileAccess::READ);
+ if (icon) {
+ data.resize(icon->get_len());
+ icon->get_buffer(&data.write[0], icon->get_len());
+ icon->close();
+ memdelete(icon);
+ }
+ } else {
+ Ref<Image> icon;
+ icon.instance();
+ icon->load(iconpath);
+ if (!icon->empty()) {
+ _make_icon(icon, data);
+ }
}
}
//bleh?
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/3d/camera.cpp b/scene/3d/camera.cpp
index 54d7681a3a..8b91f56344 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -722,8 +722,9 @@ void ClippedCamera::set_process_mode(ProcessMode p_mode) {
if (process_mode == p_mode) {
return;
}
- set_process_internal(p_mode == CLIP_PROCESS_IDLE);
- set_physics_process_internal(p_mode == CLIP_PROCESS_PHYSICS);
+ process_mode = p_mode;
+ set_process_internal(process_mode == CLIP_PROCESS_IDLE);
+ set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS);
}
ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const {
return process_mode;
@@ -786,7 +787,7 @@ void ClippedCamera::_notification(int p_what) {
float csafe, cunsafe;
if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, csafe, cunsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
- clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from).normalized() * csafe);
+ clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * csafe);
}
_update_camera();
diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp
index f32b1398fd..3190e1e0b2 100644
--- a/scene/3d/collision_shape.cpp
+++ b/scene/3d/collision_shape.cpp
@@ -65,7 +65,6 @@ void CollisionShape::make_convex_from_brothers() {
}
void CollisionShape::_update_in_shape_owner(bool p_xform_only) {
-
parent->shape_owner_set_transform(owner_id, get_transform());
if (p_xform_only)
return;
@@ -228,6 +227,9 @@ void CollisionShape::_update_debug_shape() {
}
void CollisionShape::_shape_changed() {
+ // If this is a heightfield shape our center may have changed
+ _update_in_shape_owner(true);
+
if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !debug_shape_dirty) {
debug_shape_dirty = true;
call_deferred("_update_debug_shape");
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 93731c4023..003f76664d 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -410,19 +410,19 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01"), "set_cell_size", "get_cell_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01"), "set_cell_height", "get_cell_height");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/height", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_height", "get_agent_height");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/radius", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_radius", "get_agent_radius");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_climb", PROPERTY_HINT_RANGE, "0.1,5.0,0.01"), "set_agent_max_climb", "get_agent_max_climb");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/height", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_height", "get_agent_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/radius", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_radius", "get_agent_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_climb", PROPERTY_HINT_RANGE, "0.1,5.0,0.01,or_greater"), "set_agent_max_climb", "get_agent_max_climb");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "agent/max_slope", PROPERTY_HINT_RANGE, "0.0,90.0,0.1"), "set_agent_max_slope", "get_agent_max_slope");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01"), "set_region_min_size", "get_region_min_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01"), "set_region_merge_size", "get_region_merge_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01"), "set_edge_max_length", "get_edge_max_length");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01"), "set_edge_max_error", "get_edge_max_error");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0"), "set_verts_per_poly", "get_verts_per_poly");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.0,16.0,0.01"), "set_detail_sample_distance", "get_detail_sample_distance");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01"), "set_detail_sample_max_error", "get_detail_sample_max_error");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater"), "set_edge_max_length", "get_edge_max_length");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater"), "set_edge_max_error", "get_edge_max_error");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_max_error", "get_detail_sample_max_error");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans");
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index f5e979e9e6..026374ded1 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -369,7 +369,6 @@ void ItemList::clear() {
update();
shape_changed = true;
defer_select_single = -1;
- scroll_bar->set_value(0);
}
void ItemList::set_fixed_column_width(int p_size) {
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..71e84e974f 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;
@@ -1255,6 +1252,11 @@ void TextEdit::_notification(int p_what) {
cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color);
}
+ if (draw_spaces && str[j] == ' ') {
+ int yofs = (get_row_height() - cache.space_icon->get_height()) / 2;
+ cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ }
+
char_ofs += char_w;
if (line_wrap_index == line_wrap_amount && j == str.length() - 1 && is_folded(line)) {
@@ -4513,6 +4515,7 @@ void TextEdit::_update_caches() {
#endif
cache.row_height = cache.font->get_height() + cache.line_spacing;
cache.tab_icon = get_icon("tab");
+ cache.space_icon = get_icon("space");
cache.folded_icon = get_icon("folded");
cache.can_fold_icon = get_icon("fold");
cache.folded_eol_icon = get_icon("GuiEllipsis", "EditorIcons");
@@ -5649,6 +5652,16 @@ bool TextEdit::is_drawing_tabs() const {
return draw_tabs;
}
+void TextEdit::set_draw_spaces(bool p_draw) {
+
+ draw_spaces = p_draw;
+}
+
+bool TextEdit::is_drawing_spaces() const {
+
+ return draw_spaces;
+}
+
void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
override_selected_font_color = p_override_selected_font_color;
}
@@ -6382,6 +6395,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled);
ClassDB::bind_method(D_METHOD("set_draw_tabs"), &TextEdit::set_draw_tabs);
ClassDB::bind_method(D_METHOD("is_drawing_tabs"), &TextEdit::is_drawing_tabs);
+ ClassDB::bind_method(D_METHOD("set_draw_spaces"), &TextEdit::set_draw_spaces);
+ ClassDB::bind_method(D_METHOD("is_drawing_spaces"), &TextEdit::is_drawing_spaces);
ClassDB::bind_method(D_METHOD("set_breakpoint_gutter_enabled", "enable"), &TextEdit::set_breakpoint_gutter_enabled);
ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled);
ClassDB::bind_method(D_METHOD("set_draw_fold_gutter"), &TextEdit::set_draw_fold_gutter);
@@ -6433,6 +6448,7 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_tabs"), "set_draw_tabs", "is_drawing_tabs");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_spaces"), "set_draw_spaces", "is_drawing_spaces");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "breakpoint_gutter"), "set_breakpoint_gutter_enabled", "is_breakpoint_gutter_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
@@ -6474,6 +6490,7 @@ TextEdit::TextEdit() {
setting_row = false;
draw_tabs = false;
+ draw_spaces = false;
override_selected_font_color = false;
draw_caret = true;
max_chars = 0;
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 4badd85e07..eb9fb2cf57 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -163,6 +163,7 @@ private:
struct Cache {
Ref<Texture> tab_icon;
+ Ref<Texture> space_icon;
Ref<Texture> can_fold_icon;
Ref<Texture> folded_icon;
Ref<Texture> folded_eol_icon;
@@ -290,6 +291,7 @@ private:
bool first_draw;
bool setting_row;
bool draw_tabs;
+ bool draw_spaces;
bool override_selected_font_color;
bool cursor_changed_dirty;
bool text_changed_dirty;
@@ -613,6 +615,8 @@ public:
int get_indent_size();
void set_draw_tabs(bool p_draw);
bool is_drawing_tabs() const;
+ void set_draw_spaces(bool p_draw);
+ bool is_drawing_spaces() const;
void set_override_selected_font_color(bool p_override_selected_font_color);
bool is_overriding_selected_font_color() const;
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index b3bd3f47e6..0b88763300 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -425,6 +425,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_icon("tab", "TextEdit", make_icon(tab_png));
+ theme->set_icon("space", "TextEdit", make_icon(space_png));
theme->set_icon("folded", "TextEdit", make_icon(arrow_right_png));
theme->set_icon("fold", "TextEdit", make_icon(arrow_down_png));
diff --git a/scene/resources/default_theme/space.png b/scene/resources/default_theme/space.png
new file mode 100644
index 0000000000..7e458a6c45
--- /dev/null
+++ b/scene/resources/default_theme/space.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index a09b811b37..87b8afd6a3 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -358,6 +358,10 @@ static const unsigned char selection_oof_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x2, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xaf, 0xdf, 0x90, 0xa5, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0x3, 0x20, 0x25, 0x16, 0xc, 0x1f, 0x74, 0xbf, 0x74, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x2f, 0x33, 0x4, 0x32, 0xde, 0xce, 0x64, 0xf4, 0x68, 0x53, 0x0, 0x32, 0xfe, 0xcd, 0xa0, 0x90, 0x1, 0x37, 0x10, 0x6e, 0x5, 0xdc, 0x52, 0xb8, 0x33, 0x0, 0xcc, 0x7, 0x26, 0xff, 0x1f, 0x38, 0x23, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char space_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc4, 0xf, 0xbe, 0x8b, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x63, 0x60, 0xa0, 0x2a, 0xf8, 0xff, 0xff, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0x5, 0x91, 0xc5, 0x58, 0x90, 0x24, 0x85, 0x18, 0x18, 0x18, 0x14, 0xa0, 0x6c, 0x6, 0x46, 0x46, 0xc6, 0xf7, 0xc, 0xc, 0xc, 0xc, 0x4c, 0x14, 0x5b, 0x41, 0x39, 0x0, 0x0, 0x71, 0x1a, 0x13, 0x5d, 0x87, 0xfe, 0x9e, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char spinbox_updown_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0xdc, 0x4f, 0x7f, 0x98, 0x86, 0x47, 0xfa, 0x81, 0xe5, 0x83, 0x1f, 0xf, 0x7e, 0x3d, 0xb2, 0xc5, 0xa5, 0x5b, 0xe2, 0xc1, 0x93, 0x7, 0xff, 0x81, 0xf0, 0xf9, 0x63, 0x69, 0x2c, 0xd2, 0x67, 0x58, 0xef, 0x1f, 0x2, 0x4a, 0x42, 0xe0, 0xf1, 0xdb, 0xec, 0x98, 0xfa, 0x67, 0x2, 0x25, 0xe0, 0xf0, 0xe1, 0x2, 0x86, 0x41, 0x7, 0x30, 0x1d, 0x39, 0x3, 0xbf, 0x37, 0x8f, 0xdd, 0x66, 0x27, 0x29, 0xa0, 0x10, 0x4a, 0x2c, 0xa0, 0x41, 0x8d, 0x1b, 0x3c, 0x4c, 0x3, 0x46, 0x16, 0x69, 0x0, 0x0, 0x87, 0x2a, 0x58, 0xb5, 0x18, 0xe9, 0x80, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
diff --git a/scene/resources/height_map_shape.cpp b/scene/resources/height_map_shape.cpp
index 32e9c527ef..8cd271dab0 100644
--- a/scene/resources/height_map_shape.cpp
+++ b/scene/resources/height_map_shape.cpp
@@ -34,35 +34,43 @@
Vector<Vector3> HeightMapShape::_gen_debug_mesh_lines() {
Vector<Vector3> points;
- // This will be slow for large maps...
- // also we'll have to figure out how well bullet centers this shape...
+ if ((map_width != 0) && (map_depth != 0)) {
- Vector2 size(map_width - 1, map_depth - 1);
- Vector2 start = size * -0.5;
- int offset = 0;
+ // This will be slow for large maps...
+ // also we'll have to figure out how well bullet centers this shape...
- PoolRealArray::Read r = map_data.read();
+ Vector2 size(map_width - 1, map_depth - 1);
+ Vector2 start = size * -0.5;
- for (int d = 0; d < map_depth; d++) {
- Vector3 height(start.x, 0.0, start.y);
+ PoolRealArray::Read r = map_data.read();
- for (int w = 0; w < map_width; w++) {
- height.y = r[offset++];
+ // reserve some memory for our points..
+ points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2));
- if (w != map_width - 1) {
- points.push_back(height);
- points.push_back(Vector3(height.x + 1.0, r[offset], height.z));
- }
+ // now set our points
+ int r_offset = 0;
+ int w_offset = 0;
+ for (int d = 0; d < map_depth; d++) {
+ Vector3 height(start.x, 0.0, start.y);
+
+ for (int w = 0; w < map_width; w++) {
+ height.y = r[r_offset++];
+
+ if (w != map_width - 1) {
+ points.write[w_offset++] = height;
+ points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
+ }
- if (d != map_depth - 1) {
- points.push_back(height);
- points.push_back(Vector3(height.x, r[offset + map_width - 1], height.z + 1.0));
+ if (d != map_depth - 1) {
+ points.write[w_offset++] = height;
+ points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
+ }
+
+ height.x += 1.0;
}
- height.x += 1.0;
+ start.y += 1.0;
}
-
- start.y += 1.0;
}
return points;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index a5eb950c36..92172912c2 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -111,10 +111,12 @@ void ImageTexture::reload_from_file() {
Ref<Image> img;
img.instance();
- Error err = ImageLoader::load_image(path, img);
- ERR_FAIL_COND(err != OK);
-
- create_from_image(img, flags);
+ if (ImageLoader::load_image(path, img) == OK) {
+ create_from_image(img, flags);
+ } else {
+ Resource::reload_from_file();
+ _change_notify();
+ }
}
bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
@@ -638,7 +640,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_
bool mipmaps = df & FORMAT_BIT_HAS_MIPMAPS;
if (!mipmaps) {
- int size = Image::get_image_data_size(tw, th, format, 0);
+ int size = Image::get_image_data_size(tw, th, format, false);
PoolVector<uint8_t> img_data;
img_data.resize(size);
@@ -660,7 +662,6 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_
int mipmaps2 = Image::get_image_required_mipmaps(tw, th, format);
int total_size = Image::get_image_data_size(tw, th, format, true);
int idx = 0;
- int ofs = 0;
while (mipmaps2 > 1 && p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) {
@@ -670,9 +671,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_
idx++;
}
- if (idx > 0) {
- ofs = Image::get_image_data_size(tw, th, format, idx - 1);
- }
+ int ofs = Image::get_image_mipmap_offset(tw, th, format, idx);
if (total_size - ofs <= 0) {
memdelete(f);
diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp
index 96d5c9df89..abf9d5593c 100644
--- a/servers/audio/effects/audio_effect_record.cpp
+++ b/servers/audio/effects/audio_effect_record.cpp
@@ -32,6 +32,9 @@
void AudioEffectRecordInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
if (!is_recording) {
+ for (int i = 0; i < p_frame_count; i++) {
+ p_dst_frames[i] = p_src_frames[i];
+ }
return;
}
@@ -39,6 +42,7 @@ void AudioEffectRecordInstance::process(const AudioFrame *p_src_frames, AudioFra
const AudioFrame *src = p_src_frames;
AudioFrame *rb_buf = ring_buffer.ptrw();
for (int i = 0; i < p_frame_count; i++) {
+ p_dst_frames[i] = p_src_frames[i];
rb_buf[ring_buffer_pos & ring_buffer_mask] = src[i];
ring_buffer_pos++;
}
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"; }
diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c
index e7c64a7e17..9704c1079f 100644
--- a/thirdparty/glad/glad.c
+++ b/thirdparty/glad/glad.c
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.29 on Mon Mar 4 12:47:22 2019.
+ OpenGL loader generated by glad 0.1.29 on Wed May 1 23:16:34 2019.
Language/Generator: C/C++
Specification: gl
@@ -9,6 +9,8 @@
Extensions:
GL_ARB_debug_output,
GL_ARB_framebuffer_object,
+ GL_EXT_framebuffer_blit,
+ GL_EXT_framebuffer_multisample,
GL_EXT_framebuffer_object
Loader: True
Local files: False
@@ -16,9 +18,9 @@
Reproducible: False
Commandline:
- --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_object"
+ --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object"
Online:
- https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_object
+ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object
*/
#include <stdio.h>
@@ -992,11 +994,15 @@ PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL;
PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL;
int GLAD_GL_ARB_debug_output = 0;
int GLAD_GL_ARB_framebuffer_object = 0;
+int GLAD_GL_EXT_framebuffer_blit = 0;
+int GLAD_GL_EXT_framebuffer_multisample = 0;
int GLAD_GL_EXT_framebuffer_object = 0;
PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL;
PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL;
PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL;
PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB = NULL;
+PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL;
PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT = NULL;
PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT = NULL;
PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT = NULL;
@@ -1807,6 +1813,14 @@ static void load_GL_ARB_framebuffer_object(GLADloadproc load) {
glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample");
glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer");
}
+static void load_GL_EXT_framebuffer_blit(GLADloadproc load) {
+ if(!GLAD_GL_EXT_framebuffer_blit) return;
+ glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC)load("glBlitFramebufferEXT");
+}
+static void load_GL_EXT_framebuffer_multisample(GLADloadproc load) {
+ if(!GLAD_GL_EXT_framebuffer_multisample) return;
+ glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)load("glRenderbufferStorageMultisampleEXT");
+}
static void load_GL_EXT_framebuffer_object(GLADloadproc load) {
if(!GLAD_GL_EXT_framebuffer_object) return;
glad_glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)load("glIsRenderbufferEXT");
@@ -1831,6 +1845,8 @@ static int find_extensionsGL(void) {
if (!get_exts()) return 0;
GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output");
GLAD_GL_ARB_framebuffer_object = has_ext("GL_ARB_framebuffer_object");
+ GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit");
+ GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample");
GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object");
free_exts();
return 1;
@@ -1912,6 +1928,8 @@ int gladLoadGLLoader(GLADloadproc load) {
if (!find_extensionsGL()) return 0;
load_GL_ARB_debug_output(load);
load_GL_ARB_framebuffer_object(load);
+ load_GL_EXT_framebuffer_blit(load);
+ load_GL_EXT_framebuffer_multisample(load);
load_GL_EXT_framebuffer_object(load);
return GLVersion.major != 0 || GLVersion.minor != 0;
}
diff --git a/thirdparty/glad/glad/glad.h b/thirdparty/glad/glad/glad.h
index 6345de6f7a..b398faf627 100644
--- a/thirdparty/glad/glad/glad.h
+++ b/thirdparty/glad/glad/glad.h
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.29 on Mon Mar 4 12:47:22 2019.
+ OpenGL loader generated by glad 0.1.29 on Wed May 1 23:16:34 2019.
Language/Generator: C/C++
Specification: gl
@@ -9,6 +9,8 @@
Extensions:
GL_ARB_debug_output,
GL_ARB_framebuffer_object,
+ GL_EXT_framebuffer_blit,
+ GL_EXT_framebuffer_multisample,
GL_EXT_framebuffer_object
Loader: True
Local files: False
@@ -16,9 +18,9 @@
Reproducible: False
Commandline:
- --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_object"
+ --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object"
Online:
- https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_object
+ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object
*/
@@ -3633,6 +3635,13 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146
#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148
+#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT 0x8D57
#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
@@ -3704,6 +3713,20 @@ GLAPI PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB;
#define GL_ARB_framebuffer_object 1
GLAPI int GLAD_GL_ARB_framebuffer_object;
#endif
+#ifndef GL_EXT_framebuffer_blit
+#define GL_EXT_framebuffer_blit 1
+GLAPI int GLAD_GL_EXT_framebuffer_blit;
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GLAPI PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT;
+#define glBlitFramebufferEXT glad_glBlitFramebufferEXT
+#endif
+#ifndef GL_EXT_framebuffer_multisample
+#define GL_EXT_framebuffer_multisample 1
+GLAPI int GLAD_GL_EXT_framebuffer_multisample;
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT;
+#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT
+#endif
#ifndef GL_EXT_framebuffer_object
#define GL_EXT_framebuffer_object 1
GLAPI int GLAD_GL_EXT_framebuffer_object;