summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/object.cpp16
-rw-r--r--core/script_language.h1
-rw-r--r--core/variant.cpp12
-rw-r--r--core/variant_op.cpp4
-rw-r--r--drivers/dummy/rasterizer_dummy.h3
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp27
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h2
-rw-r--r--drivers/gles2/shader_gles2.cpp2
-rw-r--r--drivers/gles2/shaders/scene.glsl4
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp4
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h4
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp2
-rw-r--r--drivers/gles3/shaders/canvas.glsl1
-rw-r--r--drivers/gles3/shaders/effect_blur.glsl3
-rw-r--r--drivers/gles3/shaders/scene.glsl4
-rw-r--r--drivers/unix/dir_access_unix.cpp2
-rw-r--r--editor/code_editor.cpp43
-rw-r--r--editor/code_editor.h2
-rw-r--r--editor/editor_folding.cpp32
-rw-r--r--editor/editor_inspector.cpp22
-rw-r--r--editor/editor_node.cpp45
-rw-r--r--editor/editor_node.h3
-rw-r--r--editor/editor_spin_slider.cpp2
-rw-r--r--editor/import/editor_import_collada.cpp6
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp2
-rw-r--r--editor/plugins/item_list_editor_plugin.cpp4
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp2
-rw-r--r--main/tests/test_shader_lang.cpp2
-rw-r--r--methods.py4
-rw-r--r--misc/dist/uwp_template/Assets/SplashScreen.scale-100.pngbin10818 -> 10010 bytes
-rw-r--r--modules/bullet/bullet_physics_server.cpp16
-rw-r--r--modules/bullet/bullet_physics_server.h3
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp8
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.h3
-rw-r--r--modules/bullet/godot_result_callbacks.cpp8
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp4
-rw-r--r--modules/gdnative/nativescript/nativescript.h1
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.h1
-rw-r--r--modules/gdscript/gdscript.cpp1
-rw-r--r--modules/gdscript/gdscript.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/mono/SCsub28
-rw-r--r--modules/mono/csharp_script.cpp590
-rw-r--r--modules/mono/csharp_script.h36
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp8
-rw-r--r--modules/mono/editor/mono_bottom_panel.cpp10
-rw-r--r--modules/mono/glue/base_object_glue.cpp20
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp25
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h91
-rw-r--r--modules/mono/signal_awaiter_utils.cpp8
-rw-r--r--modules/mono/utils/macros.h10
-rw-r--r--modules/mono/utils/mutex_utils.h67
-rw-r--r--modules/squish/config.py2
-rw-r--r--modules/squish/image_compress_squish.cpp4
-rw-r--r--modules/squish/image_compress_squish.h2
-rw-r--r--modules/squish/register_types.cpp7
-rw-r--r--modules/squish/register_types.h2
-rw-r--r--modules/visual_script/visual_script.cpp4
-rw-r--r--modules/visual_script/visual_script.h1
-rw-r--r--platform/android/export/export.cpp22
-rw-r--r--platform/javascript/audio_driver_javascript.cpp104
-rw-r--r--platform/javascript/audio_driver_javascript.h7
-rw-r--r--platform/javascript/detect.py1
-rw-r--r--platform/uwp/export/export.cpp2
-rw-r--r--scene/2d/area_2d.cpp4
-rw-r--r--scene/2d/cpu_particles_2d.cpp6
-rw-r--r--scene/2d/parallax_background.cpp4
-rw-r--r--scene/3d/area.cpp4
-rw-r--r--scene/3d/cpu_particles.cpp16
-rw-r--r--scene/3d/physics_joint.cpp16
-rw-r--r--scene/3d/physics_joint.h7
-rw-r--r--scene/3d/soft_body.cpp2
-rw-r--r--scene/animation/animation_player.cpp10
-rw-r--r--scene/animation/animation_player.h1
-rw-r--r--scene/gui/tabs.cpp6
-rw-r--r--scene/gui/text_edit.cpp12
-rw-r--r--scene/gui/text_edit.h1
-rw-r--r--scene/main/viewport.cpp111
-rw-r--r--scene/main/viewport.h4
-rw-r--r--scene/register_scene_types.cpp6
-rw-r--r--scene/resources/environment.cpp34
-rw-r--r--scene/resources/environment.h4
-rw-r--r--scene/resources/texture.cpp22
-rw-r--r--scene/resources/theme.cpp555
-rw-r--r--scene/resources/theme.h15
-rw-r--r--servers/physics/physics_server_sw.h3
-rw-r--r--servers/physics_server.h3
-rw-r--r--servers/visual/rasterizer.h2
-rw-r--r--servers/visual/visual_server_raster.h2
-rw-r--r--servers/visual/visual_server_wrap_mt.h2
-rw-r--r--servers/visual_server.h2
-rw-r--r--thirdparty/squish/Add-Decompress-Bc5-to-Squish.patch143
-rw-r--r--thirdparty/squish/colourblock.cpp89
-rw-r--r--thirdparty/squish/godot-changes.patch102
96 files changed, 1330 insertions, 1226 deletions
diff --git a/core/object.cpp b/core/object.cpp
index ea77090a45..3a14c7c0b5 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -1443,8 +1443,20 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str
if (!s) {
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
//check in script
- if (!signal_is_valid && !script.is_null() && Ref<Script>(script)->has_script_signal(p_signal))
- signal_is_valid = true;
+ if (!signal_is_valid && !script.is_null()) {
+
+ if (Ref<Script>(script)->has_script_signal(p_signal)) {
+ signal_is_valid = true;
+ }
+#ifdef TOOLS_ENABLED
+ else {
+ //allow connecting signals anyway if script is invalid, see issue #17070
+ if (!Ref<Script>(script)->is_valid()) {
+ signal_is_valid = true;
+ }
+ }
+#endif
+ }
if (!signal_is_valid) {
ERR_EXPLAIN("In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'");
diff --git a/core/script_language.h b/core/script_language.h
index bcd9c2c5ea..654d1d4265 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -128,6 +128,7 @@ public:
virtual MethodInfo get_method_info(const StringName &p_method) const = 0;
virtual bool is_tool() const = 0;
+ virtual bool is_valid() const = 0;
virtual ScriptLanguage *get_language() const = 0;
diff --git a/core/variant.cpp b/core/variant.cpp
index edbe66ba31..eb9f34fee6 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -1662,7 +1662,17 @@ Variant::operator Transform() const {
return Transform(*_data._basis, Vector3());
else if (type == QUAT)
return Transform(Basis(*reinterpret_cast<const Quat *>(_data._mem)), Vector3());
- else
+ else if (type == TRANSFORM2D) {
+ const Transform2D &t = *_data._transform2d;
+ Transform m;
+ m.basis.elements[0][0] = t.elements[0][0];
+ m.basis.elements[1][0] = t.elements[0][1];
+ m.basis.elements[0][1] = t.elements[1][0];
+ m.basis.elements[1][1] = t.elements[1][1];
+ m.origin[0] = t.elements[2][0];
+ m.origin[1] = t.elements[2][1];
+ return m;
+ } else
return Transform();
}
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index d193858966..9f172f0d57 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -2149,7 +2149,7 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid)
int idx = p_index;
if (idx < 0)
idx += 4;
- if (idx >= 0 || idx < 4) {
+ if (idx >= 0 && idx < 4) {
Color *v = reinterpret_cast<Color *>(_data._mem);
(*v)[idx] = p_value;
valid = true;
@@ -2524,7 +2524,7 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const {
int idx = p_index;
if (idx < 0)
idx += 4;
- if (idx >= 0 || idx < 4) {
+ if (idx >= 0 && idx < 4) {
const Color *v = reinterpret_cast<const Color *>(_data._mem);
valid = true;
return (*v)[idx];
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 7c095e3798..dfdb3a6bba 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -63,7 +63,8 @@ public:
void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {}
void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {}
- void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) {}
+ void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {}
+
void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {}
void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) {}
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 6eafdb0e1c..7addbaa9fe 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -708,7 +708,7 @@ void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enabl
ERR_FAIL_COND(!env);
}
-void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) {
+void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
}
@@ -2587,9 +2587,30 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ // clear color
+
+ Color clear_color(0, 0, 0, 0);
- storage->frame.clear_request = false;
+ if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+ clear_color = Color(0, 0, 0, 0);
+ storage->frame.clear_request = false;
+ } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR || env->bg_mode == VS::ENV_BG_SKY) {
+ if (storage->frame.clear_request) {
+ clear_color = storage->frame.clear_request_color.to_linear();
+ storage->frame.clear_request = false;
+ }
+ } else if (env->bg_mode == VS::ENV_BG_CANVAS || env->bg_mode == VS::ENV_BG_COLOR || env->bg_mode == VS::ENV_BG_COLOR_SKY) {
+ clear_color = env->bg_color.to_linear();
+ storage->frame.clear_request = false;
+ } else {
+ storage->frame.clear_request = false;
+ }
+
+ if (!env || env->bg_mode != VS::ENV_BG_KEEP) {
+ glClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
+ }
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index 7d9920158f..ba406183c7 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -413,7 +413,7 @@ public:
virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
- virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale);
+ virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale);
virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture);
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness);
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index c5a67d4e75..84bd413abb 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -99,7 +99,7 @@ void ShaderGLES2::bind_uniforms() {
const Map<uint32_t, CameraMatrix>::Element *C = uniform_cameras.front();
while (C) {
- int idx = E->key();
+ int idx = C->key();
int location = version->uniform_location[idx];
if (location < 0) {
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index bc83b69b49..15b90a7771 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -84,8 +84,6 @@ uniform highp mat4 world_transform;
uniform highp float time;
-
-
#ifdef RENDER_DEPTH
uniform float light_bias;
uniform float light_normal_bias;
@@ -1121,7 +1119,7 @@ LIGHT_SHADER_CODE
float NdotL = dot(N, L);
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
- float cNdotV = max(NdotV, 0.0);
+ float cNdotV = max(abs(NdotV), 1e-6);
#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT)
vec3 H = normalize(V + L);
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index e0c8d3af52..ffe9e1c831 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -846,7 +846,7 @@ void RasterizerSceneGLES3::environment_set_dof_blur_near(RID p_env, bool p_enabl
env->dof_blur_near_amount = p_amount;
env->dof_blur_near_quality = p_quality;
}
-void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) {
+void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -859,6 +859,7 @@ void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_
env->glow_blend_mode = p_blend_mode;
env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold;
env->glow_hdr_bleed_scale = p_hdr_bleed_scale;
+ env->glow_hdr_luminance_cap = p_hdr_luminance_cap;
env->glow_bicubic_upscale = p_bicubic_upscale;
}
void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {
@@ -3898,6 +3899,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h));
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i));
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::GLOW_STRENGTH, env->glow_strength);
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LUMINANCE_CAP, env->glow_hdr_luminance_cap);
glActiveTexture(GL_TEXTURE0);
if (i == 0) {
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index f3157d5a46..0e6027c4ad 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -404,6 +404,7 @@ public:
VS::EnvironmentGlowBlendMode glow_blend_mode;
float glow_hdr_bleed_threshold;
float glow_hdr_bleed_scale;
+ float glow_hdr_luminance_cap;
bool glow_bicubic_upscale;
VS::EnvironmentToneMapper tone_mapper;
@@ -494,6 +495,7 @@ public:
glow_blend_mode = VS::GLOW_BLEND_MODE_SOFTLIGHT;
glow_hdr_bleed_threshold = 1.0;
glow_hdr_bleed_scale = 2.0;
+ glow_hdr_luminance_cap = 12.0;
glow_bicubic_upscale = false;
dof_blur_far_enabled = false;
@@ -548,7 +550,7 @@ public:
virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
- virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale);
+ virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale);
virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture);
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 235c799a55..2b038fcc0e 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -7673,7 +7673,7 @@ void RasterizerStorageGLES3::initialize() {
config.etc2_supported = true;
config.hdr_supported = false;
config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_dxt1") || config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc");
- config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc");
+ config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc") || config.extensions.has("EXT_texture_compression_rgtc");
#endif
config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc");
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index ef2319c332..51a4edd233 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -477,6 +477,7 @@ void main() {
#if defined(NORMALMAP_USED)
vec3 normal_map = vec3(0.0, 0.0, 1.0);
+ normal_used = true;
#endif
/* clang-format off */
diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl
index b67d06bc10..fc15ca31b1 100644
--- a/drivers/gles3/shaders/effect_blur.glsl
+++ b/drivers/gles3/shaders/effect_blur.glsl
@@ -94,6 +94,7 @@ uniform sampler2D source_dof_original; //texunit:2
uniform float exposure;
uniform float white;
+uniform highp float luminance_cap;
#ifdef GLOW_USE_AUTO_EXPOSURE
@@ -271,7 +272,7 @@ void main() {
float luminance = max(frag_color.r, max(frag_color.g, frag_color.b));
float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom);
- frag_color *= feedback;
+ frag_color = min(frag_color * feedback, vec4(luminance_cap));
#endif
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index e2e3584304..407e7ec591 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1590,8 +1590,8 @@ void main() {
#endif
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- vec3 binormal = normalize(binormal_interp);// * side;
- vec3 tangent = normalize(tangent_interp);// * side;
+ vec3 binormal = normalize(binormal_interp);
+ vec3 tangent = normalize(tangent_interp);
#else
vec3 binormal = vec3(0.0);
vec3 tangent = vec3(0.0);
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index e4b652cdce..bea249d4b6 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -329,7 +329,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
}
String base = _get_root_path();
- if (base != String()) {
+ if (base != String() && !try_dir.begins_with(base)) {
ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG);
String new_dir;
new_dir.parse_utf8(real_current_dir_name);
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 2a11f70274..a0a8e9459d 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -673,7 +673,7 @@ void CodeTextEditor::_reset_zoom() {
if (font.is_valid()) {
EditorSettings::get_singleton()->set("interface/editor/code_font_size", 14);
font->set_size(14);
- zoom_nb->set_text("100%");
+ font_size_nb->set_text("14 (100%)");
}
}
@@ -748,7 +748,7 @@ bool CodeTextEditor::_add_font_size(int p_delta) {
if (font.is_valid()) {
int new_size = CLAMP(font->get_size() + p_delta, 8 * EDSCALE, 96 * EDSCALE);
- zoom_nb->set_text(itos(100 * new_size / (14 * EDSCALE)) + "%");
+ font_size_nb->set_text(itos(new_size) + " (" + itos(100 * new_size / (14 * EDSCALE)) + "%)");
if (new_size != font->get_size()) {
EditorSettings::get_singleton()->set("interface/editor/code_font_size", new_size / EDSCALE);
@@ -1162,6 +1162,9 @@ void CodeTextEditor::_on_settings_change() {
_update_font();
+ font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size");
+ font_size_nb->set_text(itos(font_size) + " (" + itos(100 * font_size / (14 * EDSCALE)) + "%)");
+
// AUTO BRACE COMPLETION
text_editor->set_auto_brace_completion(
EDITOR_DEF("text_editor/completion/auto_brace_complete", true));
@@ -1296,23 +1299,23 @@ CodeTextEditor::CodeTextEditor() {
warning_count_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
warning_count_label->set_text("0");
- Label *zoom_txt = memnew(Label);
- status_bar->add_child(zoom_txt);
- zoom_txt->set_align(Label::ALIGN_RIGHT);
- zoom_txt->set_valign(Label::VALIGN_CENTER);
- zoom_txt->set_v_size_flags(SIZE_FILL);
- zoom_txt->set_text(TTR("Zoom:"));
- zoom_txt->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
-
- zoom_nb = memnew(Label);
- status_bar->add_child(zoom_nb);
- zoom_nb->set_valign(Label::VALIGN_CENTER);
- zoom_nb->set_v_size_flags(SIZE_FILL);
- zoom_nb->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch
- zoom_nb->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch
- zoom_nb->set_custom_minimum_size(Size2(60, 1) * EDSCALE);
- zoom_nb->set_align(Label::ALIGN_RIGHT);
- zoom_nb->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
+ Label *font_size_txt = memnew(Label);
+ status_bar->add_child(font_size_txt);
+ font_size_txt->set_align(Label::ALIGN_RIGHT);
+ font_size_txt->set_valign(Label::VALIGN_CENTER);
+ font_size_txt->set_v_size_flags(SIZE_FILL);
+ font_size_txt->set_text(TTR("Font Size:"));
+ font_size_txt->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
+
+ font_size_nb = memnew(Label);
+ status_bar->add_child(font_size_nb);
+ font_size_nb->set_valign(Label::VALIGN_CENTER);
+ font_size_nb->set_v_size_flags(SIZE_FILL);
+ font_size_nb->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch
+ font_size_nb->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch
+ font_size_nb->set_custom_minimum_size(Size2(100, 1) * EDSCALE);
+ font_size_nb->set_align(Label::ALIGN_RIGHT);
+ font_size_nb->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
Label *line_txt = memnew(Label);
status_bar->add_child(line_txt);
@@ -1368,7 +1371,7 @@ CodeTextEditor::CodeTextEditor() {
font_resize_val = 0;
font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size");
- zoom_nb->set_text(itos(100 * font_size / (14 * EDSCALE)) + "%");
+ font_size_nb->set_text(itos(font_size) + " (" + itos(100 * font_size / (14 * EDSCALE)) + "%)");
font_resize_timer = memnew(Timer);
add_child(font_resize_timer);
font_resize_timer->set_one_shot(true);
diff --git a/editor/code_editor.h b/editor/code_editor.h
index 311b6a959b..2d233c61c6 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -148,7 +148,7 @@ class CodeTextEditor : public VBoxContainer {
Label *line_nb;
Label *col_nb;
- Label *zoom_nb;
+ Label *font_size_nb;
Label *info;
Timer *idle;
Timer *code_complete_timer;
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
index 776342582c..a88cd740db 100644
--- a/editor/editor_folding.cpp
+++ b/editor/editor_folding.cpp
@@ -1,8 +1,8 @@
#include "editor_folding.h"
#include "core/os/file_access.h"
-#include "editor_settings.h"
#include "editor_inspector.h"
+#include "editor_settings.h"
PoolVector<String> EditorFolding::_get_unfolds(const Object *p_object) {
@@ -172,7 +172,6 @@ bool EditorFolding::has_folding_data(const String &p_path) {
return FileAccess::exists(file);
}
-
void EditorFolding::_do_object_unfolds(Object *p_object, Set<RES> &resources) {
List<PropertyInfo> plist;
@@ -185,34 +184,33 @@ void EditorFolding::_do_object_unfolds(Object *p_object, Set<RES> &resources) {
for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
if (E->get().usage & PROPERTY_USAGE_CATEGORY) {
- group="";
- group_base="";
+ group = "";
+ group_base = "";
}
if (E->get().usage & PROPERTY_USAGE_GROUP) {
group = E->get().name;
group_base = E->get().hint_string;
if (group_base.ends_with("_")) {
- group_base=group_base.substr(0,group_base.length()-1);
+ group_base = group_base.substr(0, group_base.length() - 1);
}
}
//can unfold
if (E->get().usage & PROPERTY_USAGE_EDITOR) {
-
if (group != "") { //group
- if (group_base==String() || E->get().name.begins_with(group_base)) {
- bool can_revert = EditorPropertyRevert::can_property_revert(p_object,E->get().name);
- if (can_revert) {
+ if (group_base == String() || E->get().name.begins_with(group_base)) {
+ bool can_revert = EditorPropertyRevert::can_property_revert(p_object, E->get().name);
+ if (can_revert) {
unfold_group.insert(group);
}
}
} else { //path
int last = E->get().name.find_last("/");
- if (last!=-1) {
- bool can_revert = EditorPropertyRevert::can_property_revert(p_object,E->get().name);
+ if (last != -1) {
+ bool can_revert = EditorPropertyRevert::can_property_revert(p_object, E->get().name);
if (can_revert) {
- unfold_group.insert(E->get().name.substr(0,last));
+ unfold_group.insert(E->get().name.substr(0, last));
}
}
}
@@ -223,13 +221,13 @@ void EditorFolding::_do_object_unfolds(Object *p_object, Set<RES> &resources) {
if (res.is_valid() && !resources.has(res) && res->get_path() != String() && !res->get_path().is_resource_file()) {
resources.insert(res);
- _do_object_unfolds(res.ptr(),resources);
+ _do_object_unfolds(res.ptr(), resources);
}
}
}
- for (Set<String>::Element *E=unfold_group.front();E;E=E->next()) {
- p_object->editor_set_section_unfold(E->get(),true);
+ for (Set<String>::Element *E = unfold_group.front(); E; E = E->next()) {
+ p_object->editor_set_section_unfold(E->get(), true);
}
}
@@ -243,7 +241,7 @@ void EditorFolding::_do_node_unfolds(Node *p_root, Node *p_node, Set<RES> &resou
}
}
- _do_object_unfolds(p_node,resources);
+ _do_object_unfolds(p_node, resources);
for (int i = 0; i < p_node->get_child_count(); i++) {
_do_node_unfolds(p_root, p_node->get_child(i), resources);
@@ -253,7 +251,7 @@ void EditorFolding::_do_node_unfolds(Node *p_root, Node *p_node, Set<RES> &resou
void EditorFolding::unfold_scene(Node *p_scene) {
Set<RES> resources;
- _do_node_unfolds(p_scene,p_scene,resources);
+ _do_node_unfolds(p_scene, p_scene, resources);
}
EditorFolding::EditorFolding() {
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index b50af93352..10c9974cdd 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -128,18 +128,22 @@ void EditorProperty::_notification(int p_what) {
bottom_rect = Rect2(m, rect.size.height + get_constant("vseparation", "Tree"), size.width - m, bottom_editor->get_combined_minimum_size().height);
}
- }
- if (keying) {
- Ref<Texture> key;
+ if (keying) {
+ Ref<Texture> key;
- if (use_keying_next()) {
- key = get_icon("KeyNext", "EditorIcons");
- } else {
- key = get_icon("Key", "EditorIcons");
- }
+ if (use_keying_next()) {
+ key = get_icon("KeyNext", "EditorIcons");
+ } else {
+ key = get_icon("Key", "EditorIcons");
+ }
- rect.size.x -= key->get_width() + get_constant("hseparator", "Tree");
+ rect.size.x -= key->get_width() + get_constant("hseparator", "Tree");
+
+ if (no_children) {
+ text_size -= key->get_width() + 4 * EDSCALE;
+ }
+ }
}
//set children
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 40a7b8310f..d009ed61b5 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -999,6 +999,22 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
}
+bool EditorNode::_validate_scene_recursive(const String &p_filename, Node *p_node) {
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ if (child->get_filename() == p_filename) {
+ return true;
+ }
+
+ if (_validate_scene_recursive(p_filename, child)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void EditorNode::_save_scene(String p_file, int idx) {
Node *scene = editor_data.get_edited_scene_root(idx);
@@ -1009,6 +1025,11 @@ void EditorNode::_save_scene(String p_file, int idx) {
return;
}
+ if (scene->get_filename() != String() && _validate_scene_recursive(scene->get_filename(), scene)) {
+ show_accept(TTR("This scene can't be saved because there is a cyclic instancing inclusion.\nPlease resolve it and then attempt to save again."), TTR("OK"));
+ return;
+ }
+
editor_data.apply_changes_in_editors();
_save_default_environment();
@@ -3228,17 +3249,31 @@ Ref<Texture> EditorNode::get_class_icon(const String &p_class, const String &p_f
void EditorNode::progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) {
- singleton->progress_dialog->add_task(p_task, p_label, p_steps, p_can_cancel);
+ if (singleton->disable_progress_dialog) {
+ print_line(p_task + ": begin: " + p_label + " steps: " + itos(p_steps));
+ } else {
+ singleton->progress_dialog->add_task(p_task, p_label, p_steps, p_can_cancel);
+ }
}
bool EditorNode::progress_task_step(const String &p_task, const String &p_state, int p_step, bool p_force_refresh) {
- return singleton->progress_dialog->task_step(p_task, p_state, p_step, p_force_refresh);
+ if (singleton->disable_progress_dialog) {
+ print_line("\t" + p_task + ": step " + itos(p_step) + ": " + p_state);
+ return false;
+ } else {
+
+ return singleton->progress_dialog->task_step(p_task, p_state, p_step, p_force_refresh);
+ }
}
void EditorNode::progress_end_task(const String &p_task) {
- singleton->progress_dialog->end_task(p_task);
+ if (singleton->disable_progress_dialog) {
+ print_line(p_task + ": end");
+ } else {
+ singleton->progress_dialog->end_task(p_task);
+ }
}
void EditorNode::progress_add_task_bg(const String &p_task, const String &p_label, int p_steps) {
@@ -3320,7 +3355,7 @@ Error EditorNode::export_preset(const String &p_preset, const String &p_path, bo
export_defer.path = p_path;
export_defer.debug = p_debug;
export_defer.password = p_password;
-
+ disable_progress_dialog = true;
return OK;
}
@@ -4710,7 +4745,7 @@ EditorNode::EditorNode() {
_initializing_addons = false;
docks_visible = true;
restoring_scenes = false;
-
+ disable_progress_dialog = false;
scene_distraction = false;
script_distraction = false;
diff --git a/editor/editor_node.h b/editor/editor_node.h
index e220daf8a9..4d89d1f956 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -445,6 +445,7 @@ private:
void _show_messages();
void _vp_resized();
+ bool _validate_scene_recursive(const String &p_filename, Node *p_node);
void _save_scene(String p_file, int idx = -1);
void _save_all_scenes();
int _next_unsaved_scene(bool p_valid_filename, int p_start = 0);
@@ -524,6 +525,8 @@ private:
} export_defer;
+ bool disable_progress_dialog;
+
static EditorNode *singleton;
static Vector<EditorNodeInitCallback> _init_callbacks;
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index b6e4375ce9..8ea56b8578 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -154,7 +154,7 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
void EditorSpinSlider::_notification(int p_what) {
- if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_OUT || p_what == MainLoop::NOTIFICATION_WM_FOCUS_OUT) {
+ if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_OUT || p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) {
if (grabbing_spinner) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
grabbing_spinner = false;
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index afd09748f3..cdc35a98e2 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -1655,8 +1655,9 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
}
}
- Quat q = Math::is_equal_approx(xform.basis.determinant(), 0) ? Quat() : xform.basis.get_rotation_quat();
Vector3 s = xform.basis.get_scale();
+ bool singular_matrix = Math::is_equal_approx(s.x, 0.0f) || Math::is_equal_approx(s.y, 0.0f) || Math::is_equal_approx(s.z, 0.0f);
+ Quat q = singular_matrix ? Quat() : xform.basis.get_rotation_quat();
Vector3 l = xform.origin;
animation->transform_track_insert_key(track, snapshots[i], l, q, s);
@@ -1705,8 +1706,9 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
- Quat q = Math::is_equal_approx(xform.basis.determinant(), 0) ? Quat() : xform.basis.get_rotation_quat();
Vector3 s = xform.basis.get_scale();
+ bool singular_matrix = Math::is_equal_approx(s.x, 0.0f) || Math::is_equal_approx(s.y, 0.0f) || Math::is_equal_approx(s.z, 0.0f);
+ Quat q = singular_matrix ? Quat() : xform.basis.get_rotation_quat();
Vector3 l = xform.origin;
animation->transform_track_insert_key(track, 0, l, q, s);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index e83773257b..990c77430f 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -849,7 +849,7 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
return;
int idx = -1;
- for (int i = 0; node_rects.size(); i++) {
+ for (int i = 0; i < node_rects.size(); i++) {
if (node_rects[i].node_name == playback->get_current_node()) {
idx = i;
break;
diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp
index 8df40232b0..a32f42cc56 100644
--- a/editor/plugins/item_list_editor_plugin.cpp
+++ b/editor/plugins/item_list_editor_plugin.cpp
@@ -265,6 +265,9 @@ void ItemListEditor::_notification(int p_notification) {
add_button->set_icon(get_icon("Add", "EditorIcons"));
del_button->set_icon(get_icon("Remove", "EditorIcons"));
+ } else if (p_notification == NOTIFICATION_READY) {
+
+ get_tree()->connect("node_removed", this, "_node_removed");
}
}
@@ -341,6 +344,7 @@ bool ItemListEditor::handles(Object *p_object) const {
void ItemListEditor::_bind_methods() {
+ ClassDB::bind_method("_node_removed", &ItemListEditor::_node_removed);
ClassDB::bind_method("_edit_items", &ItemListEditor::_edit_items);
ClassDB::bind_method("_add_button", &ItemListEditor::_add_pressed);
ClassDB::bind_method("_delete_button", &ItemListEditor::_delete_pressed);
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 40781908fd..82936d63d2 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -598,7 +598,7 @@ bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant &
return false;
for (int i = 0; i < files.size(); i++) {
- String file = files[0];
+ String file = files[i];
String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
if (!ClassDB::is_parent_class(ftype, "Texture")) {
diff --git a/main/tests/test_shader_lang.cpp b/main/tests/test_shader_lang.cpp
index 9df5973376..357143e499 100644
--- a/main/tests/test_shader_lang.cpp
+++ b/main/tests/test_shader_lang.cpp
@@ -180,7 +180,7 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
String scode = dump_node_code(bnode->statements[i], p_level);
- if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) {
+ if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) {
code += scode; //use directly
} else {
code += _mktab(p_level) + scode + ";\n";
diff --git a/methods.py b/methods.py
index 5fcbc94298..f8fc6c64ef 100644
--- a/methods.py
+++ b/methods.py
@@ -6,7 +6,7 @@ import glob
import string
import datetime
import subprocess
-from compat import iteritems, isbasestring
+from compat import iteritems, isbasestring, decode_utf8
def add_source_files(self, sources, filetype, lib_env=None, shared=False):
@@ -645,7 +645,7 @@ def detect_darwin_sdk_path(platform, env):
if not env[var_name]:
try:
- sdk_path = subprocess.check_output(['xcrun', '--sdk', sdk_name, '--show-sdk-path']).strip()
+ sdk_path = decode_utf8(subprocess.check_output(['xcrun', '--sdk', sdk_name, '--show-sdk-path']).strip())
if sdk_path:
env[var_name] = sdk_path
except (subprocess.CalledProcessError, OSError) as e:
diff --git a/misc/dist/uwp_template/Assets/SplashScreen.scale-100.png b/misc/dist/uwp_template/Assets/SplashScreen.scale-100.png
index 0c27fda8e7..a4dd3d7175 100644
--- a/misc/dist/uwp_template/Assets/SplashScreen.scale-100.png
+++ b/misc/dist/uwp_template/Assets/SplashScreen.scale-100.png
Binary files differ
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 315afe3d72..7bc731e75e 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -1471,6 +1471,22 @@ bool BulletPhysicsServer::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis
return generic_6dof_joint->get_flag(p_axis, p_flag);
}
+void BulletPhysicsServer::generic_6dof_joint_set_precision(RID p_joint, int p_precision) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
+ Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
+ generic_6dof_joint->set_precision(p_precision);
+}
+
+int BulletPhysicsServer::generic_6dof_joint_get_precision(RID p_joint) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
+ Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
+ return generic_6dof_joint->get_precision();
+}
+
void BulletPhysicsServer::free(RID p_rid) {
if (shape_owner.owns(p_rid)) {
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index c8c782267e..0cea3f5ba6 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -375,6 +375,9 @@ public:
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable);
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag);
+ virtual void generic_6dof_joint_set_precision(RID p_joint, int precision);
+ virtual int generic_6dof_joint_get_precision(RID p_joint);
+
/* MISC */
virtual void free(RID p_rid);
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
index a94b88d566..812dcd2d56 100644
--- a/modules/bullet/generic_6dof_joint_bullet.cpp
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -265,3 +265,11 @@ bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOF
ERR_FAIL_INDEX_V(p_axis, 3, false);
return flags[p_axis][p_flag];
}
+
+void Generic6DOFJointBullet::set_precision(int p_precision) {
+ sixDOFConstraint->setOverrideNumSolverIterations(MAX(1, p_precision));
+}
+
+int Generic6DOFJointBullet::get_precision() const {
+ return sixDOFConstraint->getOverrideNumSolverIterations();
+}
diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h
index 176127ed6c..848c3a10cd 100644
--- a/modules/bullet/generic_6dof_joint_bullet.h
+++ b/modules/bullet/generic_6dof_joint_bullet.h
@@ -68,6 +68,9 @@ public:
void set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value);
bool get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const;
+
+ void set_precision(int p_precision);
+ int get_precision() const;
};
#endif
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 3b44ab838e..0117bb375f 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -102,6 +102,9 @@ bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) con
}
btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) {
+ if (count >= m_resultMax)
+ return 1; // not used by bullet
+
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(convexResult.m_hitCollisionObject->getUserPointer());
PhysicsDirectSpaceState::ShapeResult &result = m_results[count];
@@ -172,6 +175,9 @@ btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::Loc
}
bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ if (m_count >= m_resultMax)
+ return false;
+
const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
if (needs) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
@@ -249,6 +255,8 @@ bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *pr
}
btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
+ if (m_count >= m_resultMax)
+ return 1; // not used by bullet
if (m_self_object == colObj0Wrap->getCollisionObject()) {
B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 0]); // Local contact
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index eb133502c4..bcaf3f346e 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -294,6 +294,10 @@ MethodInfo NativeScript::get_method_info(const StringName &p_method) const {
return MethodInfo();
}
+bool NativeScript::is_valid() const {
+ return true;
+}
+
bool NativeScript::is_tool() const {
NativeScriptDesc *script_data = get_script_desc();
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index 51370f5fbf..e6f3c06ee5 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -160,6 +160,7 @@ public:
virtual MethodInfo get_method_info(const StringName &p_method) const;
virtual bool is_tool() const;
+ virtual bool is_valid() const;
virtual ScriptLanguage *get_language() const;
diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h
index 31c6c4d67f..3ade8ac004 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.h
+++ b/modules/gdnative/pluginscript/pluginscript_script.h
@@ -102,6 +102,7 @@ public:
PropertyInfo get_property_info(const StringName &p_property) const;
bool is_tool() const { return _tool; }
+ bool is_valid() const { return true; }
virtual ScriptLanguage *get_language() const;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 1f5f5035f9..538249c8e2 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -867,7 +867,6 @@ bool GDScript::has_script_signal(const StringName &p_signal) const {
else if (base_cache.is_valid()) {
return base_cache->has_script_signal(p_signal);
}
-
#endif
return false;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index f344beba9f..752d660ffb 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -141,7 +141,7 @@ protected:
static void _bind_methods();
public:
- bool is_valid() const { return valid; }
+ virtual bool is_valid() const { return valid; }
const Map<StringName, Ref<GDScript> > &get_subclasses() const { return subclasses; }
const Map<StringName, Variant> &get_constants() const { return constants; }
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 310c4e21f2..caa7fbfeca 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -132,7 +132,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.kind = GDScriptDataType::SCRIPT;
result.script_type = p_datatype.script_type;
result.native_type = result.script_type->get_instance_base_type();
- }
+ } break;
case GDScriptParser::DataType::GDSCRIPT: {
result.kind = GDScriptDataType::GDSCRIPT;
result.script_type = p_datatype.script_type;
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index 0e5dd9b4cf..e1f5e2ef28 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -103,6 +103,16 @@ import os
def find_nuget_unix():
+ import os
+
+ if 'NUGET_PATH' in os.environ:
+ hint_path = os.environ['NUGET_PATH']
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ hint_path = os.path.join(hint_path, 'nuget')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
import os.path
import sys
@@ -129,6 +139,16 @@ def find_nuget_unix():
def find_nuget_windows():
+ import os
+
+ if 'NUGET_PATH' in os.environ:
+ hint_path = os.environ['NUGET_PATH']
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ hint_path = os.path.join(hint_path, 'nuget.exe')
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
import mono_reg_utils as monoreg
mono_root = ''
@@ -160,14 +180,6 @@ def find_nuget_windows():
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
- if 'NUGET_PATH' in os.environ:
- hint_path = os.environ['NUGET_PATH']
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- hint_path = os.path.join(hint_path, 'nuget.exe')
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
-
return None
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 700e518cfc..3c818898e6 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -50,6 +50,7 @@
#include "mono_gd/gd_mono_marshal.h"
#include "signal_awaiter_utils.h"
#include "utils/macros.h"
+#include "utils/mutex_utils.h"
#include "utils/string_utils.h"
#include "utils/thread_local.h"
@@ -378,60 +379,72 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
return "object";
if (!ClassDB::class_exists(p_var_type_name)) {
- Variant::Type var_types[] = {
- Variant::BOOL,
- Variant::INT,
- Variant::REAL,
- Variant::STRING,
- Variant::VECTOR2,
- Variant::RECT2,
- Variant::VECTOR3,
- Variant::TRANSFORM2D,
- Variant::PLANE,
- Variant::QUAT,
- Variant::AABB,
- Variant::BASIS,
- Variant::TRANSFORM,
- Variant::COLOR,
- Variant::NODE_PATH,
- Variant::_RID
- };
-
- for (int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) {
- if (p_var_type_name == Variant::get_type_name(var_types[i]))
- return p_var_type_name;
- }
+ return p_var_type_name;
+ }
+
+ if (p_var_type_name == Variant::get_type_name(Variant::OBJECT))
+ return "Godot.Object";
- if (p_var_type_name == "String")
- return "string"; // I prefer this one >:[
+ if (p_var_type_name == Variant::get_type_name(Variant::REAL)) {
+#ifdef REAL_T_IS_DOUBLE
+ return "double";
+#else
+ return "float";
+#endif
+ }
- // TODO these will be rewritten later into custom containers
+ if (p_var_type_name == Variant::get_type_name(Variant::STRING))
+ return "string"; // I prefer this one >:[
- if (p_var_type_name == "Array")
- return "object[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::DICTIONARY))
+ return "Collections.Dictionary";
- if (p_var_type_name == "Dictionary")
- return "Dictionary<object, object>";
+ if (p_var_type_name == Variant::get_type_name(Variant::ARRAY))
+ return "Collections.Array";
- if (p_var_type_name == "PoolByteArray")
- return "byte[]";
- if (p_var_type_name == "PoolIntArray")
- return "int[]";
- if (p_var_type_name == "PoolRealArray")
- return "float[]";
- if (p_var_type_name == "PoolStringArray")
- return "string[]";
- if (p_var_type_name == "PoolVector2Array")
- return "Vector2[]";
- if (p_var_type_name == "PoolVector3Array")
- return "Vector3[]";
- if (p_var_type_name == "PoolColorArray")
- return "Color[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::POOL_BYTE_ARRAY))
+ return "byte[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::POOL_INT_ARRAY))
+ return "int[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::POOL_REAL_ARRAY)) {
+#ifdef REAL_T_IS_DOUBLE
+ return "double[]";
+#else
+ return "float[]";
+#endif
+ }
+ if (p_var_type_name == Variant::get_type_name(Variant::POOL_STRING_ARRAY))
+ return "string[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::POOL_VECTOR2_ARRAY))
+ return "Vector2[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::POOL_VECTOR3_ARRAY))
+ return "Vector3[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::POOL_COLOR_ARRAY))
+ return "Color[]";
+
+ Variant::Type var_types[] = {
+ Variant::BOOL,
+ Variant::INT,
+ Variant::VECTOR2,
+ Variant::RECT2,
+ Variant::VECTOR3,
+ Variant::TRANSFORM2D,
+ Variant::PLANE,
+ Variant::QUAT,
+ Variant::AABB,
+ Variant::BASIS,
+ Variant::TRANSFORM,
+ Variant::COLOR,
+ Variant::NODE_PATH,
+ Variant::_RID
+ };
- return "object";
+ for (int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) {
+ if (p_var_type_name == Variant::get_type_name(var_types[i]))
+ return p_var_type_name;
}
- return p_var_type_name;
+ return "object";
}
String CSharpLanguage::make_function(const String &, const String &p_name, const PoolStringArray &p_args) const {
@@ -507,8 +520,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
MonoException *exc = NULL;
- GDMonoUtils::StackTrace_GetFrames st_get_frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames);
- MonoArray *frames = st_get_frames(p_stack_trace, (MonoObject **)&exc);
+ MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, (MonoObject **)&exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -532,7 +544,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
MonoString *file_name;
int file_line_num;
MonoString *method_decl;
- get_sf_info(frame, &file_name, &file_line_num, &method_decl, (MonoObject **)&exc);
+ invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, (MonoObject **)&exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -561,10 +573,8 @@ void CSharpLanguage::frame() {
MonoObject *task_scheduler = task_scheduler_handle->get_target();
if (task_scheduler) {
- GDMonoUtils::GodotTaskScheduler_Activate thunk = CACHED_METHOD_THUNK(GodotTaskScheduler, Activate);
-
MonoException *exc = NULL;
- thunk(task_scheduler, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, (MonoObject **)&exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
@@ -599,24 +609,20 @@ void CSharpLanguage::reload_all_scripts() {
#ifdef DEBUG_ENABLED
-#ifndef NO_THREADS
- lock->lock();
-#endif
-
List<Ref<CSharpScript> > scripts;
- SelfList<CSharpScript> *elem = script_list.first();
- while (elem) {
- if (elem->self()->get_path().is_resource_file()) {
- scripts.push_back(Ref<CSharpScript>(elem->self())); //cast to gdscript to avoid being erased by accident
+ {
+ SCOPED_MUTEX_LOCK(script_instances_mutex);
+
+ SelfList<CSharpScript> *elem = script_list.first();
+ while (elem) {
+ if (elem->self()->get_path().is_resource_file()) {
+ scripts.push_back(Ref<CSharpScript>(elem->self())); //cast to gdscript to avoid being erased by accident
+ }
+ elem = elem->next();
}
- elem = elem->next();
}
-#ifndef NO_THREADS
- lock->unlock();
-#endif
-
//as scripts are going to be reloaded, must proceed without locking here
scripts.sort_custom<CSharpScriptDepSort>(); //update in inheritance dependency order
@@ -625,6 +631,7 @@ void CSharpLanguage::reload_all_scripts() {
E->get()->load_source_code(E->get()->get_path());
E->get()->reload(true);
}
+
#endif
}
@@ -634,15 +641,17 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft
#ifdef TOOLS_ENABLED
MonoReloadNode::get_singleton()->restart_reload_timer();
- reload_assemblies_if_needed(p_soft_reload);
+ if (is_assembly_reloading_needed()) {
+ reload_assemblies(p_soft_reload);
+ }
#endif
}
#ifdef TOOLS_ENABLED
-void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
+bool CSharpLanguage::is_assembly_reloading_needed() {
if (!gdmono->is_runtime_initialized())
- return;
+ return false;
GDMonoAssembly *proj_assembly = gdmono->get_project_assembly();
@@ -660,164 +669,208 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
// Maybe it wasn't loaded from the default path, so check this as well
proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name);
if (!FileAccess::exists(proj_asm_path))
- return; // No assembly to load
+ return false; // No assembly to load
}
if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time())
- return; // Already up to date
+ return false; // Already up to date
} else {
if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name)))
- return; // No assembly to load
+ return false; // No assembly to load
}
if (!gdmono->get_core_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE))
- return; // The core API assembly to load is invalidated
+ return false; // The core API assembly to load is invalidated
if (!gdmono->get_editor_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR))
- return; // The editor API assembly to load is invalidated
+ return false; // The editor API assembly to load is invalidated
-#ifndef NO_THREADS
- lock->lock();
-#endif
+ return true;
+}
+
+void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
+
+ if (!gdmono->is_runtime_initialized())
+ return;
+
+ // There is no soft reloading with Mono. It's always hard reloading.
List<Ref<CSharpScript> > scripts;
- SelfList<CSharpScript> *elem = script_list.first();
- while (elem) {
- if (elem->self()->get_path().is_resource_file()) {
+ {
+ SCOPED_MUTEX_LOCK(script_instances_mutex);
- scripts.push_back(Ref<CSharpScript>(elem->self())); //cast to CSharpScript to avoid being erased by accident
+ for (SelfList<CSharpScript> *elem = script_list.first(); elem; elem = elem->next()) {
+ if (elem->self()->get_path().is_resource_file()) {
+ // Cast to CSharpScript to avoid being erased by accident
+ scripts.push_back(Ref<CSharpScript>(elem->self()));
+ }
}
- elem = elem->next();
}
-#ifndef NO_THREADS
- lock->unlock();
-#endif
+ List<Ref<CSharpScript> > to_reload;
- //when someone asks you why dynamically typed languages are easier to write....
+ // As scripts are going to be reloaded, must proceed without locking here
- Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
+ scripts.sort_custom<CSharpScriptDepSort>(); // Update in inheritance dependency order
- //as scripts are going to be reloaded, must proceed without locking here
+ for (List<Ref<CSharpScript> >::Element *E = scripts.front(); E; E = E->next()) {
- scripts.sort_custom<CSharpScriptDepSort>(); //update in inheritance dependency order
+ Ref<CSharpScript> &script = E->get();
- for (List<Ref<CSharpScript> >::Element *E = scripts.front(); E; E = E->next()) {
+ to_reload.push_back(script);
- to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant> > >());
+ // Script::instances are deleted during managed object disposal, which happens on domain finalize.
+ // Only placeholders are kept. Therefore we need to keep a copy before that happens.
- if (!p_soft_reload) {
+ for (Set<Object *>::Element *E = script->instances.front(); E; E = E->next()) {
+ script->pending_reload_instances.insert(E->get()->get_instance_id());
+ }
- //save state and remove script from instances
- Map<ObjectID, List<Pair<StringName, Variant> > > &map = to_reload[E->get()];
+#ifdef TOOLS_ENABLED
+ for (Set<PlaceHolderScriptInstance *>::Element *E = script->placeholders.front(); E; E = E->next()) {
+ script->pending_reload_instances.insert(E->get()->get_owner()->get_instance_id());
+ }
+#endif
- while (E->get()->instances.front()) {
- Object *obj = E->get()->instances.front()->get();
- //save instance info
- List<Pair<StringName, Variant> > state;
- if (obj->get_script_instance()) {
+ // FIXME: What about references? Need to keep them alive if only managed code references them.
- obj->get_script_instance()->get_property_state(state);
+ // Save state and remove script from instances
+ Map<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state;
- Ref<MonoGCHandle> gchandle = CAST_CSHARP_INSTANCE(obj->get_script_instance())->gchandle;
- if (gchandle.is_valid())
- gchandle->release();
+ while (script->instances.front()) {
+ Object *obj = script->instances.front()->get();
+ // Save instance info
+ CSharpScript::StateBackup state;
- map[obj->get_instance_id()] = state;
- obj->set_script(RefPtr());
- }
- }
+ ERR_CONTINUE(!obj->get_script_instance());
- //same thing for placeholders
- while (E->get()->placeholders.size()) {
-
- Object *obj = E->get()->placeholders.front()->get()->get_owner();
- //save instance info
- List<Pair<StringName, Variant> > state;
- if (obj->get_script_instance()) {
- obj->get_script_instance()->get_property_state(state);
- map[obj->get_instance_id()] = state;
- obj->set_script(RefPtr());
- } else {
- // no instance found. Let's remove it so we don't loop forever
- E->get()->placeholders.erase(E->get()->placeholders.front()->get());
- }
- }
+ // TODO: Proper state backup (Not only variants, serialize managed state of scripts)
+ obj->get_script_instance()->get_property_state(state.properties);
- for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) {
- map[F->key()] = F->get(); //pending to reload, use this one instead
- }
+ Ref<MonoGCHandle> gchandle = CAST_CSHARP_INSTANCE(obj->get_script_instance())->gchandle;
+ if (gchandle.is_valid())
+ gchandle->release();
- E->get()->_clear();
+ owners_map[obj->get_instance_id()] = state;
+ obj->set_script(RefPtr()); // Remove script and existing script instances (placeholder are not removed before domain reload)
}
+
+ script->_clear();
}
+ // Do domain reload
if (gdmono->reload_scripts_domain() != OK) {
// Failed to reload the scripts domain
// Make sure to add the scripts back to their owners before returning
- for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
- Ref<CSharpScript> scr = E->key();
- for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) {
+ for (List<Ref<CSharpScript> >::Element *E = to_reload.front(); E; E = E->next()) {
+ Ref<CSharpScript> scr = E->get();
+
+ for (const Map<ObjectID, CSharpScript::StateBackup>::Element *F = scr->pending_reload_state.front(); F; F = F->next()) {
Object *obj = ObjectDB::get_instance(F->key());
+
if (!obj)
continue;
+
+ ObjectID obj_id = obj->get_instance_id();
+
+ // Use a placeholder for now to avoid losing the state when saving a scene
+
obj->set_script(scr.get_ref_ptr());
- // Save reload state for next time if not saved
- if (!scr->pending_reload_state.has(obj->get_instance_id())) {
- scr->pending_reload_state[obj->get_instance_id()] = F->get();
+
+ PlaceHolderScriptInstance *placeholder = scr->placeholder_instance_create(obj);
+ obj->set_script_instance(placeholder);
+
+ // Even though build didn't fail, this tells the placeholder to keep properties and
+ // it allows using property_set_fallback for restoring the state without a valid script.
+ placeholder->set_build_failed(true);
+
+ // Restore Variant properties state, it will be kept by the placeholder until the next script reloading
+ for (List<Pair<StringName, Variant> >::Element *G = scr->pending_reload_state[obj_id].properties.front(); G; G = G->next()) {
+ placeholder->property_set_fallback(G->get().first, G->get().second, NULL);
}
+
+ scr->pending_reload_state.erase(obj_id);
}
}
return;
}
- for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
+ for (List<Ref<CSharpScript> >::Element *E = to_reload.front(); E; E = E->next()) {
- Ref<CSharpScript> scr = E->key();
+ Ref<CSharpScript> scr = E->get();
scr->exports_invalidated = true;
scr->signals_invalidated = true;
scr->reload(p_soft_reload);
scr->update_exports();
- //restore state if saved
- for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) {
+ {
+#ifdef DEBUG_ENABLED
+ for (Set<ObjectID>::Element *F = scr->pending_reload_instances.front(); F; F = F->next()) {
+ ObjectID obj_id = F->get();
+ Object *obj = ObjectDB::get_instance(obj_id);
+
+ if (!obj) {
+ scr->pending_reload_state.erase(obj_id);
+ continue;
+ }
- Object *obj = ObjectDB::get_instance(F->key());
- if (!obj)
- continue;
+ ScriptInstance *si = obj->get_script_instance();
- if (!p_soft_reload) {
- //clear it just in case (may be a pending reload state)
- obj->set_script(RefPtr());
- }
- obj->set_script(scr.get_ref_ptr());
- if (!obj->get_script_instance()) {
- //failed, save reload state for next time if not saved
- if (!scr->pending_reload_state.has(obj->get_instance_id())) {
- scr->pending_reload_state[obj->get_instance_id()] = F->get();
+#ifdef TOOLS_ENABLED
+ if (si) {
+ // If the script instance is not null, then it must be a placeholder.
+ // Non-placeholder script instances are removed in godot_icall_Object_Disposed.
+ CRASH_COND(!si->is_placeholder());
+
+ if (scr->is_tool() || ScriptServer::is_scripting_enabled()) {
+ // Replace placeholder with a script instance
+
+ CSharpScript::StateBackup &state_backup = scr->pending_reload_state[obj_id];
+
+ // Backup placeholder script instance state before replacing it with a script instance
+ obj->get_script_instance()->get_property_state(state_backup.properties);
+
+ ScriptInstance *script_instance = scr->instance_create(obj);
+
+ if (script_instance) {
+ scr->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(si));
+ obj->set_script_instance(script_instance);
+ }
+
+ // TODO: Restore serialized state
+
+ for (List<Pair<StringName, Variant> >::Element *G = state_backup.properties.front(); G; G = G->next()) {
+ script_instance->set(G->get().first, G->get().second);
+ }
+
+ scr->pending_reload_state.erase(obj_id);
+ }
+
+ continue;
}
- continue;
- }
+#else
+ CRASH_COND(si != NULL);
+#endif
+ // Re-create script instance
- if (scr->valid && scr->is_tool() && obj->get_script_instance()->is_placeholder()) {
- // Script instance was a placeholder, but now the script was built successfully and is a tool script.
- // We have to replace the placeholder with an actual C# script instance.
- scr->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(obj->get_script_instance()));
- ScriptInstance *script_instance = scr->instance_create(obj);
- obj->set_script_instance(script_instance); // Not necessary as it's already done in instance_create, but just in case...
- }
+ obj->set_script(scr.get_ref_ptr()); // will create the script instance as well
+
+ // TODO: Restore serialized state
+
+ for (List<Pair<StringName, Variant> >::Element *G = scr->pending_reload_state[obj_id].properties.front(); G; G = G->next()) {
+ obj->get_script_instance()->set(G->get().first, G->get().second);
+ }
- for (List<Pair<StringName, Variant> >::Element *G = F->get().front(); G; G = G->next()) {
- obj->get_script_instance()->set(G->get().first, G->get().second);
+ scr->pending_reload_state.erase(obj_id);
}
+#endif
- scr->pending_reload_state.erase(obj->get_instance_id()); //as it reloaded, remove pending state
+ scr->pending_reload_instances.clear();
}
-
- //if instance states were saved, set them!
}
+ // FIXME: Hack to refresh editor in order to display new properties and signals. See if there is a better alternative.
if (Engine::get_singleton()->is_editor_hint()) {
EditorNode::get_singleton()->get_inspector()->update_tree();
NodeDock::singleton->update_lists();
@@ -940,27 +993,18 @@ void CSharpLanguage::set_language_index(int p_idx) {
void CSharpLanguage::release_script_gchandle(Ref<MonoGCHandle> &p_gchandle) {
- if (!p_gchandle->is_released()) { // Do not locking unnecessarily
-#ifndef NO_THREADS
- get_singleton()->script_gchandle_release_lock->lock();
-#endif
-
+ if (!p_gchandle->is_released()) { // Do not lock unnecessarily
+ SCOPED_MUTEX_LOCK(get_singleton()->script_gchandle_release_mutex);
p_gchandle->release();
-
-#ifndef NO_THREADS
- get_singleton()->script_gchandle_release_lock->unlock();
-#endif
}
}
-void CSharpLanguage::release_script_gchandle(MonoObject *p_pinned_expected_obj, Ref<MonoGCHandle> &p_gchandle) {
+void CSharpLanguage::release_script_gchandle(MonoObject *p_expected_obj, Ref<MonoGCHandle> &p_gchandle) {
- uint32_t pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(p_pinned_expected_obj); // we might lock after this, so pin it
+ uint32_t pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(p_expected_obj); // We might lock after this, so pin it
- if (!p_gchandle->is_released()) { // Do not locking unnecessarily
-#ifndef NO_THREADS
- get_singleton()->script_gchandle_release_lock->lock();
-#endif
+ if (!p_gchandle->is_released()) { // Do not lock unnecessarily
+ SCOPED_MUTEX_LOCK(get_singleton()->script_gchandle_release_mutex);
MonoObject *target = p_gchandle->get_target();
@@ -968,13 +1012,9 @@ void CSharpLanguage::release_script_gchandle(MonoObject *p_pinned_expected_obj,
// already released and could have been replaced) or if we can't get its target MonoObject*
// (which doesn't necessarily mean it was released, and we want it released in order to
// avoid locking other threads unnecessarily).
- if (target == p_pinned_expected_obj || target == NULL) {
+ if (target == p_expected_obj || target == NULL) {
p_gchandle->release();
}
-
-#ifndef NO_THREADS
- get_singleton()->script_gchandle_release_lock->unlock();
-#endif
}
MonoGCHandle::free_handle(pinned_gchandle);
@@ -990,13 +1030,13 @@ CSharpLanguage::CSharpLanguage() {
gdmono = NULL;
#ifdef NO_THREADS
- lock = NULL;
- gchandle_bind_lock = NULL;
- script_gchandle_release_lock = NULL;
+ script_instances_mutex = NULL;
+ script_gchandle_release_mutex = NULL;
+ language_bind_mutex = NULL;
#else
- lock = Mutex::create();
- script_bind_lock = Mutex::create();
- script_gchandle_release_lock = Mutex::create();
+ script_instances_mutex = Mutex::create();
+ script_gchandle_release_mutex = Mutex::create();
+ language_bind_mutex = Mutex::create();
#endif
lang_idx = -1;
@@ -1006,19 +1046,19 @@ CSharpLanguage::~CSharpLanguage() {
finish();
- if (lock) {
- memdelete(lock);
- lock = NULL;
+ if (script_instances_mutex) {
+ memdelete(script_instances_mutex);
+ script_instances_mutex = NULL;
}
- if (script_bind_lock) {
- memdelete(script_bind_lock);
- script_bind_lock = NULL;
+ if (language_bind_mutex) {
+ memdelete(language_bind_mutex);
+ language_bind_mutex = NULL;
}
- if (script_gchandle_release_lock) {
- memdelete(script_gchandle_release_lock);
- script_gchandle_release_lock = NULL;
+ if (script_gchandle_release_mutex) {
+ memdelete(script_gchandle_release_mutex);
+ script_gchandle_release_mutex = NULL;
}
singleton = NULL;
@@ -1055,15 +1095,12 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
script_binding.wrapper_class = type_class; // cache
script_binding.gchandle = MonoGCHandle::create_strong(mono_object);
-#ifndef NO_THREADS
- script_bind_lock->lock();
-#endif
-
- void *data = (void *)script_bindings.insert(p_object, script_binding);
+ void *data;
-#ifndef NO_THREADS
- script_bind_lock->unlock();
-#endif
+ {
+ SCOPED_MUTEX_LOCK(language_bind_mutex);
+ data = (void *)script_bindings.insert(p_object, script_binding);
+ }
// Tie managed to unmanaged
Reference *ref = Object::cast_to<Reference>(p_object);
@@ -1093,23 +1130,19 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
if (finalizing)
return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
-#ifndef NO_THREADS
- script_bind_lock->lock();
-#endif
-
- Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data;
+ {
+ SCOPED_MUTEX_LOCK(language_bind_mutex);
- // Set the native instance field to IntPtr.Zero, if not yet garbage collected
- MonoObject *mono_object = data->value().gchandle->get_target();
- if (mono_object) {
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
- }
+ Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_data;
- script_bindings.erase(data);
+ // Set the native instance field to IntPtr.Zero, if not yet garbage collected
+ MonoObject *mono_object = data->value().gchandle->get_target();
+ if (mono_object) {
+ CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
+ }
-#ifndef NO_THREADS
- script_bind_lock->unlock();
-#endif
+ script_bindings.erase(data);
+ }
}
void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
@@ -1524,7 +1557,7 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
} else {
r_owner_deleted = false;
CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
- if (p_is_finalizer) {
+ if (p_is_finalizer && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
// If the native instance is still alive, then it was
// referenced from another thread before the finalizer could
// unreference it and delete it, so we want to keep it.
@@ -1651,6 +1684,8 @@ void CSharpInstance::notification(int p_notification) {
// It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed
// to be sent at least once, which happens right before the call to the destructor.
+ predelete_notified = true;
+
if (base_ref) {
// It's not safe to proceed if the owner derives Reference and the refcount reached 0.
// At this point, Dispose() was already called (manually or from the finalizer) so
@@ -1666,10 +1701,8 @@ void CSharpInstance::notification(int p_notification) {
MonoObject *mono_object = get_mono_object();
ERR_FAIL_NULL(mono_object);
- GDMonoUtils::GodotObject_Dispose thunk = CACHED_METHOD_THUNK(GodotObject, Dispose);
-
MonoException *exc = NULL;
- thunk(mono_object, (MonoObject **)&exc);
+ GDMonoUtils::dispose(mono_object, &exc);
if (exc) {
GDMonoUtils::set_pending_exception(exc);
@@ -1720,12 +1753,35 @@ CSharpInstance::CSharpInstance() :
owner(NULL),
base_ref(false),
ref_dying(false),
- unsafe_referenced(false) {
+ unsafe_referenced(false),
+ predelete_notified(false),
+ destructing_script_instance(false) {
}
CSharpInstance::~CSharpInstance() {
if (gchandle.is_valid()) {
+ if (!predelete_notified && !ref_dying) {
+ // This destructor is not called from the owners destructor.
+ // This could be being called from the owner's set_script_instance method,
+ // meaning this script is being replaced with another one. If this is the case,
+ // we must call Dispose here, because Dispose calls owner->set_script_instance(NULL)
+ // and that would mess up with the new script instance if called later.
+
+ MonoObject *mono_object = gchandle->get_target();
+
+ if (mono_object) {
+ MonoException *exc = NULL;
+ destructing_script_instance = true;
+ GDMonoUtils::dispose(mono_object, &exc);
+ destructing_script_instance = false;
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ }
+ }
+ }
+
gchandle->release(); // Make sure it's released
}
@@ -1734,9 +1790,7 @@ CSharpInstance::~CSharpInstance() {
}
if (script.is_valid() && owner) {
-#ifndef NO_THREADS
- CSharpLanguage::singleton->lock->lock();
-#endif
+ SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
#ifdef DEBUG_ENABLED
// CSharpInstance must not be created unless it's going to be added to the list for sure
@@ -1746,10 +1800,6 @@ CSharpInstance::~CSharpInstance() {
#else
script->instances.erase(owner);
#endif
-
-#ifndef NO_THREADS
- CSharpLanguage::singleton->lock->unlock();
-#endif
}
}
@@ -1882,10 +1932,8 @@ bool CSharpScript::_update_exports() {
// Dispose the temporary managed instance
- GDMonoUtils::GodotObject_Dispose thunk = CACHED_METHOD_THUNK(GodotObject, Dispose);
-
MonoException *exc = NULL;
- thunk(tmp_object, (MonoObject **)&exc);
+ GDMonoUtils::dispose(tmp_object, &exc);
if (exc) {
ERR_PRINT("Exception thrown from method Dispose() of temporary MonoObject:");
@@ -2312,17 +2360,13 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
ERR_FAIL_V(NULL);
}
- uint32_t pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(mono_object); // we might lock after this, so pin it
-
-#ifndef NO_THREADS
- CSharpLanguage::singleton->lock->lock();
-#endif
-
- instances.insert(instance->owner);
+ // Tie managed to unmanaged
+ instance->gchandle = MonoGCHandle::create_strong(mono_object);
-#ifndef NO_THREADS
- CSharpLanguage::singleton->lock->unlock();
-#endif
+ {
+ SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+ instances.insert(instance->owner);
+ }
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, instance->owner);
@@ -2330,13 +2374,8 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
ctor->invoke(mono_object, p_args);
- // Tie managed to unmanaged
- instance->gchandle = MonoGCHandle::create_strong(mono_object);
-
/* STEP 3, PARTY */
- MonoGCHandle::free_handle(pinned_gchandle);
-
//@TODO make thread safe
return instance;
}
@@ -2411,17 +2450,8 @@ PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_t
bool CSharpScript::instance_has(const Object *p_this) const {
-#ifndef NO_THREADS
- CSharpLanguage::singleton->lock->lock();
-#endif
-
- bool ret = instances.has((Object *)p_this);
-
-#ifndef NO_THREADS
- CSharpLanguage::singleton->lock->unlock();
-#endif
-
- return ret;
+ SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+ return instances.has((Object *)p_this);
}
bool CSharpScript::has_source_code() const {
@@ -2454,15 +2484,11 @@ bool CSharpScript::has_method(const StringName &p_method) const {
Error CSharpScript::reload(bool p_keep_state) {
-#ifndef NO_THREADS
- CSharpLanguage::singleton->lock->lock();
-#endif
-
- bool has_instances = instances.size();
-
-#ifndef NO_THREADS
- CSharpLanguage::singleton->lock->unlock();
-#endif
+ bool has_instances;
+ {
+ SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+ has_instances = instances.size();
+ }
ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE);
@@ -2648,35 +2674,19 @@ CSharpScript::CSharpScript() :
_resource_path_changed();
#ifdef DEBUG_ENABLED
-
-#ifndef NO_THREADS
- CSharpLanguage::get_singleton()->lock->lock();
-#endif
-
- CSharpLanguage::get_singleton()->script_list.add(&script_list);
-
-#ifndef NO_THREADS
- CSharpLanguage::get_singleton()->lock->unlock();
+ {
+ SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+ CSharpLanguage::get_singleton()->script_list.add(&this->script_list);
+ }
#endif
-
-#endif // DEBUG_ENABLED
}
CSharpScript::~CSharpScript() {
#ifdef DEBUG_ENABLED
-
-#ifndef NO_THREADS
- CSharpLanguage::get_singleton()->lock->lock();
+ SCOPED_MUTEX_LOCK(CSharpLanguage::get_singleton()->script_instances_mutex);
+ CSharpLanguage::get_singleton()->script_list.remove(&this->script_list);
#endif
-
- CSharpLanguage::get_singleton()->script_list.remove(&script_list);
-
-#ifndef NO_THREADS
- CSharpLanguage::get_singleton()->lock->unlock();
-#endif
-
-#endif // DEBUG_ENABLED
}
/*************** RESOURCE ***************/
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index fc604df2a0..501e0d9d6d 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -82,6 +82,21 @@ class CSharpScript : public Script {
Set<Object *> instances;
+#ifdef DEBUG_ENABLED
+ Set<ObjectID> pending_reload_instances;
+#endif
+
+ struct StateBackup {
+ // TODO
+ // Replace with buffer containing the serialized state of managed scripts.
+ // Keep variant state backup to use only with script instance placeholders.
+ List<Pair<StringName, Variant> > properties;
+ };
+
+#ifdef TOOLS_ENABLED
+ Map<ObjectID, CSharpScript::StateBackup> pending_reload_state;
+#endif
+
String source;
StringName name;
@@ -105,10 +120,6 @@ class CSharpScript : public Script {
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
#endif
-#ifdef DEBUG_ENABLED
- Map<ObjectID, List<Pair<StringName, Variant> > > pending_reload_state;
-#endif
-
Map<StringName, PropertyInfo> member_info;
void _clear();
@@ -158,6 +169,8 @@ public:
virtual void update_exports();
virtual bool is_tool() const { return tool; }
+ virtual bool is_valid() const { return valid; }
+
virtual Ref<Script> get_base_script() const;
virtual ScriptLanguage *get_language() const;
@@ -184,6 +197,8 @@ class CSharpInstance : public ScriptInstance {
bool base_ref;
bool ref_dying;
bool unsafe_referenced;
+ bool predelete_notified;
+ bool destructing_script_instance;
Ref<CSharpScript> script;
Ref<MonoGCHandle> gchandle;
@@ -204,6 +219,8 @@ class CSharpInstance : public ScriptInstance {
public:
MonoObject *get_mono_object() const;
+ _FORCE_INLINE_ bool is_destructing_script_instance() { return destructing_script_instance; }
+
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
@@ -253,11 +270,9 @@ class CSharpLanguage : public ScriptLanguage {
GDMono *gdmono;
SelfList<CSharpScript>::List script_list;
- Mutex *lock;
- Mutex *script_bind_lock;
- Mutex *script_gchandle_release_lock;
-
- Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
+ Mutex *script_instances_mutex;
+ Mutex *script_gchandle_release_mutex;
+ Mutex *language_bind_mutex;
Map<Object *, CSharpScriptBinding> script_bindings;
@@ -294,7 +309,8 @@ public:
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
#ifdef TOOLS_ENABLED
- void reload_assemblies_if_needed(bool p_soft_reload);
+ bool is_assembly_reloading_needed();
+ void reload_assemblies(bool p_soft_reload);
#endif
void project_assembly_loaded();
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index f27511ad5e..cce86efbf5 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -475,7 +475,9 @@ MonoReloadNode *MonoReloadNode::singleton = NULL;
void MonoReloadNode::_reload_timer_timeout() {
- CSharpLanguage::get_singleton()->reload_assemblies_if_needed(false);
+ if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) {
+ CSharpLanguage::get_singleton()->reload_assemblies(false);
+ }
}
void MonoReloadNode::restart_reload_timer() {
@@ -493,7 +495,9 @@ void MonoReloadNode::_notification(int p_what) {
switch (p_what) {
case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
restart_reload_timer();
- CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
+ if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) {
+ CSharpLanguage::get_singleton()->reload_assemblies(false);
+ }
} break;
default: {
} break;
diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp
index d7bfa54aba..e89d21d92d 100644
--- a/modules/mono/editor/mono_bottom_panel.cpp
+++ b/modules/mono/editor/mono_bottom_panel.cpp
@@ -154,10 +154,14 @@ void MonoBottomPanel::_build_project_pressed() {
Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path);
ERR_FAIL_COND(metadata_err != OK);
- GodotSharpBuilds::get_singleton()->build_project_blocking("Tools");
+ bool build_success = GodotSharpBuilds::get_singleton()->build_project_blocking("Tools");
- MonoReloadNode::get_singleton()->restart_reload_timer();
- CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
+ if (build_success) {
+ MonoReloadNode::get_singleton()->restart_reload_timer();
+ if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) {
+ CSharpLanguage::get_singleton()->reload_assemblies(false);
+ }
+ }
}
void MonoBottomPanel::_view_log_pressed() {
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index d718c3cc61..58916c5283 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -54,8 +54,10 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
if (p_ptr->get_script_instance()) {
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
if (cs_instance) {
- cs_instance->mono_object_disposed(p_obj);
- p_ptr->set_script_instance(NULL);
+ if (!cs_instance->is_destructing_script_instance()) {
+ cs_instance->mono_object_disposed(p_obj);
+ p_ptr->set_script_instance(NULL);
+ }
return;
}
}
@@ -82,12 +84,14 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_
if (ref->get_script_instance()) {
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance());
if (cs_instance) {
- bool r_owner_deleted;
- cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, r_owner_deleted);
- if (!r_owner_deleted && !p_is_finalizer) {
- // If the native instance is still alive and Dispose() was called
- // (instead of the finalizer), then we remove the script instance.
- ref->set_script_instance(NULL);
+ if (!cs_instance->is_destructing_script_instance()) {
+ bool r_owner_deleted;
+ cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, r_owner_deleted);
+ if (!r_owner_deleted && !p_is_finalizer) {
+ // If the native instance is still alive and Dispose() was called
+ // (instead of the finalizer), then we remove the script instance.
+ ref->set_script_instance(NULL);
+ }
}
return;
}
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 5d9b9213e7..f09e93e662 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -423,7 +423,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
MonoException *exc = NULL;
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -435,7 +435,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
exc = NULL;
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 2543f5dc47..3f0a5d6e50 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -163,7 +163,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
MonoException *exc = NULL;
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -172,7 +172,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
exc = NULL;
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
@@ -192,8 +192,11 @@ String mono_to_utf8_string(MonoString *p_mono_string) {
MonoError error;
char *utf8 = mono_string_to_utf8_checked(p_mono_string, &error);
- ERR_EXPLAIN("Conversion of MonoString to UTF8 failed.");
- ERR_FAIL_COND_V(!mono_error_ok(&error), String());
+ if (!mono_error_ok(&error)) {
+ ERR_PRINTS(String("Failed to convert MonoString* to UTF-8: ") + mono_error_get_message(&error));
+ mono_error_cleanup(&error);
+ return String();
+ }
String ret = String::utf8(utf8);
@@ -546,7 +549,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
MonoException *exc = NULL;
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -555,7 +558,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
exc = NULL;
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
@@ -710,16 +713,14 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (CACHED_CLASS(Array) == type_class) {
MonoException *exc = NULL;
- GDMonoUtils::Array_GetPtr get_ptr = CACHED_METHOD_THUNK(Array, GetPtr);
- Array *ptr = get_ptr(p_obj, (MonoObject **)&exc);
+ Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
if (CACHED_CLASS(Dictionary) == type_class) {
MonoException *exc = NULL;
- GDMonoUtils::Dictionary_GetPtr get_ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr);
- Dictionary *ptr = get_ptr(p_obj, (MonoObject **)&exc);
+ Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
@@ -731,7 +732,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
MonoException *exc = NULL;
GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
- MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc);
+ MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_dict) {
@@ -744,7 +745,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
exc = NULL;
GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
- MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc);
+ MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
UNLIKELY_UNHANDLED_EXCEPTION(exc);
if (is_array) {
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index fe2c09799c..211987d242 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -694,4 +694,8 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &
}
}
+void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
+ invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, (MonoObject **)r_exc);
+}
+
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index f00680ff03..170df32991 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -243,6 +243,8 @@ MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_param
uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error);
+void dispose(MonoObject *p_mono_object, MonoException **r_exc);
+
} // namespace GDMonoUtils
#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL)))
@@ -267,4 +269,93 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &
#define GD_MONO_END_RUNTIME_INVOKE \
_runtime_invoke_count_ref -= 1;
+inline void invoke_method_thunk(void (*p_method_thunk)()) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ p_method_thunk();
+ GD_MONO_END_RUNTIME_INVOKE;
+}
+
+template <class R>
+R invoke_method_thunk(R (*p_method_thunk)()) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ R r = p_method_thunk();
+ GD_MONO_END_RUNTIME_INVOKE;
+ return r;
+}
+
+template <class P1>
+void invoke_method_thunk(void (*p_method_thunk)(P1), P1 p_arg1) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ p_method_thunk(p_arg1);
+ GD_MONO_END_RUNTIME_INVOKE;
+}
+
+template <class R, class P1>
+R invoke_method_thunk(R (*p_method_thunk)(P1), P1 p_arg1) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ R r = p_method_thunk(p_arg1);
+ GD_MONO_END_RUNTIME_INVOKE;
+ return r;
+}
+
+template <class P1, class P2>
+void invoke_method_thunk(void (*p_method_thunk)(P1, P2), P1 p_arg1, P2 p_arg2) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ p_method_thunk(p_arg1, p_arg2);
+ GD_MONO_END_RUNTIME_INVOKE;
+}
+
+template <class R, class P1, class P2>
+R invoke_method_thunk(R (*p_method_thunk)(P1, P2), P1 p_arg1, P2 p_arg2) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ R r = p_method_thunk(p_arg1, p_arg2);
+ GD_MONO_END_RUNTIME_INVOKE;
+ return r;
+}
+
+template <class P1, class P2, class P3>
+void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3), P1 p_arg1, P2 p_arg2, P3 p_arg3) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ p_method_thunk(p_arg1, p_arg2, p_arg3);
+ GD_MONO_END_RUNTIME_INVOKE;
+}
+
+template <class R, class P1, class P2, class P3>
+R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3), P1 p_arg1, P2 p_arg2, P3 p_arg3) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ R r = p_method_thunk(p_arg1, p_arg2, p_arg3);
+ GD_MONO_END_RUNTIME_INVOKE;
+ return r;
+}
+
+template <class P1, class P2, class P3, class P4>
+void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3, P4), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4);
+ GD_MONO_END_RUNTIME_INVOKE;
+}
+
+template <class R, class P1, class P2, class P3, class P4>
+R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3, P4), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ R r = p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4);
+ GD_MONO_END_RUNTIME_INVOKE;
+ return r;
+}
+
+template <class P1, class P2, class P3, class P4, class P5>
+void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3, P4, P5), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4, P5 p_arg5) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4, p_arg5);
+ GD_MONO_END_RUNTIME_INVOKE;
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3, P4, P5), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4, P5 p_arg5) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ R r = p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4, p_arg5);
+ GD_MONO_END_RUNTIME_INVOKE;
+ return r;
+}
+
#endif // GD_MONOUTILS_H
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index fa1fbebb16..c6748309f3 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -98,11 +98,9 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc
mono_array_set(signal_args, MonoObject *, i, boxed);
}
- GDMonoUtils::SignalAwaiter_SignalCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback);
-
MonoException *exc = NULL;
GD_MONO_BEGIN_RUNTIME_INVOKE;
- thunk(get_target(), signal_args, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, (MonoObject **)&exc);
GD_MONO_END_RUNTIME_INVOKE;
if (exc) {
@@ -129,14 +127,12 @@ SignalAwaiterHandle::SignalAwaiterHandle(MonoObject *p_managed) :
SignalAwaiterHandle::~SignalAwaiterHandle() {
if (!completed) {
- GDMonoUtils::SignalAwaiter_FailureCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback);
-
MonoObject *awaiter = get_target();
if (awaiter) {
MonoException *exc = NULL;
GD_MONO_BEGIN_RUNTIME_INVOKE;
- thunk(awaiter, (MonoObject **)&exc);
+ invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, (MonoObject **)&exc);
GD_MONO_END_RUNTIME_INVOKE;
if (exc) {
diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h
index 40b47e8648..c801fb2f33 100644
--- a/modules/mono/utils/macros.h
+++ b/modules/mono/utils/macros.h
@@ -31,15 +31,17 @@
#ifndef UTIL_MACROS_H
#define UTIL_MACROS_H
+#define _GD_VARNAME_CONCAT_B(m_ignore, m_name) m_name
+#define _GD_VARNAME_CONCAT_A(m_a, m_b, m_c) _GD_VARNAME_CONCAT_B(hello there, m_a##m_b##m_c)
+#define _GD_VARNAME_CONCAT(m_a, m_b, m_c) _GD_VARNAME_CONCAT_A(m_a, m_b, m_c)
+#define GD_UNIQUE_NAME(m_name) _GD_VARNAME_CONCAT(m_name, _, __COUNTER__)
+
// noreturn
#if __cpp_static_assert
#define GD_STATIC_ASSERT(m_cond) static_assert((m_cond), "Condition '" #m_cond "' failed")
#else
-#define _GD_STATIC_ASSERT_VARNAME_CONCAT_B(m_ignore, m_name) m_name
-#define _GD_STATIC_ASSERT_VARNAME_CONCAT_A(m_a, m_b) GD_STATIC_ASSERT_VARNAME_CONCAT_B(hello there, m_a##m_b)
-#define _GD_STATIC_ASSERT_VARNAME_CONCAT(m_a, m_b) GD_STATIC_ASSERT_VARNAME_CONCAT_A(m_a, m_b)
-#define GD_STATIC_ASSERT(m_cond) typedef int GD_STATIC_ASSERT_VARNAME_CONCAT(godot_static_assert_, __COUNTER__)[((m_cond) ? 1 : -1)]
+#define GD_STATIC_ASSERT(m_cond) typedef int GD_UNIQUE_NAME(godot_static_assert)[((m_cond) ? 1 : -1)]
#endif
#undef _NO_RETURN_
diff --git a/modules/mono/utils/mutex_utils.h b/modules/mono/utils/mutex_utils.h
new file mode 100644
index 0000000000..07d659b6eb
--- /dev/null
+++ b/modules/mono/utils/mutex_utils.h
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* mutex_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef MUTEX_UTILS_H
+#define MUTEX_UTILS_H
+
+#include "core/error_macros.h"
+#include "core/os/mutex.h"
+
+#include "macros.h"
+
+class ScopedMutexLock {
+ Mutex *mutex;
+
+public:
+ ScopedMutexLock(Mutex *mutex) {
+ this->mutex = mutex;
+#ifndef NO_THREADS
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!mutex);
+#endif
+ this->mutex->lock();
+#endif
+ }
+
+ ~ScopedMutexLock() {
+#ifndef NO_THREADS
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!mutex);
+#endif
+ mutex->unlock();
+#endif
+ }
+};
+
+#define SCOPED_MUTEX_LOCK(m_mutex) ScopedMutexLock GD_UNIQUE_NAME(__scoped_mutex_lock__)(m_mutex);
+
+// TODO: Add version that receives a lambda instead, once C++11 is allowed
+
+#endif // MUTEX_UTILS_H
diff --git a/modules/squish/config.py b/modules/squish/config.py
index 098f1eafa9..1c8cd12a2d 100644
--- a/modules/squish/config.py
+++ b/modules/squish/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return env['tools']
+ return True
def configure(env):
pass
diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp
index a08ac7bd28..4161a0f6ae 100644
--- a/modules/squish/image_compress_squish.cpp
+++ b/modules/squish/image_compress_squish.cpp
@@ -30,8 +30,6 @@
#include "image_compress_squish.h"
-#include "core/print_string.h"
-
#include <squish.h>
void image_decompress_squish(Image *p_image) {
@@ -76,6 +74,7 @@ void image_decompress_squish(Image *p_image) {
p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
}
+#ifdef TOOLS_ENABLED
void image_compress_squish(Image *p_image, float p_lossy_quality, Image::CompressSource p_source) {
if (p_image->get_format() >= Image::FORMAT_DXT1)
@@ -204,3 +203,4 @@ void image_compress_squish(Image *p_image, float p_lossy_quality, Image::Compres
p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
}
}
+#endif
diff --git a/modules/squish/image_compress_squish.h b/modules/squish/image_compress_squish.h
index dfebdc955f..dd53f2787a 100644
--- a/modules/squish/image_compress_squish.h
+++ b/modules/squish/image_compress_squish.h
@@ -33,7 +33,9 @@
#include "core/image.h"
+#ifdef TOOLS_ENABLED
void image_compress_squish(Image *p_image, float p_lossy_quality, Image::CompressSource p_source);
+#endif
void image_decompress_squish(Image *p_image);
#endif // IMAGE_COMPRESS_SQUISH_H
diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp
index d4ed676cce..9a5bb47f19 100644
--- a/modules/squish/register_types.cpp
+++ b/modules/squish/register_types.cpp
@@ -29,17 +29,14 @@
/*************************************************************************/
#include "register_types.h"
-
-#ifdef TOOLS_ENABLED
-
#include "image_compress_squish.h"
void register_squish_types() {
+#ifdef TOOLS_ENABLED
Image::set_compress_bc_func(image_compress_squish);
+#endif
Image::_image_decompress_bc = image_decompress_squish;
}
void unregister_squish_types() {}
-
-#endif
diff --git a/modules/squish/register_types.h b/modules/squish/register_types.h
index 00f5c345c4..9dbd69c46b 100644
--- a/modules/squish/register_types.h
+++ b/modules/squish/register_types.h
@@ -28,7 +28,5 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef TOOLS_ENABLED
void register_squish_types();
void unregister_squish_types();
-#endif
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 186e9e63b1..5b3b3a6769 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -981,6 +981,10 @@ bool VisualScript::is_tool() const {
return false;
}
+bool VisualScript::is_valid() const {
+ return true; //always valid
+}
+
ScriptLanguage *VisualScript::get_language() const {
return VisualScriptLanguage::singleton;
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index bd666447a3..cdc9159a73 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -341,6 +341,7 @@ public:
virtual Error reload(bool p_keep_state = false);
virtual bool is_tool() const;
+ virtual bool is_valid() const;
virtual ScriptLanguage *get_language() const;
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 3766f732e4..a3b5b6dd58 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -672,10 +672,13 @@ class EditorExportAndroid : public EditorExportPlatform {
aperms++;
}
- for (int i = 0; i < MAX_USER_PERMISSIONS; i++) {
- String user_perm = p_preset->get("user_permissions/" + itos(i));
- if (user_perm.strip_edges() != "" && user_perm.strip_edges() != "False")
- perms.push_back(user_perm.strip_edges());
+ PoolStringArray user_perms = p_preset->get("permissions/custom_permissions");
+
+ for (int i = 0; i < user_perms.size(); i++) {
+ String user_perm = user_perms[i].strip_edges();
+ if (!user_perm.empty()) {
+ perms.push_back(user_perm);
+ }
}
if (p_give_internet) {
@@ -1104,10 +1107,6 @@ class EditorExportAndroid : public EditorExportPlatform {
}
public:
- enum {
- MAX_USER_PERMISSIONS = 20
- };
-
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total);
public:
@@ -1169,17 +1168,14 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default));
}
+ r_options->push_back(ExportOption(PropertyInfo(Variant::POOL_STRING_ARRAY, "permissions/custom_permissions"), PoolStringArray()));
+
const char **perms = android_perms;
while (*perms) {
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "permissions/" + String(*perms).to_lower()), false));
perms++;
}
-
- for (int i = 0; i < MAX_USER_PERMISSIONS; i++) {
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "user_permissions/" + itos(i)), false));
- }
}
virtual String get_name() const {
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index 7a6613bb32..a5b627b8dc 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -44,6 +44,11 @@ extern "C" EMSCRIPTEN_KEEPALIVE void audio_driver_js_mix() {
AudioDriverJavaScript::singleton->mix_to_js();
}
+extern "C" EMSCRIPTEN_KEEPALIVE void audio_driver_process_capture(float sample) {
+
+ AudioDriverJavaScript::singleton->process_capture(sample);
+}
+
void AudioDriverJavaScript::mix_to_js() {
int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode());
@@ -51,31 +56,39 @@ void AudioDriverJavaScript::mix_to_js() {
int32_t *stream_buffer = reinterpret_cast<int32_t *>(internal_buffer);
audio_server_process(sample_count, stream_buffer);
for (int i = 0; i < sample_count * channel_count; i++) {
- internal_buffer[i] = float(stream_buffer[i] >> 16) / 32768.0;
+ internal_buffer[i] = float(stream_buffer[i] >> 16) / 32768.f;
}
}
+void AudioDriverJavaScript::process_capture(float sample) {
+
+ int32_t sample32 = int32_t(sample * 32768.f) * (1U << 16);
+ input_buffer_write(sample32);
+}
+
Error AudioDriverJavaScript::init() {
/* clang-format off */
EM_ASM({
_audioDriver_audioContext = new (window.AudioContext || window.webkitAudioContext);
+ _audioDriver_audioInput = null;
+ _audioDriver_inputStream = null;
_audioDriver_scriptNode = null;
});
/* clang-format on */
int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode());
/* clang-format off */
- int buffer_length = EM_ASM_INT({
+ buffer_length = EM_ASM_INT({
var CHANNEL_COUNT = $0;
var channelCount = _audioDriver_audioContext.destination.channelCount;
try {
// Try letting the browser recommend a buffer length.
- _audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(0, 0, channelCount);
+ _audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(0, 2, channelCount);
} catch (e) {
// ...otherwise, default to 4096.
- _audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(4096, 0, channelCount);
+ _audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(4096, 2, channelCount);
}
_audioDriver_scriptNode.connect(_audioDriver_audioContext.destination);
@@ -91,6 +104,7 @@ Error AudioDriverJavaScript::init() {
memdelete_arr(internal_buffer);
internal_buffer = memnew_arr(float, buffer_length *channel_count);
}
+
return internal_buffer ? OK : ERR_OUT_OF_MEMORY;
}
@@ -101,11 +115,13 @@ void AudioDriverJavaScript::start() {
var INTERNAL_BUFFER_PTR = $0;
var audioDriverMixFunction = cwrap('audio_driver_js_mix');
+ var audioDriverProcessCapture = cwrap('audio_driver_process_capture', null, ['number']);
_audioDriver_scriptNode.onaudioprocess = function(audioProcessingEvent) {
audioDriverMixFunction();
- // The output buffer contains the samples that will be modified and played.
+
+ var input = audioProcessingEvent.inputBuffer;
var output = audioProcessingEvent.outputBuffer;
- var input = HEAPF32.subarray(
+ var internalBuffer = HEAPF32.subarray(
INTERNAL_BUFFER_PTR / HEAPF32.BYTES_PER_ELEMENT,
INTERNAL_BUFFER_PTR / HEAPF32.BYTES_PER_ELEMENT + output.length * output.numberOfChannels);
@@ -113,8 +129,16 @@ void AudioDriverJavaScript::start() {
var outputData = output.getChannelData(channel);
// Loop through samples.
for (var sample = 0; sample < outputData.length; sample++) {
- // Set output equal to input.
- outputData[sample] = input[sample * output.numberOfChannels + channel];
+ outputData[sample] = internalBuffer[sample * output.numberOfChannels + channel];
+ }
+ }
+
+ if (_audioDriver_audioInput) {
+ var inputDataL = input.getChannelData(0);
+ var inputDataR = input.getChannelData(1);
+ for (var i = 0; i < inputDataL.length; i++) {
+ audioDriverProcessCapture(inputDataL[i]);
+ audioDriverProcessCapture(inputDataR[i]);
}
}
};
@@ -152,14 +176,74 @@ void AudioDriverJavaScript::finish() {
/* clang-format off */
EM_ASM({
_audioDriver_audioContext = null;
+ _audioDriver_audioInput = null;
_audioDriver_scriptNode = null;
});
/* clang-format on */
- memdelete_arr(internal_buffer);
- internal_buffer = NULL;
+
+ if (internal_buffer) {
+ memdelete_arr(internal_buffer);
+ internal_buffer = NULL;
+ }
+}
+
+Error AudioDriverJavaScript::capture_start() {
+
+ input_buffer_init(buffer_length);
+
+ /* clang-format off */
+ EM_ASM({
+ function gotMediaInput(stream) {
+ _audioDriver_inputStream = stream;
+ _audioDriver_audioInput = _audioDriver_audioContext.createMediaStreamSource(stream);
+ _audioDriver_audioInput.connect(_audioDriver_scriptNode);
+ }
+
+ function gotMediaInputError(e) {
+ console.log(e);
+ }
+
+ if (navigator.mediaDevices.getUserMedia) {
+ navigator.mediaDevices.getUserMedia({"audio": true}).then(gotMediaInput, gotMediaInputError);
+ } else {
+ if (!navigator.getUserMedia)
+ navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
+ navigator.getUserMedia({"audio": true}, gotMediaInput, gotMediaInputError);
+ }
+ });
+ /* clang-format on */
+
+ return OK;
+}
+
+Error AudioDriverJavaScript::capture_stop() {
+
+ /* clang-format off */
+ EM_ASM({
+ if (_audioDriver_inputStream) {
+ const tracks = _audioDriver_inputStream.getTracks();
+ for (var i = 0; i < tracks.length; i++) {
+ tracks[i].stop();
+ }
+ _audioDriver_inputStream = null;
+ }
+
+ if (_audioDriver_audioInput) {
+ _audioDriver_audioInput.disconnect();
+ _audioDriver_audioInput = null;
+ }
+
+ });
+ /* clang-format on */
+
+ input_buffer.clear();
+
+ return OK;
}
AudioDriverJavaScript::AudioDriverJavaScript() {
+ internal_buffer = NULL;
+
singleton = this;
}
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index a65a8ec29f..c8aeb0b446 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/javascript/audio_driver_javascript.h
@@ -37,8 +37,12 @@ class AudioDriverJavaScript : public AudioDriver {
float *internal_buffer;
+ int buffer_length;
+
public:
void mix_to_js();
+ void process_capture(float sample);
+
static AudioDriverJavaScript *singleton;
virtual const char *get_name() const;
@@ -51,6 +55,9 @@ public:
virtual void unlock();
virtual void finish();
+ virtual Error capture_start();
+ virtual Error capture_stop();
+
AudioDriverJavaScript();
};
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index cf85c3df7f..22b5f1f87a 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -122,6 +122,7 @@ def configure(env):
## Link flags
env.Append(LINKFLAGS=['-s', 'BINARYEN=1'])
+ env.Append(LINKFLAGS=['-s', 'BINARYEN_TRAP_MODE=\'clamp\''])
# Allow increasing memory buffer size during runtime. This is efficient
# when using WebAssembly (in comparison to asm.js) and works well for
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 41e59a5352..c0ea13e7fb 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -1134,7 +1134,7 @@ public:
} break;
}
- if (!exists_export_template("uwp_" + platform_infix + "_debug.zip", &err) || !exists_export_template("uwp_" + platform_infix + "_debug.zip", &err)) {
+ if (!exists_export_template("uwp_" + platform_infix + "_debug.zip", &err) || !exists_export_template("uwp_" + platform_infix + "_release.zip", &err)) {
valid = false;
r_missing_templates = true;
}
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index ae5891fa50..4a4aaf3238 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -158,7 +158,9 @@ void Area2D::_body_inout(int p_status, const RID &p_body, int p_instance, int p_
Map<ObjectID, BodyState>::Element *E = body_map.find(objid);
- ERR_FAIL_COND(!body_in && !E);
+ if (!body_in && !E) {
+ return; //does not exist because it was likely removed from the tree
+ }
locked = true;
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 613387bf07..93ad99272c 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -1305,9 +1305,9 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
ADD_GROUP("Color", "");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index 027d64b813..59cb16fe91 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -206,7 +206,9 @@ void ParallaxBackground::_bind_methods() {
ParallaxBackground::ParallaxBackground() {
- base_scale = Vector2(1, 1);
scale = 1.0;
set_layer(-1); //behind all by default
+
+ base_scale = Vector2(1, 1);
+ ignore_camera_zoom = false;
}
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index 5e78368804..ac77ddb7ce 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -157,7 +157,9 @@ void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_bo
Map<ObjectID, BodyState>::Element *E = body_map.find(objid);
- ERR_FAIL_COND(!body_in && !E);
+ if (!body_in && !E) {
+ return; //likely removed from the tree
+ }
locked = true;
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index 8b4d201083..0966a344cc 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -523,7 +523,7 @@ void CPUParticles::_particles_process(float p_delta) {
Basis velocity_xform;
if (!local_coords) {
emission_xform = get_global_transform();
- velocity_xform = emission_xform.basis.inverse().transposed();
+ velocity_xform = emission_xform.basis;
}
for (int i = 0; i < pcount; i++) {
@@ -691,7 +691,7 @@ void CPUParticles::_particles_process(float p_delta) {
if (flags[FLAG_DISABLE_Z]) {
p.velocity.z = 0.0;
- p.velocity.z = 0.0;
+ p.transform.origin.z = 0.0;
}
} else if (!p.active) {
@@ -757,15 +757,15 @@ void CPUParticles::_particles_process(float p_delta) {
}
Vector3 force = gravity;
- Vector3 pos = p.transform.origin;
+ Vector3 position = p.transform.origin;
if (flags[FLAG_DISABLE_Z]) {
- pos.z = 0.0;
+ position.z = 0.0;
}
//apply linear acceleration
force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector3();
//apply radial acceleration
Vector3 org = emission_xform.origin;
- Vector3 diff = pos - org;
+ Vector3 diff = position - org;
force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3();
//apply tangential acceleration;
if (flags[FLAG_DISABLE_Z]) {
@@ -1361,9 +1361,9 @@ void CPUParticles::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
ADD_GROUP("Color", "");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp
index 02c6b1d969..8fd86c940c 100644
--- a/scene/3d/physics_joint.cpp
+++ b/scene/3d/physics_joint.cpp
@@ -707,6 +707,9 @@ void Generic6DOFJoint::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flag_z", "flag", "value"), &Generic6DOFJoint::set_flag_z);
ClassDB::bind_method(D_METHOD("get_flag_z", "flag"), &Generic6DOFJoint::get_flag_z);
+ ClassDB::bind_method(D_METHOD("set_precision", "precision"), &Generic6DOFJoint::set_precision);
+ ClassDB::bind_method(D_METHOD("get_precision"), &Generic6DOFJoint::get_precision);
+
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/upper_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_UPPER_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/lower_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_LOWER_LIMIT);
@@ -795,6 +798,8 @@ void Generic6DOFJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_z/damping"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "precision", PROPERTY_HINT_RANGE, "1,99999,1"), "set_precision", "get_precision");
+
BIND_ENUM_CONSTANT(PARAM_LINEAR_LOWER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_LINEAR_UPPER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
@@ -907,6 +912,14 @@ bool Generic6DOFJoint::get_flag_z(Flag p_flag) const {
return flags_z[p_flag];
}
+void Generic6DOFJoint::set_precision(int p_precision) {
+ precision = p_precision;
+
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_precision(
+ get_joint(),
+ precision);
+}
+
RID Generic6DOFJoint::_configure_joint(PhysicsBody *body_a, PhysicsBody *body_b) {
Transform gt = get_global_transform();
@@ -941,7 +954,8 @@ RID Generic6DOFJoint::_configure_joint(PhysicsBody *body_a, PhysicsBody *body_b)
return j;
}
-Generic6DOFJoint::Generic6DOFJoint() {
+Generic6DOFJoint::Generic6DOFJoint() :
+ precision(1) {
set_param_x(PARAM_LINEAR_LOWER_LIMIT, 0);
set_param_x(PARAM_LINEAR_UPPER_LIMIT, 0);
diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h
index ee4ca28658..753795da90 100644
--- a/scene/3d/physics_joint.h
+++ b/scene/3d/physics_joint.h
@@ -305,6 +305,8 @@ protected:
float params_z[PARAM_MAX];
bool flags_z[FLAG_MAX];
+ int precision;
+
virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
static void _bind_methods();
@@ -327,6 +329,11 @@ public:
void set_flag_z(Flag p_flag, bool p_enabled);
bool get_flag_z(Flag p_flag) const;
+ void set_precision(int p_precision);
+ int get_precision() const {
+ return precision;
+ }
+
Generic6DOFJoint();
};
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index 1e730d0b3d..835a874323 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -401,7 +401,7 @@ String SoftBody::get_configuration_warning() const {
}
Transform t = get_transform();
- if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(0).length() - 1.0) > 0.05)) {
+ if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
if (!warning.empty())
warning += "\n\n";
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 64202ba0e3..7f9953ab43 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -1120,6 +1120,15 @@ void AnimationPlayer::queue(const StringName &p_name) {
queued.push_back(p_name);
}
+PoolVector<String> AnimationPlayer::get_queue() {
+ PoolVector<String> ret;
+ for (List<StringName>::Element *E = queued.front(); E; E = E->next()) {
+ ret.push_back(E->get());
+ }
+
+ return ret;
+}
+
void AnimationPlayer::clear_queue() {
queued.clear();
}
@@ -1603,6 +1612,7 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_assigned_animation", "anim"), &AnimationPlayer::set_assigned_animation);
ClassDB::bind_method(D_METHOD("get_assigned_animation"), &AnimationPlayer::get_assigned_animation);
ClassDB::bind_method(D_METHOD("queue", "name"), &AnimationPlayer::queue);
+ ClassDB::bind_method(D_METHOD("get_queue"), &AnimationPlayer::get_queue);
ClassDB::bind_method(D_METHOD("clear_queue"), &AnimationPlayer::clear_queue);
ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationPlayer::set_active);
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index f50b2454ec..b3bf8b1e22 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -312,6 +312,7 @@ public:
void play(const StringName &p_name = StringName(), float p_custom_blend = -1, float p_custom_scale = 1.0, bool p_from_end = false);
void play_backwards(const StringName &p_name = StringName(), float p_custom_blend = -1);
void queue(const StringName &p_name);
+ PoolVector<String> get_queue();
void clear_queue();
void stop(bool p_reset = true);
bool is_playing() const;
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index cf3113ca8c..4fe4271368 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -53,7 +53,7 @@ Size2 Tabs::get_minimum_size() const {
ms.width += get_constant("hseparation");
}
- ms.width += font->get_string_size(tabs[i].text).width;
+ ms.width += Math::ceil(font->get_string_size(tabs[i].text).width);
if (tabs[i].disabled)
ms.width += tab_disabled->get_minimum_size().width;
@@ -547,7 +547,7 @@ void Tabs::_update_cache() {
for (int i = 0; i < tabs.size(); i++) {
tabs.write[i].ofs_cache = mw;
tabs.write[i].size_cache = get_tab_width(i);
- tabs.write[i].size_text = font->get_string_size(tabs[i].text).width;
+ tabs.write[i].size_text = Math::ceil(font->get_string_size(tabs[i].text).width);
mw += tabs[i].size_cache;
if (tabs[i].size_cache <= min_width || i == current) {
size_fixed += tabs[i].size_cache;
@@ -803,7 +803,7 @@ int Tabs::get_tab_width(int p_idx) const {
x += get_constant("hseparation");
}
- x += font->get_string_size(tabs[p_idx].text).width;
+ x += Math::ceil(font->get_string_size(tabs[p_idx].text).width);
if (tabs[p_idx].disabled)
x += tab_disabled->get_minimum_size().width;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 5fe6fcdfac..c339cf6374 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -5758,6 +5758,7 @@ void TextEdit::_update_completion_candidates() {
completion_base = s;
Vector<float> sim_cache;
bool single_quote = s.begins_with("'");
+ Vector<String> completion_options_casei;
for (int i = 0; i < completion_strings.size(); i++) {
if (single_quote && completion_strings[i].is_quoted()) {
@@ -5766,9 +5767,13 @@ void TextEdit::_update_completion_candidates() {
if (completion_strings[i].begins_with(s)) {
completion_options.push_back(completion_strings[i]);
+ } else if (completion_strings[i].to_lower().begins_with(s.to_lower())) {
+ completion_options_casei.push_back(completion_strings[i]);
}
}
+ completion_options.append_array(completion_options_casei);
+
if (completion_options.size() == 0) {
for (int i = 0; i < completion_strings.size(); i++) {
if (s.is_subsequence_of(completion_strings[i])) {
@@ -6040,7 +6045,10 @@ void TextEdit::menu_option(int p_option) {
case MENU_UNDO: {
undo();
} break;
- };
+ case MENU_REDO: {
+ redo();
+ }
+ }
}
void TextEdit::set_select_identifiers_on_hover(bool p_enable) {
@@ -6216,6 +6224,7 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_CLEAR);
BIND_ENUM_CONSTANT(MENU_SELECT_ALL);
BIND_ENUM_CONSTANT(MENU_UNDO);
+ BIND_ENUM_CONSTANT(MENU_REDO);
BIND_ENUM_CONSTANT(MENU_MAX);
GLOBAL_DEF("gui/timers/text_edit_idle_detect_sec", 3);
@@ -6344,6 +6353,7 @@ TextEdit::TextEdit() {
menu->add_item(RTR("Clear"), MENU_CLEAR);
menu->add_separator();
menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
+ menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
menu->connect("id_pressed", this, "menu_option");
}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 8a508a8738..b1a0b60442 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -444,6 +444,7 @@ public:
MENU_CLEAR,
MENU_SELECT_ALL,
MENU_UNDO,
+ MENU_REDO,
MENU_MAX
};
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 8545efb966..fd584e82ad 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -189,7 +189,7 @@ Viewport::GUI::GUI() {
dragging = false;
mouse_focus = NULL;
mouse_click_grabber = NULL;
- mouse_focus_button = -1;
+ mouse_focus_mask = 0;
key_focus = NULL;
mouse_over = NULL;
@@ -671,15 +671,7 @@ void Viewport::_notification(int p_what) {
case SceneTree::NOTIFICATION_WM_FOCUS_OUT: {
if (gui.mouse_focus) {
//if mouse is being pressed, send a release event
- Ref<InputEventMouseButton> mb;
- mb.instance();
- mb->set_position(gui.mouse_focus->get_local_mouse_position());
- mb->set_global_position(gui.mouse_focus->get_local_mouse_position());
- mb->set_button_index(gui.mouse_focus_button);
- mb->set_pressed(false);
- Control *c = gui.mouse_focus;
- gui.mouse_focus = NULL;
- c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ _drop_mouse_focus();
}
} break;
}
@@ -1686,10 +1678,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (mb->is_pressed()) {
Size2 pos = mpos;
- if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button) {
-
- //do not steal mouse focus and stuff
+ if (gui.mouse_focus_mask) {
+ //do not steal mouse focus and stuff while a focus mask exists
+ gui.mouse_focus_mask |= 1 << (mb->get_button_index() - 1); //add the button to the mask
} else {
bool is_handled = false;
@@ -1734,7 +1726,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
*/
gui.mouse_focus = _gui_find_control(pos);
- gui.mouse_focus_button = mb->get_button_index();
+ gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1);
if (!gui.mouse_focus) {
return;
@@ -1788,7 +1780,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
- if (gui.mouse_focus->can_process()) {
+ if (gui.mouse_focus && gui.mouse_focus->can_process()) {
_gui_call_input(gui.mouse_focus, mb);
}
@@ -1837,6 +1829,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
//change mouse accordingly
}
+ gui.mouse_focus_mask &= ~(1 << (mb->get_button_index() - 1)); //remove from mask
+
if (!gui.mouse_focus) {
//release event is only sent if a mouse focus (previously pressed button) exists
return;
@@ -1852,9 +1846,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *mouse_focus = gui.mouse_focus;
//disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise
- if (mb->get_button_index() == gui.mouse_focus_button) {
+ if (gui.mouse_focus_mask == 0) {
gui.mouse_focus = NULL;
- gui.mouse_focus_button = -1;
}
if (mouse_focus->can_process()) {
@@ -1900,6 +1893,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_data.get_type() != Variant::NIL) {
gui.mouse_focus = NULL;
+ gui.mouse_focus_mask = 0;
break;
} else {
if (gui.drag_preview != NULL) {
@@ -2412,7 +2406,7 @@ void Viewport::_gui_unfocus_control(Control *p_control) {
void Viewport::_gui_hid_control(Control *p_control) {
if (gui.mouse_focus == p_control) {
- gui.mouse_focus = NULL;
+ _drop_mouse_focus();
}
/* ???
@@ -2439,8 +2433,10 @@ void Viewport::_gui_hid_control(Control *p_control) {
void Viewport::_gui_remove_control(Control *p_control) {
- if (gui.mouse_focus == p_control)
+ if (gui.mouse_focus == p_control) {
gui.mouse_focus = NULL;
+ gui.mouse_focus_mask = 0;
+ }
if (gui.key_focus == p_control)
gui.key_focus = NULL;
if (gui.mouse_over == p_control)
@@ -2489,6 +2485,27 @@ void Viewport::_gui_accept_event() {
set_input_as_handled();
}
+void Viewport::_drop_mouse_focus() {
+
+ Control *c = gui.mouse_focus;
+ int mask = gui.mouse_focus_mask;
+ gui.mouse_focus = NULL;
+ gui.mouse_focus_mask = 0;
+
+ for (int i = 0; i < 3; i++) {
+
+ if (mask & (1 << i)) {
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+ mb->set_position(c->get_local_mouse_position());
+ mb->set_global_position(c->get_local_mouse_position());
+ mb->set_button_index(i + 1);
+ mb->set_pressed(false);
+ c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ }
+ }
+}
+
List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
gui.modal_stack.push_back(p_control);
@@ -2498,15 +2515,8 @@ List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
p_control->_modal_set_prev_focus_owner(0);
if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
- Ref<InputEventMouseButton> mb;
- mb.instance();
- mb->set_position(gui.mouse_focus->get_local_mouse_position());
- mb->set_global_position(gui.mouse_focus->get_local_mouse_position());
- mb->set_button_index(gui.mouse_focus_button);
- mb->set_pressed(false);
- Control *c = gui.mouse_focus;
- gui.mouse_focus = NULL;
- c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+
+ _drop_mouse_focus();
}
return gui.modal_stack.back();
@@ -2536,24 +2546,45 @@ void Viewport::_post_gui_grab_click_focus() {
if (gui.mouse_focus == focus_grabber)
return;
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- //send unclic
+ int mask = gui.mouse_focus_mask;
Point2 click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
- mb->set_position(click);
- mb->set_button_index(gui.mouse_focus_button);
- mb->set_pressed(false);
- gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+
+ for (int i = 0; i < 3; i++) {
+
+ if (mask & (1 << i)) {
+
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+
+ //send unclic
+
+ mb->set_position(click);
+ mb->set_button_index(i + 1);
+ mb->set_pressed(false);
+ gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ }
+ }
gui.mouse_focus = focus_grabber;
gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse();
click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
- mb->set_position(click);
- mb->set_button_index(gui.mouse_focus_button);
- mb->set_pressed(true);
- gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb);
+
+ for (int i = 0; i < 3; i++) {
+
+ if (mask & (1 << i)) {
+
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+
+ //send clic
+
+ mb->set_position(click);
+ mb->set_button_index(i + 1);
+ mb->set_pressed(true);
+ gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb);
+ }
+ }
}
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 44fb322ae2..278350b1c9 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -272,7 +272,7 @@ private:
bool key_event_accepted;
Control *mouse_focus;
Control *mouse_click_grabber;
- int mouse_focus_button;
+ int mouse_focus_mask;
Control *key_focus;
Control *mouse_over;
Control *tooltip;
@@ -379,6 +379,8 @@ private:
void _canvas_layer_add(CanvasLayer *p_canvas_layer);
void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
+ void _drop_mouse_focus();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 97230d422b..d7750c91ef 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -210,8 +210,6 @@
#include "scene/resources/physics_material.h"
#endif
-static ResourceFormatLoaderTheme *resource_loader_theme = NULL;
-
static ResourceFormatSaverText *resource_saver_text = NULL;
static ResourceFormatLoaderText *resource_loader_text = NULL;
@@ -242,9 +240,6 @@ void register_scene_types() {
resource_loader_texture_layered = memnew(ResourceFormatLoaderTextureLayered);
ResourceLoader::add_resource_format_loader(resource_loader_texture_layered);
- resource_loader_theme = memnew(ResourceFormatLoaderTheme);
- ResourceLoader::add_resource_format_loader(resource_loader_theme);
-
resource_saver_text = memnew(ResourceFormatSaverText);
ResourceSaver::add_resource_format_saver(resource_saver_text, true);
@@ -743,7 +738,6 @@ void unregister_scene_types() {
memdelete(resource_loader_dynamic_font);
memdelete(resource_loader_stream_texture);
memdelete(resource_loader_texture_layered);
- memdelete(resource_loader_theme);
DynamicFont::finish_dynamic_fonts();
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index c9cdfe866f..90552ebb47 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -504,7 +504,7 @@ float Environment::get_ssao_edge_sharpness() const {
void Environment::set_glow_enabled(bool p_enabled) {
glow_enabled = p_enabled;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
_change_notify();
}
@@ -522,7 +522,7 @@ void Environment::set_glow_level(int p_level, bool p_enabled) {
else
glow_levels &= ~(1 << p_level);
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
}
bool Environment::is_glow_level_enabled(int p_level) const {
@@ -535,7 +535,7 @@ void Environment::set_glow_intensity(float p_intensity) {
glow_intensity = p_intensity;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
}
float Environment::get_glow_intensity() const {
@@ -545,7 +545,7 @@ float Environment::get_glow_intensity() const {
void Environment::set_glow_strength(float p_strength) {
glow_strength = p_strength;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
}
float Environment::get_glow_strength() const {
@@ -556,7 +556,7 @@ void Environment::set_glow_bloom(float p_threshold) {
glow_bloom = p_threshold;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
}
float Environment::get_glow_bloom() const {
@@ -567,7 +567,7 @@ void Environment::set_glow_blend_mode(GlowBlendMode p_mode) {
glow_blend_mode = p_mode;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
}
Environment::GlowBlendMode Environment::get_glow_blend_mode() const {
@@ -578,18 +578,29 @@ void Environment::set_glow_hdr_bleed_threshold(float p_threshold) {
glow_hdr_bleed_threshold = p_threshold;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
}
float Environment::get_glow_hdr_bleed_threshold() const {
return glow_hdr_bleed_threshold;
}
+void Environment::set_glow_hdr_luminance_cap(float p_amount) {
+
+ glow_hdr_luminance_cap = p_amount;
+
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+}
+float Environment::get_glow_hdr_luminance_cap() const {
+
+ return glow_hdr_luminance_cap;
+}
+
void Environment::set_glow_hdr_bleed_scale(float p_scale) {
glow_hdr_bleed_scale = p_scale;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
}
float Environment::get_glow_hdr_bleed_scale() const {
@@ -599,7 +610,7 @@ float Environment::get_glow_hdr_bleed_scale() const {
void Environment::set_glow_bicubic_upscale(bool p_enable) {
glow_bicubic_upscale = p_enable;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_bicubic_upscale);
+ VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
}
bool Environment::is_glow_bicubic_upscale_enabled() const {
@@ -1127,6 +1138,9 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_glow_hdr_bleed_threshold", "threshold"), &Environment::set_glow_hdr_bleed_threshold);
ClassDB::bind_method(D_METHOD("get_glow_hdr_bleed_threshold"), &Environment::get_glow_hdr_bleed_threshold);
+ ClassDB::bind_method(D_METHOD("set_glow_hdr_luminance_cap", "amount"), &Environment::set_glow_hdr_luminance_cap);
+ ClassDB::bind_method(D_METHOD("get_glow_hdr_luminance_cap"), &Environment::get_glow_hdr_luminance_cap);
+
ClassDB::bind_method(D_METHOD("set_glow_hdr_bleed_scale", "scale"), &Environment::set_glow_hdr_bleed_scale);
ClassDB::bind_method(D_METHOD("get_glow_hdr_bleed_scale"), &Environment::get_glow_hdr_bleed_scale);
@@ -1148,6 +1162,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "glow_bloom", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_glow_bloom", "get_glow_bloom");
ADD_PROPERTY(PropertyInfo(Variant::INT, "glow_blend_mode", PROPERTY_HINT_ENUM, "Additive,Screen,Softlight,Replace"), "set_glow_blend_mode", "get_glow_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "glow_hdr_threshold", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_threshold", "get_glow_hdr_bleed_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "glow_hdr_luminance_cap", PROPERTY_HINT_RANGE, "0.0,256.0,0.01"), "set_glow_hdr_luminance_cap", "get_glow_hdr_luminance_cap");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "glow_hdr_scale", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_scale", "get_glow_hdr_bleed_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_bicubic_upscale"), "set_glow_bicubic_upscale", "is_glow_bicubic_upscale_enabled");
@@ -1261,6 +1276,7 @@ Environment::Environment() {
glow_bloom = 0.0;
glow_blend_mode = GLOW_BLEND_MODE_SOFTLIGHT;
glow_hdr_bleed_threshold = 1.0;
+ glow_hdr_luminance_cap = 12.0;
glow_hdr_bleed_scale = 2.0;
glow_bicubic_upscale = false;
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index 4f5d44088a..55d96bc5bd 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -141,6 +141,7 @@ private:
GlowBlendMode glow_blend_mode;
float glow_hdr_bleed_threshold;
float glow_hdr_bleed_scale;
+ float glow_hdr_luminance_cap;
bool glow_bicubic_upscale;
bool dof_blur_far_enabled;
@@ -312,6 +313,9 @@ public:
void set_glow_hdr_bleed_threshold(float p_threshold);
float get_glow_hdr_bleed_threshold() const;
+ void set_glow_hdr_luminance_cap(float p_amount);
+ float get_glow_hdr_luminance_cap() const;
+
void set_glow_hdr_bleed_scale(float p_scale);
float get_glow_hdr_bleed_scale() const;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 682bfebdd2..4f4d375481 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -994,11 +994,11 @@ void AtlasTexture::_bind_methods() {
void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
- Rect2 rc = region;
-
if (!atlas.is_valid())
return;
+ Rect2 rc = region;
+
if (rc.size.width == 0) {
rc.size.width = atlas->get_width();
}
@@ -1013,11 +1013,11 @@ void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_m
void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
- Rect2 rc = region;
-
if (!atlas.is_valid())
return;
+ Rect2 rc = region;
+
if (rc.size.width == 0) {
rc.size.width = atlas->get_width();
}
@@ -1048,11 +1048,11 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
- Rect2 rc = region;
-
if (!atlas.is_valid())
return false;
+ Rect2 rc = region;
+
Rect2 src = p_src_rect;
if (src.size == Size2()) {
src.size = rc.size;
@@ -1084,11 +1084,13 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
- if (atlas.is_valid()) {
- return atlas->is_pixel_opaque(p_x + region.position.x + margin.position.x, p_x + region.position.y + margin.position.y);
- }
+ if (!atlas.is_valid())
+ return true;
- return true;
+ int x = p_x + region.position.x + margin.position.x;
+ int y = p_y + region.position.y + margin.position.y;
+
+ return atlas->is_pixel_opaque(x, y);
}
AtlasTexture::AtlasTexture() {
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index b102d477f2..3eb652ecd9 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -39,26 +39,6 @@ void Theme::_emit_theme_changed() {
emit_changed();
}
-void Theme::_ref_font(Ref<Font> p_sc) {
-
- if (!font_refcount.has(p_sc)) {
- font_refcount[p_sc] = 1;
- p_sc->connect("changed", this, "_emit_theme_changed");
- } else {
- font_refcount[p_sc] += 1;
- }
-}
-
-void Theme::_unref_font(Ref<Font> p_sc) {
-
- ERR_FAIL_COND(!font_refcount.has(p_sc));
- font_refcount[p_sc]--;
- if (font_refcount[p_sc] == 0) {
- p_sc->disconnect("changed", this, "_emit_theme_changed");
- font_refcount.erase(p_sc);
- }
-}
-
bool Theme::_set(const StringName &p_name, const Variant &p_value) {
String sname = p_name;
@@ -217,13 +197,13 @@ void Theme::set_default_theme_font(const Ref<Font> &p_default_font) {
return;
if (default_theme_font.is_valid()) {
- _unref_font(default_theme_font);
+ default_theme_font->disconnect("changed", this, "_emit_theme_changed");
}
default_theme_font = p_default_font;
if (default_theme_font.is_valid()) {
- _ref_font(default_theme_font);
+ default_theme_font->connect("changed", this, "_emit_theme_changed", varray(), CONNECT_REFERENCE_COUNTED);
}
_change_notify();
@@ -263,8 +243,16 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_type, const R
bool new_value = !icon_map.has(p_type) || !icon_map[p_type].has(p_name);
+ if (icon_map[p_type].has(p_name) && icon_map[p_type][p_name].is_valid()) {
+ icon_map[p_type][p_name]->disconnect("changed", this, "_emit_theme_changed");
+ }
+
icon_map[p_type][p_name] = p_icon;
+ if (p_icon.is_valid()) {
+ icon_map[p_type][p_name]->connect("changed", this, "_emit_theme_changed", varray(), CONNECT_REFERENCE_COUNTED);
+ }
+
if (new_value) {
_change_notify();
emit_changed();
@@ -290,7 +278,12 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_type) {
ERR_FAIL_COND(!icon_map.has(p_type));
ERR_FAIL_COND(!icon_map[p_type].has(p_name));
+ if (icon_map[p_type][p_name].is_valid()) {
+ icon_map[p_type][p_name]->disconnect("changed", this, "_emit_theme_changed");
+ }
+
icon_map[p_type].erase(p_name);
+
_change_notify();
emit_changed();
}
@@ -358,8 +351,16 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_type, con
bool new_value = !style_map.has(p_type) || !style_map[p_type].has(p_name);
+ if (style_map[p_type].has(p_name) && style_map[p_type][p_name].is_valid()) {
+ style_map[p_type][p_name]->disconnect("changed", this, "_emit_theme_changed");
+ }
+
style_map[p_type][p_name] = p_style;
+ if (p_style.is_valid()) {
+ style_map[p_type][p_name]->connect("changed", this, "_emit_theme_changed", varray(), CONNECT_REFERENCE_COUNTED);
+ }
+
if (new_value)
_change_notify();
emit_changed();
@@ -385,7 +386,12 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_type) {
ERR_FAIL_COND(!style_map.has(p_type));
ERR_FAIL_COND(!style_map[p_type].has(p_name));
+ if (style_map[p_type][p_name].is_valid()) {
+ style_map[p_type][p_name]->disconnect("changed", this, "_emit_theme_changed");
+ }
+
style_map[p_type].erase(p_name);
+
_change_notify();
emit_changed();
}
@@ -416,15 +422,14 @@ void Theme::set_font(const StringName &p_name, const StringName &p_type, const R
bool new_value = !font_map.has(p_type) || !font_map[p_type].has(p_name);
- if (!new_value) {
- if (font_map[p_type][p_name].is_valid()) {
- _unref_font(font_map[p_type][p_name]);
- }
+ if (font_map[p_type][p_name].is_valid()) {
+ font_map[p_type][p_name]->disconnect("changed", this, "_emit_theme_changed");
}
+
font_map[p_type][p_name] = p_font;
if (p_font.is_valid()) {
- _ref_font(p_font);
+ font_map[p_type][p_name]->connect("changed", this, "_emit_theme_changed", varray(), CONNECT_REFERENCE_COUNTED);
}
if (new_value) {
@@ -452,8 +457,8 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_type) {
ERR_FAIL_COND(!font_map.has(p_type));
ERR_FAIL_COND(!font_map[p_type].has(p_name));
- if (font_map.has(p_type) && font_map[p_type].has(p_name) && font_map[p_type][p_name].is_valid()) {
- _unref_font(font_map[p_type][p_name]);
+ if (font_map[p_type][p_name].is_valid()) {
+ font_map[p_type][p_name]->disconnect("changed", this, "_emit_theme_changed");
}
font_map[p_type].erase(p_name);
@@ -570,15 +575,91 @@ void Theme::get_constant_list(StringName p_type, List<StringName> *p_list) const
}
}
+void Theme::clear() {
+
+ //these need disconnecting
+ {
+ const StringName *K = NULL;
+ while ((K = icon_map.next(K))) {
+ const StringName *L = NULL;
+ while ((L = icon_map[*K].next(L))) {
+ icon_map[*K][*L]->disconnect("changed", this, "_emit_theme_changed");
+ }
+ }
+ }
+
+ {
+ const StringName *K = NULL;
+ while ((K = style_map.next(K))) {
+ const StringName *L = NULL;
+ while ((L = style_map[*K].next(L))) {
+ style_map[*K][*L]->disconnect("changed", this, "_emit_theme_changed");
+ }
+ }
+ }
+
+ {
+ const StringName *K = NULL;
+ while ((K = font_map.next(K))) {
+ const StringName *L = NULL;
+ while ((L = font_map[*K].next(L))) {
+ font_map[*K][*L]->disconnect("changed", this, "_emit_theme_changed");
+ }
+ }
+ }
+
+ icon_map.clear();
+ style_map.clear();
+ font_map.clear();
+ shader_map.clear();
+ color_map.clear();
+ constant_map.clear();
+
+ _change_notify();
+ emit_changed();
+}
+
void Theme::copy_default_theme() {
Ref<Theme> default_theme = get_default();
- icon_map = default_theme->icon_map;
- style_map = default_theme->style_map;
- font_map = default_theme->font_map;
+ //these need reconnecting, so add normally
+ {
+ const StringName *K = NULL;
+ while ((K = default_theme->icon_map.next(K))) {
+ const StringName *L = NULL;
+ while ((L = default_theme->icon_map[*K].next(L))) {
+ set_icon(*K, *L, default_theme->icon_map[*K][*L]);
+ }
+ }
+ }
+
+ {
+ const StringName *K = NULL;
+ while ((K = default_theme->style_map.next(K))) {
+ const StringName *L = NULL;
+ while ((L = default_theme->style_map[*K].next(L))) {
+ set_stylebox(*K, *L, default_theme->style_map[*K][*L]);
+ }
+ }
+ }
+
+ {
+ const StringName *K = NULL;
+ while ((K = default_theme->font_map.next(K))) {
+ const StringName *L = NULL;
+ while ((L = default_theme->font_map[*K].next(L))) {
+ set_font(*K, *L, default_theme->font_map[*K][*L]);
+ }
+ }
+ }
+
+ //these are ok to just copy
+
color_map = default_theme->color_map;
constant_map = default_theme->constant_map;
+ shader_map = default_theme->shader_map;
+
_change_notify();
emit_changed();
}
@@ -661,6 +742,8 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_constant", "name", "type"), &Theme::clear_constant);
ClassDB::bind_method(D_METHOD("get_constant_list", "type"), &Theme::_get_constant_list);
+ ClassDB::bind_method(D_METHOD("clear"), &Theme::clear);
+
ClassDB::bind_method(D_METHOD("set_default_font", "font"), &Theme::set_default_theme_font);
ClassDB::bind_method(D_METHOD("get_default_font"), &Theme::get_default_theme_font);
@@ -678,411 +761,3 @@ Theme::Theme() {
Theme::~Theme() {
}
-
-RES ResourceFormatLoaderTheme::load(const String &p_path, const String &p_original_path, Error *r_error) {
- if (r_error)
- *r_error = ERR_CANT_OPEN;
-
- Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
-
- ERR_EXPLAIN("Unable to open theme file: " + p_path);
- ERR_FAIL_COND_V(err, RES());
- String base_path = p_path.get_base_dir();
- Ref<Theme> theme(memnew(Theme));
- Map<StringName, Variant> library;
- if (r_error)
- *r_error = ERR_FILE_CORRUPT;
-
- bool reading_library = false;
- int line = 0;
-
- while (!f->eof_reached()) {
-
- String l = f->get_line().strip_edges();
- line++;
-
- int comment = l.find(";");
- if (comment != -1)
- l = l.substr(0, comment);
- if (l == "")
- continue;
-
- if (l.begins_with("[")) {
- if (l == "[library]") {
- reading_library = true;
- } else if (l == "[theme]") {
- reading_library = false;
- } else {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Unknown section type: '" + l + "'.");
- ERR_FAIL_V(RES());
- }
- continue;
- }
-
- int eqpos = l.find("=");
- if (eqpos == -1) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Expected '='.");
- ERR_FAIL_V(RES());
- }
-
- String right = l.substr(eqpos + 1, l.length()).strip_edges();
- if (right == "") {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Expected value after '='.");
- ERR_FAIL_V(RES());
- }
-
- Variant value;
-
- if (right.is_valid_integer()) {
- //is number
- value = right.to_int();
- } else if (right.is_valid_html_color()) {
- //is html color
- value = Color::html(right);
- } else if (right.begins_with("@")) { //reference
-
- String reference = right.substr(1, right.length());
- if (!library.has(reference)) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid reference to '" + reference + "'.");
- ERR_FAIL_V(RES());
- }
-
- value = library[reference];
-
- } else if (right.begins_with("default")) { //use default
- //do none
- } else {
- //attempt to parse a constructor
- int popenpos = right.find("(");
-
- if (popenpos == -1) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid constructor syntax: " + right);
- ERR_FAIL_V(RES());
- }
-
- int pclosepos = right.find_last(")");
-
- if (pclosepos == -1) {
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid constructor parameter syntax: " + right);
- ERR_FAIL_V(RES());
- }
-
- String type = right.substr(0, popenpos);
- String param = right.substr(popenpos + 1, pclosepos - popenpos - 1);
-
- if (type == "icon") {
-
- String path;
-
- if (param.is_abs_path())
- path = param;
- else
- path = base_path + "/" + param;
-
- Ref<Texture> texture = ResourceLoader::load(path);
- if (!texture.is_valid()) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Couldn't find icon at path: " + path);
- ERR_FAIL_V(RES());
- }
-
- value = texture;
-
- } else if (type == "sbox") {
-
- String path;
-
- if (param.is_abs_path())
- path = param;
- else
- path = base_path + "/" + param;
-
- Ref<StyleBox> stylebox = ResourceLoader::load(path);
- if (!stylebox.is_valid()) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Couldn't find stylebox at path: " + path);
- ERR_FAIL_V(RES());
- }
-
- value = stylebox;
-
- } else if (type == "sboxt") {
-
- Vector<String> params = param.split(",");
- if (params.size() != 5 && params.size() != 9) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid param count for sboxt(): '" + right + "'.");
- ERR_FAIL_V(RES());
- }
-
- String path = params[0];
-
- if (!param.is_abs_path())
- path = base_path + "/" + path;
-
- Ref<Texture> tex = ResourceLoader::load(path);
- if (tex.is_null()) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Could not open texture for sboxt at path: '" + params[0] + "'.");
- ERR_FAIL_V(RES());
- }
-
- Ref<StyleBoxTexture> sbtex(memnew(StyleBoxTexture));
-
- sbtex->set_texture(tex);
-
- for (int i = 0; i < 4; i++) {
- if (!params[i + 1].is_valid_integer()) {
-
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid expand margin parameter for sboxt #" + itos(i + 1) + ", expected integer constant, got: '" + params[i + 1] + "'.");
- ERR_FAIL_V(RES());
- }
-
- int margin = params[i + 1].to_int();
- sbtex->set_expand_margin_size(Margin(i), margin);
- }
-
- if (params.size() == 9) {
-
- for (int i = 0; i < 4; i++) {
-
- if (!params[i + 5].is_valid_integer()) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid expand margin parameter for sboxt #" + itos(i + 5) + ", expected integer constant, got: '" + params[i + 5] + "'.");
- ERR_FAIL_V(RES());
- }
-
- int margin = params[i + 5].to_int();
- sbtex->set_margin_size(Margin(i), margin);
- }
- }
-
- value = sbtex;
- } else if (type == "sboxf") {
-
- Vector<String> params = param.split(",");
- if (params.size() < 2) {
-
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid param count for sboxf(): '" + right + "'.");
- ERR_FAIL_V(RES());
- }
-
- Ref<StyleBoxFlat> sbflat(memnew(StyleBoxFlat));
-
- if (!params[0].is_valid_integer()) {
-
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Expected integer numeric constant for parameter 0 (border size).");
- ERR_FAIL_V(RES());
- }
-
- sbflat->set_border_width_all(params[0].to_int());
-
- if (!params[0].is_valid_integer()) {
-
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Expected integer numeric constant for parameter 0 (border size).");
- ERR_FAIL_V(RES());
- }
-
- int left = MIN(params.size() - 1, 3);
-
- int ccodes = 0;
-
- for (int i = 0; i < left; i++) {
-
- if (params[i + 1].is_valid_html_color())
- ccodes++;
- else
- break;
- }
-
- Color normal;
- Color bright;
- Color dark;
-
- if (ccodes < 1) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Expected at least 1, 2 or 3 html color codes.");
- ERR_FAIL_V(RES());
- } else if (ccodes == 1) {
-
- normal = Color::html(params[1]);
- bright = Color::html(params[1]);
- dark = Color::html(params[1]);
- } else if (ccodes == 2) {
-
- normal = Color::html(params[1]);
- bright = Color::html(params[2]);
- dark = Color::html(params[2]);
- } else {
-
- normal = Color::html(params[1]);
- bright = Color::html(params[2]);
- dark = Color::html(params[3]);
- }
-
- sbflat->set_border_color_all(bright);
- // sbflat->set_dark_color(dark);
- sbflat->set_bg_color(normal);
-
- if (params.size() == ccodes + 5) {
- //margins
- for (int i = 0; i < 4; i++) {
-
- if (!params[i + ccodes + 1].is_valid_integer()) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid expand margin parameter for sboxf #" + itos(i + ccodes + 1) + ", expected integer constant, got: '" + params[i + ccodes + 1] + "'.");
- ERR_FAIL_V(RES());
- }
-
- //int margin = params[i+ccodes+1].to_int();
- //sbflat->set_margin_size(Margin(i),margin);
- }
- } else if (params.size() != ccodes + 1) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid amount of margin parameters for sboxt.");
- ERR_FAIL_V(RES());
- }
-
- value = sbflat;
-
- } else {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid constructor type: '" + type + "'.");
- ERR_FAIL_V(RES());
- }
- }
-
- //parse left and do something with it
- String left = l.substr(0, eqpos);
-
- if (reading_library) {
-
- left = left.strip_edges();
- if (!left.is_valid_identifier()) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": <LibraryItem> is not a valid identifier.");
- ERR_FAIL_V(RES());
- }
- if (library.has(left)) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Already in library: '" + left + "'.");
- ERR_FAIL_V(RES());
- }
-
- library[left] = value;
- } else {
-
- int pointpos = left.find(".");
- if (pointpos == -1) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Expected 'control.item=..' assign syntax.");
- ERR_FAIL_V(RES());
- }
-
- String control = left.substr(0, pointpos).strip_edges();
- if (!control.is_valid_identifier()) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": <Control> is not a valid identifier.");
- ERR_FAIL_V(RES());
- }
- String item = left.substr(pointpos + 1, left.size()).strip_edges();
- if (!item.is_valid_identifier()) {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": <Item> is not a valid identifier.");
- ERR_FAIL_V(RES());
- }
-
- if (value.get_type() == Variant::NIL) {
- //try to use exiting
- if (Theme::get_default()->has_stylebox(item, control))
- value = Theme::get_default()->get_stylebox(item, control);
- else if (Theme::get_default()->has_font(item, control))
- value = Theme::get_default()->get_font(item, control);
- else if (Theme::get_default()->has_icon(item, control))
- value = Theme::get_default()->get_icon(item, control);
- else if (Theme::get_default()->has_color(item, control))
- value = Theme::get_default()->get_color(item, control);
- else if (Theme::get_default()->has_constant(item, control))
- value = Theme::get_default()->get_constant(item, control);
- else {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Default not present for: '" + control + "." + item + "'.");
- ERR_FAIL_V(RES());
- }
- }
-
- if (value.get_type() == Variant::OBJECT) {
-
- Ref<Resource> res = value;
- if (!res.is_valid()) {
-
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid resource (NULL).");
- ERR_FAIL_V(RES());
- }
-
- if (Object::cast_to<StyleBox>(*res)) {
- theme->set_stylebox(item, control, res);
- } else if (Object::cast_to<Font>(*res)) {
- theme->set_font(item, control, res);
- } else if (Object::cast_to<Font>(*res)) {
- theme->set_font(item, control, res);
- } else if (Object::cast_to<Texture>(*res)) {
- theme->set_icon(item, control, res);
- } else {
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Invalid resource type.");
- ERR_FAIL_V(RES());
- }
- } else if (value.get_type() == Variant::COLOR) {
-
- theme->set_color(item, control, value);
-
- } else if (value.get_type() == Variant::INT) {
-
- theme->set_constant(item, control, value);
-
- } else {
-
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + ": Couldn't even determine what this setting is! what did you do!?");
- ERR_FAIL_V(RES());
- }
- }
- }
-
- f->close();
- memdelete(f);
-
- if (r_error)
- *r_error = OK;
-
- return theme;
-}
-
-void ResourceFormatLoaderTheme::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("theme");
-}
-
-bool ResourceFormatLoaderTheme::handles_type(const String &p_type) const {
-
- return p_type == "Theme";
-}
-
-String ResourceFormatLoaderTheme::get_resource_type(const String &p_path) const {
-
- if (p_path.get_extension().to_lower() == "theme")
- return "Theme";
- return "";
-}
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 0b76e95f18..ba47c5fb3c 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -47,12 +47,6 @@ class Theme : public Resource {
RES_BASE_EXTENSION("theme");
static Ref<Theme> default_theme;
-
- //keep a reference count to font, so each time the font changes, we emit theme changed too
- Map<Ref<Font>, int> font_refcount;
-
- void _ref_font(Ref<Font> p_sc);
- void _unref_font(Ref<Font> p_sc);
void _emit_theme_changed();
HashMap<StringName, HashMap<StringName, Ref<Texture> > > icon_map;
@@ -190,17 +184,10 @@ public:
void get_type_list(List<StringName> *p_list) const;
void copy_default_theme();
+ void clear();
Theme();
~Theme();
};
-class ResourceFormatLoaderTheme : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
-
#endif
diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h
index b3c61403aa..c361d00fcc 100644
--- a/servers/physics/physics_server_sw.h
+++ b/servers/physics/physics_server_sw.h
@@ -348,6 +348,9 @@ public:
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable);
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag);
+ virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) {}
+ virtual int generic_6dof_joint_get_precision(RID p_joint) { return 0; }
+
virtual JointType joint_get_type(RID p_joint) const;
virtual void joint_set_solver_priority(RID p_joint, int p_priority);
diff --git a/servers/physics_server.h b/servers/physics_server.h
index 15b353f768..9fb5e958c3 100644
--- a/servers/physics_server.h
+++ b/servers/physics_server.h
@@ -734,6 +734,9 @@ public:
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) = 0;
virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) = 0;
+ virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) = 0;
+ virtual int generic_6dof_joint_get_precision(RID p_joint) = 0;
+
/* QUERY API */
enum AreaBodyStatus {
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 4329203ccb..f78b4aaf5f 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -62,7 +62,7 @@ public:
virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) = 0;
virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) = 0;
- virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) = 0;
+ virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) = 0;
virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) = 0;
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) = 0;
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index d37fe28ac6..f3a442be99 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -504,7 +504,7 @@ public:
BIND6(environment_set_dof_blur_near, RID, bool, float, float, float, EnvironmentDOFBlurQuality)
BIND6(environment_set_dof_blur_far, RID, bool, float, float, float, EnvironmentDOFBlurQuality)
- BIND10(environment_set_glow, RID, bool, int, float, float, float, EnvironmentGlowBlendMode, float, float, bool)
+ BIND11(environment_set_glow, RID, bool, int, float, float, float, EnvironmentGlowBlendMode, float, float, float, bool)
BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index 1aeb2756ba..37f6323b8f 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -430,7 +430,7 @@ public:
FUNC6(environment_set_dof_blur_near, RID, bool, float, float, float, EnvironmentDOFBlurQuality)
FUNC6(environment_set_dof_blur_far, RID, bool, float, float, float, EnvironmentDOFBlurQuality)
- FUNC10(environment_set_glow, RID, bool, int, float, float, float, EnvironmentGlowBlendMode, float, float, bool)
+ FUNC11(environment_set_glow, RID, bool, int, float, float, float, EnvironmentGlowBlendMode, float, float, float, bool)
FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 743e010034..ad2819a95a 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -733,7 +733,7 @@ public:
GLOW_BLEND_MODE_SOFTLIGHT,
GLOW_BLEND_MODE_REPLACE,
};
- virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) = 0;
+ virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) = 0;
enum EnvironmentToneMapper {
ENV_TONE_MAPPER_LINEAR,
diff --git a/thirdparty/squish/Add-Decompress-Bc5-to-Squish.patch b/thirdparty/squish/Add-Decompress-Bc5-to-Squish.patch
deleted file mode 100644
index 1e06a8d318..0000000000
--- a/thirdparty/squish/Add-Decompress-Bc5-to-Squish.patch
+++ /dev/null
@@ -1,143 +0,0 @@
-From 7b64cc4c8b0be0443741483bf65909f5140179c0 Mon Sep 17 00:00:00 2001
-From: Orkun <orkuntezerm@gmail.com>
-Date: Sun, 19 Nov 2017 02:24:31 +0300
-Subject: [PATCH] Fix #12220: Add Decompress Bc5 to Squish
-
-This Commit fixes the corrupted file preview described in #12220.
-Added DecompressColourBc5 function to squish.
----
- thirdparty/squish/colourblock.cpp | 85 +++++++++++++++++++++++++++++++++++++++
- thirdparty/squish/colourblock.h | 3 ++
- thirdparty/squish/squish.cpp | 8 +++-
- 3 files changed, 95 insertions(+), 1 deletion(-)
-
-diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
-index af8b98036..3de46382c 100644
---- a/thirdparty/squish/colourblock.cpp
-+++ b/thirdparty/squish/colourblock.cpp
-@@ -211,4 +211,89 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
- }
- }
-
-+// -- Godot start --
-+void DecompressColourBc5( u8* rgba, void const* block)
-+{
-+ // get the block bytes
-+ u8 const* bytes = reinterpret_cast< u8 const* >( block );
-+
-+ // unpack the endpoints
-+ u8 codes[16];
-+ int red_0 = bytes[0];
-+ int red_1 = bytes[1];
-+
-+ codes[0] = red_0;
-+ codes[1] = red_1;
-+ codes[6] = 0.0f;
-+ codes[7] = 1.0f;
-+ // generate the midpoints
-+ if(red_0 > red_1)
-+ {
-+ for( int i = 2; i < 8; ++i )
-+ {
-+ codes[i] = ((8-i)*red_0 + (i-1)*red_1)/7;
-+ }
-+ }
-+ else
-+ {
-+ for( int i = 2; i < 6; ++i )
-+ {
-+ codes[i] = ((6-i)*red_0 + (i-1)*red_1)/5;
-+ }
-+ }
-+
-+ int green_0 = bytes[8];
-+ int green_1 = bytes[9];
-+
-+ codes[0 + 8] = green_0;
-+ codes[1 + 8] = green_1;
-+ codes[6 + 8] = 0.0f;
-+ codes[7 + 8] = 1.0f;
-+ // generate the midpoints
-+ if(green_0 > green_1)
-+ {
-+ for( int i = 2; i < 8; ++i )
-+ {
-+ codes[i + 8] = ((8-i)*green_0 + (i-1)*green_1)/7;
-+ }
-+ }
-+ else
-+ {
-+ for( int i = 2; i < 6; ++i )
-+ {
-+ codes[i + 8] = ((6-i)*green_0 + (i-1)*green_1)/5;
-+ }
-+ }
-+
-+ u8 indices[32];
-+ for( int i = 0; i < 4; ++i )
-+ {
-+ u8 packed = bytes[2 + i];
-+ u8* red_ind = indices + 4*i;
-+
-+ red_ind[0] = packed & 0x3;
-+ red_ind[1] = ( packed >> 2 ) & 0x3;
-+ red_ind[2] = ( packed >> 4 ) & 0x3;
-+ red_ind[3] = ( packed >> 6 ) & 0x3;
-+
-+ packed = bytes[8 + i];
-+ u8* green_ind = indices + 4*i + 16;
-+ green_ind[0] = packed & 0x3;
-+ green_ind[1] = ( packed >> 2 ) & 0x3;
-+ green_ind[2] = ( packed >> 4 ) & 0x3;
-+ green_ind[3] = ( packed >> 6 ) & 0x3;
-+ }
-+
-+ // store out the colours
-+ for( int i = 0; i < 16; ++i )
-+ {
-+ rgba[4*i] = codes[indices[i]];
-+ rgba[4*i +1] = codes[indices[i + 16] + 8];
-+ rgba[4*i +2] = 0;
-+ rgba[4*i +3] = 255;
-+ }
-+}
-+// -- GODOT end --
-+
-+
- } // namespace squish
-diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h
-index fee2cd7c5..3cb9b7e3b 100644
---- a/thirdparty/squish/colourblock.h
-+++ b/thirdparty/squish/colourblock.h
-@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void*
- void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block );
-
- void DecompressColour( u8* rgba, void const* block, bool isDxt1 );
-+// -- GODOT start --
-+void DecompressColourBc5( u8* rgba, void const* block );
-+// -- GODOT end --
-
- } // namespace squish
-
-diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp
-index 1d22a64ad..fd11a147d 100644
---- a/thirdparty/squish/squish.cpp
-+++ b/thirdparty/squish/squish.cpp
-@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags )
- colourBlock = reinterpret_cast< u8 const* >( block ) + 8;
-
- // decompress colour
-- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ // -- GODOT start --
-+ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ if(( flags & ( kBc5 ) ) != 0)
-+ DecompressColourBc5( rgba, colourBlock);
-+ else
-+ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-+ // -- GODOT end --
-
- // decompress alpha separately if necessary
- if( ( flags & kDxt3 ) != 0 )
---
-2.13.6
-
diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
index 3de46382c0..3d87adaa77 100644
--- a/thirdparty/squish/colourblock.cpp
+++ b/thirdparty/squish/colourblock.cpp
@@ -24,6 +24,9 @@
-------------------------------------------------------------------------- */
#include "colourblock.h"
+// -- Godot start --
+#include "alpha.h"
+// -- Godot end --
namespace squish {
@@ -214,83 +217,17 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
// -- Godot start --
void DecompressColourBc5( u8* rgba, void const* block)
{
- // get the block bytes
- u8 const* bytes = reinterpret_cast< u8 const* >( block );
-
- // unpack the endpoints
- u8 codes[16];
- int red_0 = bytes[0];
- int red_1 = bytes[1];
-
- codes[0] = red_0;
- codes[1] = red_1;
- codes[6] = 0.0f;
- codes[7] = 1.0f;
- // generate the midpoints
- if(red_0 > red_1)
- {
- for( int i = 2; i < 8; ++i )
- {
- codes[i] = ((8-i)*red_0 + (i-1)*red_1)/7;
- }
- }
- else
- {
- for( int i = 2; i < 6; ++i )
- {
- codes[i] = ((6-i)*red_0 + (i-1)*red_1)/5;
- }
- }
-
- int green_0 = bytes[8];
- int green_1 = bytes[9];
-
- codes[0 + 8] = green_0;
- codes[1 + 8] = green_1;
- codes[6 + 8] = 0.0f;
- codes[7 + 8] = 1.0f;
- // generate the midpoints
- if(green_0 > green_1)
- {
- for( int i = 2; i < 8; ++i )
- {
- codes[i + 8] = ((8-i)*green_0 + (i-1)*green_1)/7;
- }
- }
- else
- {
- for( int i = 2; i < 6; ++i )
- {
- codes[i + 8] = ((6-i)*green_0 + (i-1)*green_1)/5;
- }
- }
-
- u8 indices[32];
- for( int i = 0; i < 4; ++i )
- {
- u8 packed = bytes[2 + i];
- u8* red_ind = indices + 4*i;
-
- red_ind[0] = packed & 0x3;
- red_ind[1] = ( packed >> 2 ) & 0x3;
- red_ind[2] = ( packed >> 4 ) & 0x3;
- red_ind[3] = ( packed >> 6 ) & 0x3;
-
- packed = bytes[8 + i];
- u8* green_ind = indices + 4*i + 16;
- green_ind[0] = packed & 0x3;
- green_ind[1] = ( packed >> 2 ) & 0x3;
- green_ind[2] = ( packed >> 4 ) & 0x3;
- green_ind[3] = ( packed >> 6 ) & 0x3;
+ void const* rblock = block;
+ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8;
+ DecompressAlphaDxt5(rgba,rblock);
+ for ( int i = 0; i < 16; ++i ) {
+ rgba[i*4] = rgba[i*4 + 3];
}
-
- // store out the colours
- for( int i = 0; i < 16; ++i )
- {
- rgba[4*i] = codes[indices[i]];
- rgba[4*i +1] = codes[indices[i + 16] + 8];
- rgba[4*i +2] = 0;
- rgba[4*i +3] = 255;
+ DecompressAlphaDxt5(rgba,gblock);
+ for ( int i = 0; i < 16; ++i ) {
+ rgba[i*4+1] = rgba[i*4 + 3];
+ rgba[i*4 + 2] = 0;
+ rgba[i*4 + 3] = 255;
}
}
// -- GODOT end --
diff --git a/thirdparty/squish/godot-changes.patch b/thirdparty/squish/godot-changes.patch
new file mode 100644
index 0000000000..ef7bafb4b4
--- /dev/null
+++ b/thirdparty/squish/godot-changes.patch
@@ -0,0 +1,102 @@
+diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp
+index af8b98036..3d87adaa7 100644
+--- a/thirdparty/squish/colourblock.cpp
++++ b/thirdparty/squish/colourblock.cpp
+@@ -24,6 +24,9 @@
+ -------------------------------------------------------------------------- */
+
+ #include "colourblock.h"
++// -- Godot start --
++#include "alpha.h"
++// -- Godot end --
+
+ namespace squish {
+
+@@ -211,4 +214,23 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
+ }
+ }
+
++// -- Godot start --
++void DecompressColourBc5( u8* rgba, void const* block)
++{
++ void const* rblock = block;
++ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8;
++ DecompressAlphaDxt5(rgba,rblock);
++ for ( int i = 0; i < 16; ++i ) {
++ rgba[i*4] = rgba[i*4 + 3];
++ }
++ DecompressAlphaDxt5(rgba,gblock);
++ for ( int i = 0; i < 16; ++i ) {
++ rgba[i*4+1] = rgba[i*4 + 3];
++ rgba[i*4 + 2] = 0;
++ rgba[i*4 + 3] = 255;
++ }
++}
++// -- GODOT end --
++
++
+ } // namespace squish
+diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h
+index fee2cd7c5..3cb9b7e3b 100644
+--- a/thirdparty/squish/colourblock.h
++++ b/thirdparty/squish/colourblock.h
+@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void*
+ void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block );
+
+ void DecompressColour( u8* rgba, void const* block, bool isDxt1 );
++// -- GODOT start --
++void DecompressColourBc5( u8* rgba, void const* block );
++// -- GODOT end --
+
+ } // namespace squish
+
+diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h
+index 92edefe96..05f8d7259 100644
+--- a/thirdparty/squish/config.h
++++ b/thirdparty/squish/config.h
+@@ -32,6 +32,26 @@
+ #endif
+
+ // Set to 1 or 2 when building squish to use SSE or SSE2 instructions.
++// -- GODOT start --
++#ifdef _MSC_VER
++ #if defined(_M_IX86_FP)
++ #if _M_IX86_FP >= 2
++ #define SQUISH_USE_SSE 2
++ #elif _M_IX86_FP >= 1
++ #define SQUISH_USE_SSE 1
++ #endif
++ #elif defined(_M_X64)
++ #define SQUISH_USE_SSE 2
++ #endif
++#else
++ #if defined(__SSE2__)
++ #define SQUISH_USE_SSE 2
++ #elif defined(__SSE__)
++ #define SQUISH_USE_SSE 1
++ #endif
++#endif
++// -- GODOT end --
++
+ #ifndef SQUISH_USE_SSE
+ #define SQUISH_USE_SSE 0
+ #endif
+diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp
+index 1d22a64ad..fd11a147d 100644
+--- a/thirdparty/squish/squish.cpp
++++ b/thirdparty/squish/squish.cpp
+@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags )
+ colourBlock = reinterpret_cast< u8 const* >( block ) + 8;
+
+ // decompress colour
+- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ // -- GODOT start --
++ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ if(( flags & ( kBc5 ) ) != 0)
++ DecompressColourBc5( rgba, colourBlock);
++ else
++ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
++ // -- GODOT end --
+
+ // decompress alpha separately if necessary
+ if( ( flags & kDxt3 ) != 0 )