summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--COPYRIGHT.txt4
-rw-r--r--core/make_binders.py12
-rw-r--r--core/math/delaunay.h4
-rw-r--r--core/math/geometry.cpp2
-rw-r--r--core/math/geometry.h10
-rw-r--r--core/math/math_funcs.h19
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/plane.h4
-rw-r--r--core/math/rect2.h39
-rw-r--r--core/math/vector2.h8
-rw-r--r--core/math/vector3.h23
-rw-r--r--core/method_bind.h6
-rw-r--r--core/object.cpp5
-rw-r--r--core/object.h1
-rw-r--r--core/reference.h6
-rw-r--r--core/type_info.h122
-rw-r--r--doc/classes/@GDScript.xml20
-rw-r--r--doc/classes/ArrayMesh.xml18
-rw-r--r--doc/classes/AudioServer.xml18
-rw-r--r--doc/classes/AudioStreamPlayer.xml9
-rw-r--r--doc/classes/Line2D.xml3
-rw-r--r--doc/classes/LineEdit.xml13
-rw-r--r--doc/classes/ScriptEditor.xml9
-rw-r--r--doc/classes/TextEdit.xml12
-rw-r--r--doc/classes/TranslationServer.xml6
-rw-r--r--drivers/gles2/shaders/scene.glsl6
-rw-r--r--editor/animation_track_editor.cpp51
-rw-r--r--editor/animation_track_editor.h3
-rw-r--r--editor/code_editor.cpp8
-rw-r--r--editor/code_editor.h2
-rw-r--r--editor/connections_dialog.cpp7
-rw-r--r--editor/connections_dialog.h2
-rw-r--r--editor/create_dialog.cpp2
-rw-r--r--editor/dependency_editor.cpp4
-rw-r--r--editor/editor_autoload_settings.cpp4
-rw-r--r--editor/editor_dir_dialog.cpp2
-rw-r--r--editor/editor_help.cpp19
-rw-r--r--editor/editor_inspector.cpp2
-rw-r--r--editor/editor_node.cpp51
-rw-r--r--editor/editor_node.h5
-rw-r--r--editor/editor_path.cpp160
-rw-r--r--editor/editor_path.h14
-rw-r--r--editor/editor_settings.cpp1
-rw-r--r--editor/editor_themes.cpp4
-rw-r--r--editor/export_template_manager.cpp2
-rw-r--r--editor/filesystem_dock.cpp2
-rw-r--r--editor/import/resource_importer_scene.cpp7
-rw-r--r--editor/import/resource_importer_wav.cpp4
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp2
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp68
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/cpu_particles_editor_plugin.cpp1
-rw-r--r--editor/plugins/curve_editor_plugin.cpp20
-rw-r--r--editor/plugins/mesh_instance_editor_plugin.cpp1
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp1
-rw-r--r--editor/plugins/particles_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/particles_editor_plugin.cpp1
-rw-r--r--editor/plugins/physical_bone_plugin.cpp2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp6
-rw-r--r--editor/plugins/script_editor_plugin.cpp37
-rw-r--r--editor/plugins/script_editor_plugin.h4
-rw-r--r--editor/plugins/script_text_editor.cpp10
-rw-r--r--editor/plugins/script_text_editor.h2
-rw-r--r--editor/plugins/shader_editor_plugin.cpp2
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp49
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp110
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h2
-rw-r--r--editor/plugins/text_editor.cpp11
-rw-r--r--editor/plugins/text_editor.h2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp7
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp83
-rw-r--r--editor/plugins/tile_map_editor_plugin.h4
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp29
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h1
-rw-r--r--editor/progress_dialog.cpp3
-rw-r--r--editor/project_manager.cpp26
-rw-r--r--editor/project_settings_editor.cpp10
-rw-r--r--editor/quick_open.cpp18
-rw-r--r--editor/rename_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp1
-rw-r--r--editor/scene_tree_editor.cpp25
-rw-r--r--editor/script_create_dialog.cpp62
-rw-r--r--editor/script_create_dialog.h8
-rw-r--r--editor/script_editor_debugger.cpp25
-rw-r--r--editor/script_editor_debugger.h2
-rw-r--r--editor/settings_config_dialog.cpp2
-rw-r--r--main/input_default.cpp13
-rw-r--r--main/input_default.h1
-rw-r--r--modules/bullet/bullet_physics_server.cpp8
-rw-r--r--modules/bullet/bullet_physics_server.h4
-rw-r--r--modules/bullet/collision_object_bullet.cpp6
-rw-r--r--modules/bullet/collision_object_bullet.h2
-rw-r--r--modules/csg/csg.cpp10
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.cpp9
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.h1
-rw-r--r--modules/gdnative/include/arvr/godot_arvr.h1
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp34
-rw-r--r--modules/gdscript/gdscript_functions.cpp23
-rw-r--r--modules/gdscript/gdscript_functions.h2
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp6
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h1
-rw-r--r--modules/mono/csharp_script.cpp17
-rw-r--r--modules/mono/csharp_script.h15
-rw-r--r--modules/mono/editor/bindings_generator.cpp332
-rw-r--r--modules/mono/editor/bindings_generator.h68
-rw-r--r--modules/mono/editor/csharp_project.cpp2
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp9
-rw-r--r--modules/mono/glue/Managed/Files/Color.cs16
-rw-r--r--modules/mono/glue/Managed/Files/GD.cs5
-rw-r--r--modules/mono/glue/Managed/Files/Mathf.cs14
-rw-r--r--modules/mono/glue/Managed/Files/MathfEx.cs4
-rw-r--r--modules/mono/glue/Managed/Files/Plane.cs2
-rw-r--r--modules/mono/glue/Managed/Files/Quat.cs2
-rw-r--r--modules/mono/glue/Managed/Files/Vector2.cs26
-rw-r--r--modules/mono/glue/Managed/Files/Vector3.cs23
-rw-r--r--modules/mono/glue/gd_glue.cpp2
-rw-r--r--modules/mono/glue/gd_glue.h2
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp24
-rw-r--r--modules/mono/utils/string_utils.cpp49
-rw-r--r--modules/mono/utils/string_utils.h13
-rw-r--r--modules/theora/video_stream_theora.cpp8
-rw-r--r--modules/visual_script/visual_script_editor.cpp10
-rw-r--r--modules/visual_script/visual_script_editor.h2
-rw-r--r--modules/webm/video_stream_webm.cpp31
-rw-r--r--platform/android/export/export.cpp4
-rw-r--r--platform/osx/os_osx.mm13
-rw-r--r--platform/windows/os_windows.cpp13
-rw-r--r--platform/x11/detect.py23
-rw-r--r--platform/x11/os_x11.cpp27
-rw-r--r--scene/2d/audio_stream_player_2d.cpp35
-rw-r--r--scene/2d/audio_stream_player_2d.h5
-rw-r--r--scene/2d/collision_object_2d.cpp4
-rw-r--r--scene/2d/line_2d.cpp10
-rw-r--r--scene/2d/line_2d.h2
-rw-r--r--scene/2d/navigation_2d.cpp12
-rw-r--r--scene/2d/tile_map.cpp5
-rw-r--r--scene/3d/arvr_nodes.cpp26
-rw-r--r--scene/3d/audio_stream_player_3d.cpp35
-rw-r--r--scene/3d/audio_stream_player_3d.h5
-rw-r--r--scene/3d/collision_object.cpp4
-rw-r--r--scene/3d/path.cpp8
-rw-r--r--scene/3d/soft_body.cpp2
-rw-r--r--scene/3d/spatial.cpp6
-rw-r--r--scene/3d/voxel_light_baker.cpp6
-rw-r--r--scene/audio/audio_stream_player.cpp138
-rw-r--r--scene/audio/audio_stream_player.h8
-rw-r--r--scene/gui/base_button.cpp5
-rw-r--r--scene/gui/color_picker.cpp74
-rw-r--r--scene/gui/color_picker.h11
-rw-r--r--scene/gui/graph_edit.cpp2
-rw-r--r--scene/gui/item_list.cpp1
-rw-r--r--scene/gui/line_edit.cpp32
-rw-r--r--scene/gui/menu_button.cpp14
-rw-r--r--scene/gui/menu_button.h1
-rw-r--r--scene/gui/option_button.cpp11
-rw-r--r--scene/gui/popup.cpp2
-rw-r--r--scene/gui/popup_menu.cpp69
-rw-r--r--scene/gui/rich_text_label.cpp3
-rw-r--r--scene/gui/tab_container.cpp5
-rw-r--r--scene/gui/text_edit.cpp113
-rw-r--r--scene/gui/text_edit.h6
-rw-r--r--scene/gui/texture_button.cpp2
-rw-r--r--scene/gui/texture_rect.cpp2
-rw-r--r--scene/main/scene_tree.cpp5
-rw-r--r--scene/main/viewport.cpp4
-rw-r--r--scene/register_scene_types.cpp4
-rw-r--r--scene/resources/animation.cpp38
-rw-r--r--scene/resources/default_theme/default_theme.cpp3
-rw-r--r--scene/resources/packed_scene.cpp2
-rw-r--r--scene/resources/tile_set.cpp28
-rw-r--r--servers/arvr/arvr_interface.h1
-rw-r--r--servers/audio/effects/audio_effect_spectrum_analyzer.cpp2
-rw-r--r--servers/audio_server.cpp42
-rw-r--r--servers/audio_server.h14
-rw-r--r--servers/physics/collision_object_sw.cpp3
-rw-r--r--servers/physics/collision_object_sw.h2
-rw-r--r--servers/physics/collision_solver_sat.cpp6
-rw-r--r--servers/physics/joints/cone_twist_joint_sw.cpp6
-rw-r--r--servers/physics/joints/generic_6dof_joint_sw.cpp2
-rw-r--r--servers/physics/joints/hinge_joint_sw.cpp6
-rw-r--r--servers/physics/physics_server_sw.cpp8
-rw-r--r--servers/physics/physics_server_sw.h4
-rw-r--r--servers/physics_2d/collision_object_2d_sw.cpp4
-rw-r--r--servers/physics_2d/collision_object_2d_sw.h2
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.cpp4
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp8
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h4
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h4
-rw-r--r--servers/physics_2d_server.h4
-rw-r--r--servers/physics_server.h4
-rw-r--r--servers/visual/visual_server_canvas.h2
-rw-r--r--servers/visual/visual_server_scene.cpp4
-rw-r--r--thirdparty/README.md13
-rw-r--r--thirdparty/libpng/LICENSE8
-rw-r--r--thirdparty/libpng/arm/palette_neon_intrinsics.c32
-rw-r--r--thirdparty/libpng/png.c11
-rw-r--r--thirdparty/libpng/png.h129
-rw-r--r--thirdparty/libpng/pngconf.h6
-rw-r--r--thirdparty/libpng/pngget.c162
-rw-r--r--thirdparty/libpng/pnginfo.h13
-rw-r--r--thirdparty/libpng/pnglibconf.h4
-rw-r--r--thirdparty/libpng/pngpread.c199
-rw-r--r--thirdparty/libpng/pngpriv.h65
-rw-r--r--thirdparty/libpng/pngread.c88
-rw-r--r--thirdparty/libpng/pngrtran.c50
-rw-r--r--thirdparty/libpng/pngrutil.c290
-rw-r--r--thirdparty/libpng/pngset.c146
-rw-r--r--thirdparty/libpng/pngstruct.h33
-rw-r--r--thirdparty/libpng/pngwrite.c52
-rw-r--r--thirdparty/libpng/pngwutil.c139
-rw-r--r--thirdparty/libsimplewebm/OpusVorbisDecoder.cpp2
-rw-r--r--thirdparty/libsimplewebm/OpusVorbisDecoder.hpp4
-rw-r--r--thirdparty/libsimplewebm/VPXDecoder.cpp14
-rw-r--r--thirdparty/libsimplewebm/VPXDecoder.hpp6
-rw-r--r--thirdparty/misc/yuv2rgb.h121
218 files changed, 3564 insertions, 1174 deletions
diff --git a/.gitignore b/.gitignore
index 2697507adb..cd6785a8ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,12 +40,14 @@ gmon.out
*.swo
*.swp
-# QT project files
+# Qt project files
*.config
*.creator
*.creator.*
*.files
*.includes
+*.cflags
+*.cxxflags
# Eclipse CDT files
.cproject
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 3e2dc1538d..5431e2b403 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -185,8 +185,8 @@ License: BSD-3-clause
Files: ./thirdparty/libpng/
Comment: libpng
-Copyright: 1995-2018, The PNG Reference Library Authors.
- 2018, Cosmin Truta.
+Copyright: 1995-2019, The PNG Reference Library Authors.
+ 2018-2019, Cosmin Truta.
2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
1996-1997, Andreas Dilger.
1995-1996, Guy Eric Schalnat, Group 42, Inc.
diff --git a/core/make_binders.py b/core/make_binders.py
index 4c61b90d99..5c1c66cab6 100644
--- a/core/make_binders.py
+++ b/core/make_binders.py
@@ -9,6 +9,12 @@ public:
$ifret R$ $ifnoret void$ (T::*method)($arg, P@$) $ifconst const$;
#ifdef DEBUG_METHODS_ENABLED
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
+ $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
+ $
+ return GodotTypeInfo::METADATA_NONE;
+ }
Variant::Type _get_argument_type(int p_argument) const {
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
$arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE;
@@ -94,6 +100,12 @@ public:
#ifdef DEBUG_METHODS_ENABLED
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
+ $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
+ $
+ return GodotTypeInfo::METADATA_NONE;
+ }
Variant::Type _get_argument_type(int p_argument) const {
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
diff --git a/core/math/delaunay.h b/core/math/delaunay.h
index bd0cf97937..ed52c506db 100644
--- a/core/math/delaunay.h
+++ b/core/math/delaunay.h
@@ -80,11 +80,11 @@ public:
}
static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) {
- if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON) {
+ if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]))) {
return true;
}
- if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON) {
+ if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]))) {
return true;
}
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index a84b5a16c7..0ab8707d3a 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -836,7 +836,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
Vector3 rel = edge1_A - edge0_A;
real_t den = clip.normal.dot(rel);
- if (Math::abs(den) < CMP_EPSILON)
+ if (Math::is_zero_approx(den))
continue; // point too short
real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den;
diff --git a/core/math/geometry.h b/core/math/geometry.h
index 7347cb742a..f3a671aa9a 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -181,8 +181,8 @@ public:
}
}
// finally do the division to get sc and tc
- sc = (Math::abs(sN) < CMP_EPSILON ? 0.0 : sN / sD);
- tc = (Math::abs(tN) < CMP_EPSILON ? 0.0 : tN / tD);
+ sc = (Math::is_zero_approx(sN) ? 0.0 : sN / sD);
+ tc = (Math::is_zero_approx(tN) ? 0.0 : tN / tD);
// get the difference of the two closest points
Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
@@ -195,7 +195,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = p_dir.cross(e2);
real_t a = e1.dot(h);
- if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test
+ if (Math::is_zero_approx(a)) // parallel test
return false;
real_t f = 1.0 / a;
@@ -233,7 +233,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = rel.cross(e2);
real_t a = e1.dot(h);
- if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test
+ if (Math::is_zero_approx(a)) // parallel test
return false;
real_t f = 1.0 / a;
@@ -535,7 +535,7 @@ public:
// see http://paulbourke.net/geometry/pointlineplane/
const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y;
- if (Math::abs(denom) < CMP_EPSILON) { // parallel?
+ if (Math::is_zero_approx(denom)) { // parallel?
return false;
}
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 0d209402dd..a75f2fb4ab 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -272,13 +272,20 @@ public:
return diff < epsilon;
}
- static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
- // TODO: Comparing floats for approximate-equality is non-trivial.
- // Using epsilon should cover the typical cases in Godot (where a == b is used to compare two reals), such as matrix and vector comparison operators.
- // A proper implementation in terms of ULPs should eventually replace the contents of this function.
- // See https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ for details.
+ static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
+ real_t tolerance = CMP_EPSILON * abs(a);
+ if (tolerance < CMP_EPSILON) {
+ tolerance = CMP_EPSILON;
+ }
+ return abs(a - b) < tolerance;
+ }
+
+ static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
+ return abs(a - b) < tolerance;
+ }
- return abs(a - b) < epsilon;
+ static _ALWAYS_INLINE_ bool is_zero_approx(real_t s) {
+ return abs(s) < CMP_EPSILON;
}
static _ALWAYS_INLINE_ float absf(float g) {
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index cd3cbce300..b01853c4ac 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -110,7 +110,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::is_zero_approx(den)) {
return false;
}
@@ -135,7 +135,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::is_zero_approx(den)) {
return false;
}
diff --git a/core/math/plane.h b/core/math/plane.h
index 1c6e4b816b..ec817edd2c 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -125,12 +125,12 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_
bool Plane::operator==(const Plane &p_plane) const {
- return normal == p_plane.normal && d == p_plane.d;
+ return normal == p_plane.normal && Math::is_equal_approx(d, p_plane.d);
}
bool Plane::operator!=(const Plane &p_plane) const {
- return normal != p_plane.normal || d != p_plane.d;
+ return normal != p_plane.normal || !Math::is_equal_approx(d, p_plane.d);
}
#endif // PLANE_H
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 901d372132..3b66617c83 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -103,7 +103,7 @@ struct Rect2 {
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
}
- inline bool has_no_area() const {
+ _FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
@@ -154,8 +154,6 @@ struct Rect2 {
return true;
}
- inline bool no_area() const { return (size.width <= 0 || size.height <= 0); }
-
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -189,7 +187,7 @@ struct Rect2 {
return g;
}
- inline Rect2 expand(const Vector2 &p_vector) const {
+ _FORCE_INLINE_ Rect2 expand(const Vector2 &p_vector) const {
Rect2 r = *this;
r.expand_to(p_vector);
@@ -215,7 +213,7 @@ struct Rect2 {
size = end - begin;
}
- inline Rect2 abs() const {
+ _FORCE_INLINE_ Rect2 abs() const {
return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
}
@@ -265,7 +263,7 @@ struct Rect2i {
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
}
- inline bool has_no_area() const {
+ _FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
@@ -316,8 +314,6 @@ struct Rect2i {
return true;
}
- bool no_area() { return (size.width <= 0 || size.height <= 0); }
-
bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -331,6 +327,33 @@ struct Rect2i {
return g;
}
+ inline Rect2i grow_margin(Margin p_margin, int p_amount) const {
+ Rect2i g = *this;
+ g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
+ (MARGIN_TOP == p_margin) ? p_amount : 0,
+ (MARGIN_RIGHT == p_margin) ? p_amount : 0,
+ (MARGIN_BOTTOM == p_margin) ? p_amount : 0);
+ return g;
+ }
+
+ inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const {
+
+ Rect2i g = *this;
+ g.position.x -= p_left;
+ g.position.y -= p_top;
+ g.size.width += p_left + p_right;
+ g.size.height += p_top + p_bottom;
+
+ return g;
+ }
+
+ _FORCE_INLINE_ Rect2i expand(const Vector2i &p_vector) const {
+
+ Rect2i r = *this;
+ r.expand_to(p_vector);
+ return r;
+ }
+
inline void expand_to(const Point2i &p_vector) {
Point2i begin = position;
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 9a214ef9b5..a0c6024c9f 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -106,8 +106,8 @@ struct Vector2 {
bool operator==(const Vector2 &p_vec2) const;
bool operator!=(const Vector2 &p_vec2) const;
- bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
- bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); }
+ bool operator<(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y < p_vec2.y) : (x < p_vec2.x); }
+ bool operator<=(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y <= p_vec2.y) : (x < p_vec2.x); }
real_t angle() const;
@@ -213,11 +213,11 @@ _FORCE_INLINE_ Vector2 Vector2::operator-() const {
_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const {
- return x == p_vec2.x && y == p_vec2.y;
+ return Math::is_equal_approx(x, p_vec2.x) && Math::is_equal_approx(y, p_vec2.y);
}
_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
- return x != p_vec2.x || y != p_vec2.y;
+ return !Math::is_equal_approx(x, p_vec2.x) || !Math::is_equal_approx(y, p_vec2.y);
}
Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const {
diff --git a/core/math/vector3.h b/core/math/vector3.h
index e9074c5bd4..21fc09653f 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -341,17 +341,17 @@ Vector3 Vector3::operator-() const {
bool Vector3::operator==(const Vector3 &p_v) const {
- return (x == p_v.x && y == p_v.y && z == p_v.z);
+ return (Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z));
}
bool Vector3::operator!=(const Vector3 &p_v) const {
- return (x != p_v.x || y != p_v.y || z != p_v.z);
+ return (!Math::is_equal_approx(x, p_v.x) || !Math::is_equal_approx(y, p_v.y) || !Math::is_equal_approx(z, p_v.z));
}
bool Vector3::operator<(const Vector3 &p_v) const {
- if (x == p_v.x) {
- if (y == p_v.y)
+ if (Math::is_equal_approx(x, p_v.x)) {
+ if (Math::is_equal_approx(y, p_v.y))
return z < p_v.z;
else
return y < p_v.y;
@@ -362,8 +362,8 @@ bool Vector3::operator<(const Vector3 &p_v) const {
bool Vector3::operator<=(const Vector3 &p_v) const {
- if (x == p_v.x) {
- if (y == p_v.y)
+ if (Math::is_equal_approx(x, p_v.x)) {
+ if (Math::is_equal_approx(y, p_v.y))
return z <= p_v.z;
else
return y < p_v.y;
@@ -402,13 +402,14 @@ real_t Vector3::length_squared() const {
void Vector3::normalize() {
- real_t l = length();
- if (l == 0) {
+ real_t lengthsq = length_squared();
+ if (lengthsq == 0) {
x = y = z = 0;
} else {
- x /= l;
- y /= l;
- z /= l;
+ real_t length = Math::sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ z /= length;
}
}
diff --git a/core/method_bind.h b/core/method_bind.h
index 5ea8adb7e0..1b0c3b27c0 100644
--- a/core/method_bind.h
+++ b/core/method_bind.h
@@ -273,6 +273,8 @@ public:
void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise
Vector<StringName> get_argument_names() const;
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const = 0;
+
#endif
void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
@@ -329,6 +331,10 @@ public:
return _gen_argument_type_info(p_arg).type;
}
+ virtual GodotTypeInfo::Metadata get_argument_meta(int) const {
+ return GodotTypeInfo::METADATA_NONE;
+ }
+
#else
virtual Variant::Type _gen_argument_type(int p_arg) const {
diff --git a/core/object.cpp b/core/object.cpp
index 039f556c87..f860423a27 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -1059,6 +1059,10 @@ Variant Object::get_meta(const String &p_name) const {
return metadata[p_name];
}
+void Object::remove_meta(const String &p_name) {
+ metadata.erase(p_name);
+}
+
Array Object::_get_property_list_bind() const {
List<PropertyInfo> lpi;
@@ -1691,6 +1695,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_script"), &Object::get_script);
ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta);
+ ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta);
ClassDB::bind_method(D_METHOD("get_meta", "name"), &Object::get_meta);
ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta);
ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind);
diff --git a/core/object.h b/core/object.h
index 3730af1ad4..94abaacdcc 100644
--- a/core/object.h
+++ b/core/object.h
@@ -673,6 +673,7 @@ public:
bool has_meta(const String &p_name) const;
void set_meta(const String &p_name, const Variant &p_value);
+ void remove_meta(const String &p_name);
Variant get_meta(const String &p_name) const;
void get_meta_list(List<String> *p_list) const;
diff --git a/core/reference.h b/core/reference.h
index 9105dbbd58..8a19f846c7 100644
--- a/core/reference.h
+++ b/core/reference.h
@@ -375,7 +375,8 @@ struct PtrToArg<const RefPtr &> {
template <class T>
struct GetTypeInfo<Ref<T> > {
- enum { VARIANT_TYPE = Variant::OBJECT };
+ static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
@@ -384,7 +385,8 @@ struct GetTypeInfo<Ref<T> > {
template <class T>
struct GetTypeInfo<const Ref<T> &> {
- enum { VARIANT_TYPE = Variant::OBJECT };
+ static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
diff --git a/core/type_info.h b/core/type_info.h
index c38688fea1..d85a63ee42 100644
--- a/core/type_info.h
+++ b/core/type_info.h
@@ -67,43 +67,80 @@ struct TypeInherits {
!TypesAreSame<B volatile const, void volatile const>::value;
};
+namespace GodotTypeInfo {
+enum Metadata {
+ METADATA_NONE,
+ METADATA_INT_IS_INT8,
+ METADATA_INT_IS_INT16,
+ METADATA_INT_IS_INT32,
+ METADATA_INT_IS_INT64,
+ METADATA_INT_IS_UINT8,
+ METADATA_INT_IS_UINT16,
+ METADATA_INT_IS_UINT32,
+ METADATA_INT_IS_UINT64,
+ METADATA_REAL_IS_FLOAT,
+ METADATA_REAL_IS_DOUBLE
+};
+}
+
template <class T, typename = void>
struct GetTypeInfo {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
ERR_PRINT("GetTypeInfo fallback. Bug!");
return PropertyInfo(); // Not "Nil", this is an error
}
};
-#define MAKE_TYPE_INFO(m_type, m_var_type) \
- template <> \
- struct GetTypeInfo<m_type> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
- }; \
- template <> \
- struct GetTypeInfo<const m_type &> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
+#define MAKE_TYPE_INFO(m_type, m_var_type) \
+ template <> \
+ struct GetTypeInfo<m_type> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_type &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ };
+
+#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \
+ template <> \
+ struct GetTypeInfo<m_type> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = m_metadata; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_type &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = m_metadata; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
};
MAKE_TYPE_INFO(bool, Variant::BOOL)
-MAKE_TYPE_INFO(uint8_t, Variant::INT)
-MAKE_TYPE_INFO(int8_t, Variant::INT)
-MAKE_TYPE_INFO(uint16_t, Variant::INT)
-MAKE_TYPE_INFO(int16_t, Variant::INT)
-MAKE_TYPE_INFO(uint32_t, Variant::INT)
-MAKE_TYPE_INFO(int32_t, Variant::INT)
-MAKE_TYPE_INFO(int64_t, Variant::INT)
-MAKE_TYPE_INFO(uint64_t, Variant::INT)
+MAKE_TYPE_INFO_WITH_META(uint8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT8)
+MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT8)
+MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT16)
+MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT16)
+MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT32)
+MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
+MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
+MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
MAKE_TYPE_INFO(wchar_t, Variant::INT)
-MAKE_TYPE_INFO(float, Variant::REAL)
-MAKE_TYPE_INFO(double, Variant::REAL)
+MAKE_TYPE_INFO_WITH_META(float, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
+MAKE_TYPE_INFO_WITH_META(double, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
MAKE_TYPE_INFO(String, Variant::STRING)
MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
@@ -138,6 +175,7 @@ MAKE_TYPE_INFO(BSP_Tree, Variant::DICTIONARY)
template <>
struct GetTypeInfo<RefPtr> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
}
@@ -145,6 +183,7 @@ struct GetTypeInfo<RefPtr> {
template <>
struct GetTypeInfo<const RefPtr &> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
}
@@ -154,6 +193,7 @@ struct GetTypeInfo<const RefPtr &> {
template <>
struct GetTypeInfo<Variant> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
@@ -162,25 +202,28 @@ struct GetTypeInfo<Variant> {
template <>
struct GetTypeInfo<const Variant &> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
};
-#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \
- template <> \
- struct GetTypeInfo<m_template<m_type> > { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
- }; \
- template <> \
- struct GetTypeInfo<const m_template<m_type> &> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
+#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \
+ template <> \
+ struct GetTypeInfo<m_template<m_type> > { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_template<m_type> &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
};
MAKE_TEMPLATE_TYPE_INFO(Vector, uint8_t, Variant::POOL_BYTE_ARRAY)
@@ -202,6 +245,7 @@ MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY)
template <typename T>
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(StringName(T::get_class_static()));
}
@@ -210,6 +254,7 @@ struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type>
template <typename T>
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(StringName(T::get_class_static()));
}
@@ -219,6 +264,7 @@ struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>:
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \
} \
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index 29bf9b62ce..22834a4c81 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -498,6 +498,17 @@
[/codeblock]
</description>
</method>
+ <method name="is_equal_approx">
+ <return type="bool">
+ </return>
+ <argument index="0" name="a" type="float">
+ </argument>
+ <argument index="1" name="b" type="float">
+ </argument>
+ <description>
+ Returns True/False whether [code]a[/code] and [code]b[/code] are approximately equal to each other.
+ </description>
+ </method>
<method name="is_inf">
<return type="bool">
</return>
@@ -525,6 +536,15 @@
Returns whether [code]s[/code] is a NaN (Not-A-Number) value.
</description>
</method>
+ <method name="is_zero_approx">
+ <return type="bool">
+ </return>
+ <argument index="0" name="s" type="float">
+ </argument>
+ <description>
+ Returns True/False whether [code]s[/code] is zero or almost zero.
+ </description>
+ </method>
<method name="len">
<return type="int">
</return>
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index 00bd72d4a5..db0fc77b25 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -205,31 +205,31 @@
Amount of weights/bone indices per vertex (always 4).
</constant>
<constant name="ARRAY_VERTEX" value="0" enum="ArrayType">
- Vertex array (array of [Vector3] vertices).
+ [PoolVector3Array], [PoolVector2Array], or [Array] of vertex positions.
</constant>
<constant name="ARRAY_NORMAL" value="1" enum="ArrayType">
- Normal array (array of [Vector3] normals).
+ [PoolVector3Array] of vertex normals.
</constant>
<constant name="ARRAY_TANGENT" value="2" enum="ArrayType">
- Tangent array, array of groups of 4 floats. first 3 floats determine the tangent, and the last the binormal direction as -1 or 1.
+ [PoolRealArray] of vertex tangents. Each element in groups of 4 floats, first 3 floats determine the tangent, and the last the binormal direction as -1 or 1.
</constant>
<constant name="ARRAY_COLOR" value="3" enum="ArrayType">
- Vertex array (array of [Color] colors).
+ [PoolColorArray] of vertex colors.
</constant>
<constant name="ARRAY_TEX_UV" value="4" enum="ArrayType">
- UV array (array of [Vector3] UVs or float array of groups of 2 floats (u,v)).
+ [PoolVector2Array] for UV coordinates.
</constant>
<constant name="ARRAY_TEX_UV2" value="5" enum="ArrayType">
- Second UV array (array of [Vector3] UVs or float array of groups of 2 floats (u,v)).
+ [PoolVector2Array] for second UV coordinates.
</constant>
<constant name="ARRAY_BONES" value="6" enum="ArrayType">
- Array of bone indices, as a float array. Each element in groups of 4 floats.
+ [PoolRealArray] or [PoolIntArray] of bone indices. Each element in groups of 4 floats.
</constant>
<constant name="ARRAY_WEIGHTS" value="7" enum="ArrayType">
- Array of bone weights, as a float array. Each element in groups of 4 floats.
+ [PoolRealArray] of bone weights. Each element in groups of 4 floats.
</constant>
<constant name="ARRAY_INDEX" value="8" enum="ArrayType">
- [Array] of integers used as indices referencing vertices, colors, normals, tangents, and textures. All of those arrays must have the same number of elements as the vertex array. No index can be beyond the vertex array size. When this index array is present, it puts the function into "index mode," where the index selects the *i*'th vertex, normal, tangent, color, UV, etc. This means if you want to have different normals or colors along an edge, you have to duplicate the vertices.
+ [PoolIntArray] of integers used as indices referencing vertices, colors, normals, tangents, and textures. All of those arrays must have the same number of elements as the vertex array. No index can be beyond the vertex array size. When this index array is present, it puts the function into "index mode," where the index selects the *i*'th vertex, normal, tangent, color, UV, etc. This means if you want to have different normals or colors along an edge, you have to duplicate the vertices.
For triangles, the index array is interpreted as triples, referring to the vertices of each triangle. For lines, the index array is in pairs indicating the start and end of each line.
</constant>
<constant name="ARRAY_MAX" value="9" enum="ArrayType">
diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml
index 83fbd28152..6dc1600cf2 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -184,6 +184,12 @@
Returns the sample rate at the output of the audioserver.
</description>
</method>
+ <method name="get_output_latency" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_speaker_mode" qualifiers="const">
<return type="int" enum="AudioServer.SpeakerMode">
</return>
@@ -191,6 +197,18 @@
Returns the speaker configuration.
</description>
</method>
+ <method name="get_time_since_last_mix" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_time_to_next_mix" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="is_bus_bypassing_effects" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index c6ec45f15e..07d7c875db 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -10,6 +10,15 @@
<link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<methods>
+ <method name="get_mix_time" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the actual amount of time this stream player was mixing since play() was pressed.
+ To know the exact position this song is mixing right now, add the value to [method AudioServer.get_time_since_last_mix].
+ Also consider substracting [method AudioServer.get_output_latency] to that result.
+ </description>
+ </method>
<method name="get_playback_position">
<return type="float">
</return>
diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml
index 623b23807f..c55760767a 100644
--- a/doc/classes/Line2D.xml
+++ b/doc/classes/Line2D.xml
@@ -14,8 +14,11 @@
</return>
<argument index="0" name="position" type="Vector2">
</argument>
+ <argument index="1" name="at_position" type="int" default="-1">
+ </argument>
<description>
Add a point at the [code]position[/code]. Appends the point at the end of the line.
+ If [code]at_position[/code] is given, the point is inserted before the point number [code]at_position[/code], moving that point (and every point after) after the inserted point. If [code]at_position[/code] is not given, or is an illegal value ([code]at_position &lt; 0[/code] or [code]at_position &gt;= [method get_point_count][/code]), the point will be appended at the end of the point list.
</description>
</method>
<method name="clear_points">
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index 6ea097ec2f..bb180b591d 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -1,10 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="LineEdit" inherits="Control" category="Core" version="3.2">
<brief_description>
- Control that provides single line string editing.
+ Control that provides single-line string editing.
</brief_description>
<description>
- LineEdit provides a single line string editor, used for text fields.
+ LineEdit provides a single-line string editor, used for text fields. It features many built-in shortcuts which will always be available:
+ - Ctrl + C: Copy
+ - Ctrl + X: Cut
+ - Ctrl + V or Ctrl + Y: Paste/"yank"
+ - Ctrl + Z: Undo
+ - Ctrl + Shift + Z: Redo
+ - Ctrl + U: Delete text from the cursor position to the beginning of the line
+ - Ctrl + K: Delete text from the cursor position to the end of the line
+ - Ctrl + A: Select all text
+ - Up/Down arrow: Move the cursor to the beginning/end of the line
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml
index 666ab15802..28e1f75ac1 100644
--- a/doc/classes/ScriptEditor.xml
+++ b/doc/classes/ScriptEditor.xml
@@ -55,6 +55,15 @@
Returns an array with all [Script] objects which are currently open in editor.
</description>
</method>
+ <method name="goto_line">
+ <return type="void">
+ </return>
+ <argument index="0" name="line_number" type="int">
+ </argument>
+ <description>
+ Goes to the specified line in the current script.
+ </description>
+ </method>
<method name="open_script_create_dialog">
<return type="void">
</return>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 1817055bab..fa78fbe305 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -41,6 +41,7 @@
<argument index="0" name="line" type="int">
</argument>
<description>
+ Returns if the given line is foldable, that is, it has indented lines right below it.
</description>
</method>
<method name="clear_colors">
@@ -120,6 +121,7 @@
<return type="void">
</return>
<description>
+ Folds all lines that are possible to be folded (see [method can_fold]).
</description>
</method>
<method name="fold_line">
@@ -128,6 +130,7 @@
<argument index="0" name="line" type="int">
</argument>
<description>
+ Folds the given line, if possible (see [method can_fold]).
</description>
</method>
<method name="get_breakpoints" qualifiers="const">
@@ -165,6 +168,7 @@
<return type="PopupMenu">
</return>
<description>
+ Returns the [PopupMenu] of this [TextEdit]. By default, this menu is displayed when right-clicking on the [TextEdit].
</description>
</method>
<method name="get_selection_from_column" qualifiers="const">
@@ -231,6 +235,7 @@
<argument index="0" name="line" type="int">
</argument>
<description>
+ Returns if the given line is folded.
</description>
</method>
<method name="is_line_hidden" qualifiers="const">
@@ -346,6 +351,7 @@
<argument index="0" name="line" type="int">
</argument>
<description>
+ Unfolds the given line, if folded.
</description>
</method>
<method name="unhide_all_lines">
@@ -376,6 +382,12 @@
<member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled">
If [code]true[/code], a right click displays the context menu.
</member>
+ <member name="draw_tabs" type="bool" setter="set_draw_tabs" getter="is_drawing_tabs">
+ If [code]true[/code], the "tab" character will have a visible representation.
+ </member>
+ <member name="fold_gutter" type="bool" setter="set_fold_gutter_enabled" getter="is_fold_gutter_enabled">
+ If [code]true[/code], the fold gutter is visible. This enables folding groups of indented lines.
+ </member>
<member name="hiding_enabled" type="int" setter="set_hiding_enabled" getter="is_hiding_enabled">
</member>
<member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled">
diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml
index a3acc2c659..05774635b8 100644
--- a/doc/classes/TranslationServer.xml
+++ b/doc/classes/TranslationServer.xml
@@ -27,6 +27,12 @@
Clears the server from all translations.
</description>
</method>
+ <method name="get_loaded_locales" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_locale" qualifiers="const">
<return type="String">
</return>
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 5d21c679ba..1c35b455c4 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -1545,6 +1545,11 @@ FRAGMENT_SHADER_CODE
#ifdef BASE_PASS
//none
+
+#ifdef AMBIENT_LIGHT_DISABLED
+ ambient_light = vec3(0.0, 0.0, 0.0);
+#else
+
#ifdef USE_RADIANCE_MAP
vec3 ref_vec = reflect(-eye_position, N);
@@ -1567,6 +1572,7 @@ FRAGMENT_SHADER_CODE
#endif
+#endif // AMBIENT_LIGHT_DISABLED
ambient_light *= ambient_energy;
#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index a34ced7328..4dff7d5b69 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -544,7 +544,7 @@ public:
if (use_fps && animation->get_step() > 0) {
float max_frame = animation->get_length() / animation->get_step();
- p_list->push_back(PropertyInfo(Variant::REAL, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1"));
} else {
p_list->push_back(PropertyInfo(Variant::REAL, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
}
@@ -1022,8 +1022,14 @@ void AnimationTimelineEdit::update_values() {
editing = true;
if (use_fps && animation->get_step() > 0) {
length->set_value(animation->get_length() / animation->get_step());
+ length->set_step(1);
+ length->set_tooltip(TTR("Animation length (frames)"));
+ time_icon->set_tooltip(TTR("Animation length (frames)"));
} else {
length->set_value(animation->get_length());
+ length->set_step(0.01);
+ length->set_tooltip(TTR("Animation length (seconds)"));
+ time_icon->set_tooltip(TTR("Animation length (seconds)"));
}
loop->set_pressed(animation->has_loop());
editing = false;
@@ -1168,7 +1174,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
len_hb->add_child(expander);
time_icon = memnew(TextureRect);
time_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
- time_icon->set_tooltip(TTR("Animation Length Time (seconds)"));
+ time_icon->set_tooltip(TTR("Animation length (seconds)"));
len_hb->add_child(time_icon);
length = memnew(EditorSpinSlider);
length->set_min(0.001);
@@ -1177,7 +1183,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
length->set_allow_greater(true);
length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0));
length->set_hide_slider(true);
- length->set_tooltip(TTR("Animation Length Time (seconds)"));
+ length->set_tooltip(TTR("Animation length (seconds)"));
length->connect("value_changed", this, "_anim_length_changed");
len_hb->add_child(length);
loop = memnew(ToolButton);
@@ -2541,6 +2547,15 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
step->set_read_only(false);
snap->set_disabled(false);
snap_mode->set_disabled(false);
+
+ imported_anim_warning->hide();
+ for (int i = 0; i < animation->get_track_count(); i++) {
+ if (animation->track_is_imported(i)) {
+ imported_anim_warning->show();
+ break;
+ }
+ }
+
} else {
hscroll->hide();
edit->set_disabled(true);
@@ -3610,6 +3625,7 @@ void AnimationTrackEditor::_notification(int p_what) {
snap->set_icon(get_icon("Snap", "EditorIcons"));
view_group->set_icon(get_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons"));
selected_filter->set_icon(get_icon("AnimationFilter", "EditorIcons"));
+ imported_anim_warning->set_icon(get_icon("NodeWarning", "EditorIcons"));
main_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
}
@@ -3857,7 +3873,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
ERR_FAIL_INDEX(p_track, animation->get_track_count());
if (snap->is_pressed() && step->get_value() != 0) {
- p_ofs = Math::stepify(p_ofs, step->get_value());
+ p_ofs = snap_time(p_ofs);
}
while (animation->track_find_key(p_track, p_ofs, true) != -1) { //make sure insertion point is valid
p_ofs += 0.001;
@@ -4116,6 +4132,7 @@ void AnimationTrackEditor::_update_key_edit() {
key_edit = memnew(AnimationTrackKeyEdit);
key_edit->animation = animation;
key_edit->track = selection.front()->key().track;
+ key_edit->use_fps = timeline->is_using_fps();
float ofs = animation->track_get_key_time(key_edit->track, selection.front()->key().key);
key_edit->key_ofs = ofs;
@@ -4889,12 +4906,28 @@ void AnimationTrackEditor::_selection_changed() {
float AnimationTrackEditor::snap_time(float p_value) {
if (snap->is_pressed()) {
- p_value = Math::stepify(p_value, step->get_value());
+
+ double snap_increment;
+ if (timeline->is_using_fps() && step->get_value() > 0)
+ snap_increment = 1.0 / step->get_value();
+ else
+ snap_increment = step->get_value();
+
+ p_value = Math::stepify(p_value, snap_increment);
}
return p_value;
}
+void AnimationTrackEditor::_show_imported_anim_warning() const {
+
+ EditorNode::get_singleton()->show_warning(TTR("This animation belongs to an imported scene, so changes to imported tracks will not be saved.\n\n"
+ "To enable the ability to add custom tracks, navigate to the scene's import settings and set\n"
+ "\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks\", then re-import.\n"
+ "Alternatively, use an import preset that imports animations to separate files."),
+ TTR("Warning: Editing imported animation"));
+}
+
void AnimationTrackEditor::_bind_methods() {
ClassDB::bind_method("_animation_changed", &AnimationTrackEditor::_animation_changed);
@@ -4933,6 +4966,7 @@ void AnimationTrackEditor::_bind_methods() {
ClassDB::bind_method("_view_group_toggle", &AnimationTrackEditor::_view_group_toggle);
ClassDB::bind_method("_selection_changed", &AnimationTrackEditor::_selection_changed);
ClassDB::bind_method("_snap_mode_changed", &AnimationTrackEditor::_snap_mode_changed);
+ ClassDB::bind_method("_show_imported_anim_warning", &AnimationTrackEditor::_show_imported_anim_warning);
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::REAL, "position"), PropertyInfo(Variant::BOOL, "drag")));
ADD_SIGNAL(MethodInfo("keying_changed"));
@@ -5003,6 +5037,13 @@ AnimationTrackEditor::AnimationTrackEditor() {
//timeline_vbox->add_child(memnew(HSeparator));
HBoxContainer *bottom_hb = memnew(HBoxContainer);
add_child(bottom_hb);
+
+ imported_anim_warning = memnew(Button);
+ imported_anim_warning->hide();
+ imported_anim_warning->set_tooltip(TTR("Warning: Editing imported animation"));
+ imported_anim_warning->connect("pressed", this, "_show_imported_anim_warning");
+ bottom_hb->add_child(imported_anim_warning);
+
bottom_hb->add_spacer();
selected_filter = memnew(ToolButton);
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 5ac5999b68..a69659642c 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -309,6 +309,9 @@ class AnimationTrackEditor : public VBoxContainer {
ToolButton *snap;
OptionButton *snap_mode;
+ Button *imported_anim_warning;
+ void _show_imported_anim_warning() const;
+
void _snap_mode_changed(int p_mode);
Vector<AnimationTrackEdit *> track_edits;
Vector<AnimationTrackEditGroup *> groups;
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index d097d34c97..ec984e480a 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1177,6 +1177,14 @@ void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) {
text_editor->select(p_line, p_begin, p_line, p_end);
}
+void CodeTextEditor::set_executing_line(int p_line) {
+ text_editor->set_executing_line(p_line);
+}
+
+void CodeTextEditor::clear_executing_line() {
+ text_editor->clear_executing_line();
+}
+
Variant CodeTextEditor::get_edit_state() {
Dictionary state;
diff --git a/editor/code_editor.h b/editor/code_editor.h
index e3dbfe1ce0..b98af377ce 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -217,6 +217,8 @@ public:
void goto_line(int p_line);
void goto_line_selection(int p_line, int p_begin, int p_end);
+ void set_executing_line(int p_line);
+ void clear_executing_line();
Variant get_edit_state();
void set_edit_state(const Variant &p_state);
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 03a71f3248..a9a96da7b1 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -113,14 +113,14 @@ Signal automatically called by parent dialog.
void ConnectDialog::ok_pressed() {
if (dst_method->get_text() == "") {
- error->set_text(TTR("Method in target Node must be specified!"));
+ error->set_text(TTR("Method in target node must be specified."));
error->popup_centered_minsize();
return;
}
Node *target = tree->get_selected();
if (target->get_script().is_null()) {
if (!target->has_method(dst_method->get_text())) {
- error->set_text(TTR("Target method not found! Specify a valid method or attach a script to target Node."));
+ error->set_text(TTR("Target method not found. Specify a valid method or attach a script to the target node."));
error->popup_centered_minsize();
return;
}
@@ -444,8 +444,9 @@ ConnectDialog::ConnectDialog() {
cdbinds = memnew(ConnectDialogBinds);
- error = memnew(ConfirmationDialog);
+ error = memnew(AcceptDialog);
add_child(error);
+ error->set_title(TTR("Cannot connect signal"));
error->get_ok()->set_text(TTR("Close"));
get_ok()->set_text(TTR("Connect"));
}
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index 59fe6dacfe..9b35d84426 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -64,7 +64,7 @@ class ConnectDialog : public ConfirmationDialog {
VBoxContainer *vbc_right;
SceneTreeEditor *tree;
- ConfirmationDialog *error;
+ AcceptDialog *error;
EditorInspector *bind_editor;
OptionButton *type_list;
CheckButton *deferred;
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 26bd651c2b..ac42f15f7f 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -721,6 +721,7 @@ CreateDialog::CreateDialog() {
favorites->connect("cell_selected", this, "_favorite_selected");
favorites->connect("item_activated", this, "_favorite_activated");
favorites->set_drag_forwarding(this);
+ favorites->add_constant_override("draw_guides", 1);
VBoxContainer *rec_vb = memnew(VBoxContainer);
vsc->add_child(rec_vb);
@@ -733,6 +734,7 @@ CreateDialog::CreateDialog() {
recent->set_hide_folding(true);
recent->connect("cell_selected", this, "_history_selected");
recent->connect("item_activated", this, "_history_activated");
+ recent->add_constant_override("draw_guides", 1);
VBoxContainer *vbc = memnew(VBoxContainer);
hsc->add_child(vbc);
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 5df2b687cc..bde73e9268 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -225,9 +225,9 @@ void DependencyEditor::edit(const String &p_path) {
popup_centered_ratio();
if (EditorNode::get_singleton()->is_scene_open(p_path)) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Scene '%s' is currently being edited.\nChanges will not take effect unless reloaded."), p_path.get_file()));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Scene '%s' is currently being edited.\nChanges will only take effect when reloaded."), p_path.get_file()));
} else if (ResourceCache::has(p_path)) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Resource '%s' is in use.\nChanges will take effect when reloaded."), p_path.get_file()));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Resource '%s' is in use.\nChanges will only take effect when reloaded."), p_path.get_file()));
}
}
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 2f2b0d2cba..e0c90808a0 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -638,12 +638,12 @@ void EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
String path = p_path;
if (!FileAccess::exists(path)) {
- EditorNode::get_singleton()->show_warning(TTR("Invalid Path.") + "\n" + TTR("File does not exist."));
+ EditorNode::get_singleton()->show_warning(TTR("Invalid path.") + "\n" + TTR("File does not exist."));
return;
}
if (!path.begins_with("res://")) {
- EditorNode::get_singleton()->show_warning(TTR("Invalid Path.") + "\n" + TTR("Not in resource path."));
+ EditorNode::get_singleton()->show_warning(TTR("Invalid path.") + "\n" + TTR("Not in resource path."));
return;
}
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index e8cf730796..e04bca2a9e 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -133,7 +133,7 @@ void EditorDirDialog::_make_dir() {
TreeItem *ti = tree->get_selected();
if (!ti) {
- mkdirerr->set_text(TTR("Please select a base directory first"));
+ mkdirerr->set_text(TTR("Please select a base directory first."));
mkdirerr->popup_centered_minsize();
return;
}
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index e0a2bbf477..5917869988 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -97,8 +97,10 @@ void EditorHelp::_class_desc_select(const String &p_select) {
emit_signal("go_to_help", "class_name:" + p_select.substr(1, p_select.length()));
return;
} else if (p_select.begins_with("@")) {
- String tag = p_select.substr(1, 8).rstrip(" ");
- String link = p_select.substr(9, p_select.length());
+ int tag_end = p_select.find(" ");
+
+ String tag = p_select.substr(1, tag_end - 1);
+ String link = p_select.substr(tag_end + 1, p_select.length()).lstrip(" ");
String topic;
Map<String, int> *table = NULL;
@@ -230,7 +232,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
}
if (p_overview && p_method.description != "") {
- class_desc->push_meta("@method" + p_method.name);
+ class_desc->push_meta("@method " + p_method.name);
}
class_desc->push_color(headline_color);
@@ -468,7 +470,7 @@ void EditorHelp::_update_doc() {
}
class_desc->push_cell();
if (describe) {
- class_desc->push_meta("@member" + cd.properties[i].name);
+ class_desc->push_meta("@member " + cd.properties[i].name);
}
class_desc->push_font(doc_code_font);
@@ -1192,10 +1194,13 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
} else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ")) {
- String link_target = tag.substr(tag.find(" ") + 1, tag.length());
- String link_tag = tag.substr(0, tag.find(" ")).rpad(8);
+ int tag_end = tag.find(" ");
+
+ String link_tag = tag.substr(0, tag_end);
+ String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
+
p_rt->push_color(link_color);
- p_rt->push_meta("@" + link_tag + link_target);
+ p_rt->push_meta("@" + link_tag + " " + link_target);
p_rt->add_text(link_target + (tag.begins_with("method ") ? "()" : ""));
p_rt->pop();
p_rt->pop();
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index b0a1331b2e..ecb9ea5f35 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -434,7 +434,7 @@ bool EditorPropertyRevert::is_node_property_different(Node *p_node, const Varian
float a = p_current;
float b = p_orig;
- return Math::abs(a - b) > CMP_EPSILON; //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error
+ return !Math::is_equal_approx(a, b); //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error
}
return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig));
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index fe52e7eb7e..8703076a57 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1631,7 +1631,7 @@ void EditorNode::_edit_current() {
editable_warning = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
} else {
if ((!get_edited_scene() || get_edited_scene()->get_filename() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") {
- editable_warning = TTR("This resource belongs to a scene that was instanced or inherited.\nChanges to it will not be kept when saving the current scene.");
+ editable_warning = TTR("This resource belongs to a scene that was instanced or inherited.\nChanges to it won't be kept when saving the current scene.");
}
}
} else if (current_res->get_path().is_resource_file()) {
@@ -1656,14 +1656,14 @@ void EditorNode::_edit_current() {
if (get_edited_scene() && get_edited_scene()->get_filename() != String()) {
String source_scene = get_edited_scene()->get_filename();
if (FileAccess::exists(source_scene + ".import")) {
- editable_warning = TTR("This scene was imported, so changes to it will not be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ editable_warning = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
}
}
} else {
if (current_obj->is_class("ScriptEditorDebuggerInspectedObject")) {
- editable_warning = TTR("This is a remote object so changes to it will not be kept.\nPlease read the documentation relevant to debugging to better understand this workflow.");
+ editable_warning = TTR("This is a remote object, so changes to it won't be kept.\nPlease read the documentation relevant to debugging to better understand this workflow.");
capitalize = false;
disable_folding = true;
}
@@ -1937,6 +1937,21 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
open_request(previous_scenes.back()->get());
} break;
+ case FILE_CLOSE_OTHERS:
+ case FILE_CLOSE_RIGHT:
+ case FILE_CLOSE_ALL: {
+ if (editor_data.get_edited_scene_count() > 1 && (current_option != FILE_CLOSE_RIGHT || editor_data.get_edited_scene() < editor_data.get_edited_scene_count() - 1)) {
+ int next_tab = editor_data.get_edited_scene() + 1;
+ next_tab %= editor_data.get_edited_scene_count();
+ _scene_tab_closed(next_tab, current_option);
+ } else {
+ if (current_option != FILE_CLOSE_ALL)
+ current_option = -1;
+ else
+ _scene_tab_closed(editor_data.get_edited_scene());
+ }
+
+ } break;
case FILE_CLOSE_ALL_AND_QUIT:
case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
case FILE_CLOSE: {
@@ -2436,7 +2451,13 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case SETTINGS_MANAGE_FEATURE_PROFILES: {
- feature_profile_manager->popup_centered_ratio();
+ Size2 popup_size = Size2(900, 800) * editor_get_scale();
+ Size2 window_size = get_viewport()->get_size();
+
+ popup_size.x = MIN(window_size.x * 0.8, popup_size.x);
+ popup_size.y = MIN(window_size.y * 0.8, popup_size.y);
+
+ feature_profile_manager->popup_centered(popup_size);
} break;
case SETTINGS_TOGGLE_FULLSCREEN: {
@@ -2553,6 +2574,9 @@ void EditorNode::_discard_changes(const String &p_str) {
case FILE_CLOSE_ALL_AND_QUIT:
case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
case FILE_CLOSE:
+ case FILE_CLOSE_OTHERS:
+ case FILE_CLOSE_RIGHT:
+ case FILE_CLOSE_ALL:
case SCENE_TAB_CLOSE: {
_remove_scene(tab_closing);
@@ -2565,6 +2589,15 @@ void EditorNode::_discard_changes(const String &p_str) {
} else {
_menu_option_confirm(current_option, false);
}
+ } else if (current_option == FILE_CLOSE_OTHERS || current_option == FILE_CLOSE_RIGHT) {
+ if (editor_data.get_edited_scene_count() == 1 || (current_option == FILE_CLOSE_RIGHT && editor_data.get_edited_scene_count() <= editor_data.get_edited_scene() + 1)) {
+ current_option = -1;
+ save_confirmation->hide();
+ } else {
+ _menu_option_confirm(current_option, false);
+ }
+ } else if (current_option == FILE_CLOSE_ALL && editor_data.get_edited_scene_count() > 0) {
+ _menu_option_confirm(current_option, false);
} else {
current_option = -1;
save_confirmation->hide();
@@ -4192,8 +4225,8 @@ void EditorNode::_scene_tab_script_edited(int p_tab) {
inspector_dock->edit_resource(script);
}
-void EditorNode::_scene_tab_closed(int p_tab) {
- current_option = SCENE_TAB_CLOSE;
+void EditorNode::_scene_tab_closed(int p_tab, int option) {
+ current_option = option;
tab_closing = p_tab;
Node *scene = editor_data.get_edited_scene_root(p_tab);
if (!scene) {
@@ -4266,7 +4299,11 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
scene_tabs_context_menu->add_separator();
scene_tabs_context_menu->add_item(TTR("Show in FileSystem"), FILE_SHOW_IN_FILESYSTEM);
scene_tabs_context_menu->add_item(TTR("Play This Scene"), RUN_PLAY_SCENE);
+ scene_tabs_context_menu->add_separator();
scene_tabs_context_menu->add_item(TTR("Close Tab"), FILE_CLOSE);
+ scene_tabs_context_menu->add_item(TTR("Close Other Tabs"), FILE_CLOSE_OTHERS);
+ scene_tabs_context_menu->add_item(TTR("Close Tabs to the Right"), FILE_CLOSE_RIGHT);
+ scene_tabs_context_menu->add_item(TTR("Close All Tabs"), FILE_CLOSE_ALL);
}
scene_tabs_context_menu->set_position(mb->get_global_position());
scene_tabs_context_menu->popup();
@@ -5523,7 +5560,7 @@ EditorNode::EditorNode() {
scene_tabs->set_drag_to_rearrange_enabled(true);
scene_tabs->connect("tab_changed", this, "_scene_tab_changed");
scene_tabs->connect("right_button_pressed", this, "_scene_tab_script_edited");
- scene_tabs->connect("tab_close", this, "_scene_tab_closed");
+ scene_tabs->connect("tab_close", this, "_scene_tab_closed", varray(SCENE_TAB_CLOSE));
scene_tabs->connect("tab_hover", this, "_scene_tab_hover");
scene_tabs->connect("mouse_exited", this, "_scene_tab_exit");
scene_tabs->connect("gui_input", this, "_scene_tab_input");
diff --git a/editor/editor_node.h b/editor/editor_node.h
index a06708eb54..0084d421f9 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -150,6 +150,9 @@ private:
FILE_QUICK_OPEN_SCRIPT,
FILE_OPEN_PREV,
FILE_CLOSE,
+ FILE_CLOSE_OTHERS,
+ FILE_CLOSE_RIGHT,
+ FILE_CLOSE_ALL,
FILE_CLOSE_ALL_AND_QUIT,
FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER,
FILE_QUIT,
@@ -563,7 +566,7 @@ private:
void _dock_split_dragged(int ofs);
void _dock_popup_exit();
void _scene_tab_changed(int p_tab);
- void _scene_tab_closed(int p_tab);
+ void _scene_tab_closed(int p_tab, int option = SCENE_TAB_CLOSE);
void _scene_tab_hover(int p_tab);
void _scene_tab_exit();
void _scene_tab_input(const Ref<InputEvent> &p_input);
diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp
index 7e9d3a889e..12510e27de 100644
--- a/editor/editor_path.cpp
+++ b/editor/editor_path.cpp
@@ -56,122 +56,67 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(obj);
- int index = popup->get_item_count();
- popup->add_icon_item(icon, E->get().name.capitalize(), objects.size());
- popup->set_item_h_offset(index, p_depth * 10 * EDSCALE);
+ int index = get_popup()->get_item_count();
+ get_popup()->add_icon_item(icon, E->get().name.capitalize(), objects.size());
+ get_popup()->set_item_h_offset(index, p_depth * 10 * EDSCALE);
objects.push_back(obj->get_instance_id());
_add_children_to_popup(obj, p_depth + 1);
}
}
-void EditorPath::_gui_input(const Ref<InputEvent> &p_event) {
+void EditorPath::_about_to_show() {
- Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
-
- Object *obj = ObjectDB::get_instance(history->get_path_object(history->get_path_size() - 1));
- if (!obj)
- return;
-
- objects.clear();
- popup->clear();
- _add_children_to_popup(obj);
- popup->set_position(get_global_position() + Vector2(0, get_size().height));
- popup->set_size(Size2(get_size().width, 1));
- popup->popup();
- }
-}
+ Object *obj = ObjectDB::get_instance(history->get_path_object(history->get_path_size() - 1));
+ if (!obj)
+ return;
-void EditorPath::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_MOUSE_ENTER: {
- mouse_over = true;
- update();
- } break;
- case NOTIFICATION_MOUSE_EXIT: {
- mouse_over = false;
- update();
- } break;
- case NOTIFICATION_DRAW: {
-
- RID ci = get_canvas_item();
- Ref<Font> label_font = get_font("font", "Label");
- Size2i size = get_size();
- Ref<Texture> sn = get_icon("SmallNext", "EditorIcons");
- Ref<StyleBox> sb = get_stylebox("pressed", "Button");
-
- int ofs = sb->get_margin(MARGIN_LEFT);
-
- if (mouse_over) {
- draw_style_box(sb, Rect2(Point2(), get_size()));
- }
-
- for (int i = 0; i < history->get_path_size(); i++) {
-
- Object *obj = ObjectDB::get_instance(history->get_path_object(i));
- if (!obj)
- continue;
-
- String type = obj->get_class();
-
- Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(obj);
-
- if (icon.is_valid()) {
- icon->draw(ci, Point2i(ofs, (size.height - icon->get_height()) / 2));
- ofs += icon->get_width();
- }
-
- if (i == history->get_path_size() - 1) {
- //add name
- ofs += 4;
- int left = size.width - ofs;
- if (left < 0)
- continue;
- String name;
- if (Object::cast_to<Resource>(obj)) {
-
- Resource *r = Object::cast_to<Resource>(obj);
- if (r->get_path().is_resource_file())
- name = r->get_path().get_file();
- else
- name = r->get_name();
-
- if (name == "")
- name = r->get_class();
- } else if (obj->is_class("ScriptEditorDebuggerInspectedObject"))
- name = obj->call("get_title");
- else if (Object::cast_to<Node>(obj))
- name = Object::cast_to<Node>(obj)->get_name();
- else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "")
- name = Object::cast_to<Resource>(obj)->get_name();
- else
- name = obj->get_class();
-
- set_tooltip(obj->get_class());
-
- label_font->draw(ci, Point2i(ofs, (size.height - label_font->get_height()) / 2 + label_font->get_ascent()), name, get_color("font_color", "Label"), left);
- } else {
- //add arrow
-
- //sn->draw(ci,Point2i(ofs,(size.height-sn->get_height())/2));
- //ofs+=sn->get_width();
- ofs += 5; //just looks better! somehow
- }
- }
-
- } break;
- }
+ objects.clear();
+ get_popup()->clear();
+ get_popup()->set_size(Size2(get_size().width, 1));
+ _add_children_to_popup(obj);
}
void EditorPath::update_path() {
- update();
+ for (int i = 0; i < history->get_path_size(); i++) {
+
+ Object *obj = ObjectDB::get_instance(history->get_path_object(i));
+ if (!obj)
+ continue;
+
+ Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(obj);
+ if (icon.is_valid())
+ set_icon(icon);
+
+ if (i == history->get_path_size() - 1) {
+ String name;
+ if (Object::cast_to<Resource>(obj)) {
+
+ Resource *r = Object::cast_to<Resource>(obj);
+ if (r->get_path().is_resource_file())
+ name = r->get_path().get_file();
+ else
+ name = r->get_name();
+
+ if (name == "")
+ name = r->get_class();
+ } else if (obj->is_class("ScriptEditorDebuggerInspectedObject"))
+ name = obj->call("get_title");
+ else if (Object::cast_to<Node>(obj))
+ name = Object::cast_to<Node>(obj)->get_name();
+ else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "")
+ name = Object::cast_to<Resource>(obj)->get_name();
+ else
+ name = obj->get_class();
+
+ set_text(" " + name); // An extra space so the text is not too close of the icon.
+ set_tooltip(obj->get_class());
+ }
+ }
}
-void EditorPath::_popup_select(int p_idx) {
+void EditorPath::_id_pressed(int p_idx) {
ERR_FAIL_INDEX(p_idx, objects.size());
@@ -184,15 +129,14 @@ void EditorPath::_popup_select(int p_idx) {
void EditorPath::_bind_methods() {
- ClassDB::bind_method("_gui_input", &EditorPath::_gui_input);
- ClassDB::bind_method("_popup_select", &EditorPath::_popup_select);
+ ClassDB::bind_method("_about_to_show", &EditorPath::_about_to_show);
+ ClassDB::bind_method("_id_pressed", &EditorPath::_id_pressed);
}
EditorPath::EditorPath(EditorHistory *p_history) {
history = p_history;
- mouse_over = false;
- popup = memnew(PopupMenu);
- popup->connect("id_pressed", this, "_popup_select");
- add_child(popup);
+ set_text_align(ALIGN_LEFT);
+ get_popup()->connect("about_to_show", this, "_about_to_show");
+ get_popup()->connect("id_pressed", this, "_id_pressed");
}
diff --git a/editor/editor_path.h b/editor/editor_path.h
index e12ca02534..2dc4d21f9b 100644
--- a/editor/editor_path.h
+++ b/editor/editor_path.h
@@ -32,27 +32,23 @@
#define EDITOR_PATH_H
#include "editor_data.h"
-#include "scene/gui/control.h"
-#include "scene/gui/popup_menu.h"
+#include "scene/gui/menu_button.h"
-class EditorPath : public Control {
+class EditorPath : public MenuButton {
- GDCLASS(EditorPath, Control);
+ GDCLASS(EditorPath, MenuButton);
EditorHistory *history;
Vector<ObjectID> objects;
- PopupMenu *popup;
- bool mouse_over;
EditorPath();
- void _popup_select(int p_idx);
- void _gui_input(const Ref<InputEvent> &p_event);
+ void _id_pressed(int p_idx);
+ void _about_to_show();
void _add_children_to_popup(Object *p_obj, int p_depth = 0);
protected:
static void _bind_methods();
- void _notification(int p_what);
public:
void update_path();
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 9e9d2cf47a..b65a484b16 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -646,6 +646,7 @@ void EditorSettings::_load_default_text_editor_theme() {
_initial_set("text_editor/highlighting/member_variable_color", Color::html("e64e59"));
_initial_set("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4));
_initial_set("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2));
+ _initial_set("text_editor/highlighting/executing_line_color", Color(0.2, 0.8, 0.2, 0.4));
_initial_set("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
_initial_set("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
_initial_set("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1));
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 9641e10114..b8dd29cecc 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -831,6 +831,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("read_only", "TextEdit", style_widget_disabled);
theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons"));
+ theme->set_icon("folded", "TextEdit", theme->get_icon("GuiTreeArrowRight", "EditorIcons"));
+ theme->set_icon("fold", "TextEdit", theme->get_icon("GuiTreeArrowDown", "EditorIcons"));
theme->set_color("font_color", "TextEdit", font_color);
theme->set_color("caret_color", "TextEdit", font_color);
theme->set_color("selection_color", "TextEdit", font_color_selection);
@@ -1114,6 +1116,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color member_variable_color = main_color.linear_interpolate(mono_color, 0.6);
const Color mark_color = Color(error_color.r, error_color.g, error_color.b, 0.3);
const Color breakpoint_color = error_color;
+ const Color executing_line_color = Color(0.2, 0.8, 0.2, 0.4);
const Color code_folding_color = alpha3;
const Color search_result_color = alpha1;
const Color search_result_border_color = alpha3;
@@ -1149,6 +1152,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
setting->set_initial_value("text_editor/highlighting/member_variable_color", member_variable_color, true);
setting->set_initial_value("text_editor/highlighting/mark_color", mark_color, true);
setting->set_initial_value("text_editor/highlighting/breakpoint_color", breakpoint_color, true);
+ setting->set_initial_value("text_editor/highlighting/executing_line_color", executing_line_color, true);
setting->set_initial_value("text_editor/highlighting/code_folding_color", code_folding_color, true);
setting->set_initial_value("text_editor/highlighting/search_result_color", search_result_color, true);
setting->set_initial_value("text_editor/highlighting/search_result_border_color", search_result_border_color, true);
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index aa2a03510d..ed6d6578ad 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -690,7 +690,7 @@ ExportTemplateManager::ExportTemplateManager() {
remove_confirm->connect("confirmed", this, "_uninstall_template_confirm");
template_open = memnew(FileDialog);
- template_open->set_title(TTR("Select template file"));
+ template_open->set_title(TTR("Select Template File"));
template_open->add_filter("*.tpz ; Godot Export Templates");
template_open->set_access(FileDialog::ACCESS_FILESYSTEM);
template_open->set_mode(FileDialog::MODE_OPEN_FILE);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index aade606412..6248680a52 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1208,7 +1208,7 @@ void FileSystemDock::_make_dir_confirm() {
return;
} else if (dir_name.find("/") != -1 || dir_name.find("\\") != -1 || dir_name.find(":") != -1 || dir_name.find("*") != -1 ||
dir_name.find("|") != -1 || dir_name.find(">") != -1 || dir_name.ends_with(".") || dir_name.ends_with(" ")) {
- EditorNode::get_singleton()->show_warning(TTR("Provided name contains invalid characters"));
+ EditorNode::get_singleton()->show_warning(TTR("Provided name contains invalid characters."));
return;
}
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index ab515785da..1de276b940 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1127,7 +1127,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), animations_out ? true : false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), animations_out ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_linear_error"), 0.05));
@@ -1290,7 +1290,10 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
Object::cast_to<Spatial>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
}
- scene->set_name(p_options["nodes/root_name"]);
+ if (p_options["nodes/root_name"] != "Scene Root")
+ scene->set_name(p_options["nodes/root_name"]);
+ else
+ scene->set_name(p_save_path.get_file().get_basename());
err = OK;
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index 52dec47343..fdf1103258 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -409,12 +409,12 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
float amp = Math::abs(ampChannelSum / (float)format_channels);
if (!found && amp > limit) {
- first = i / format_channels;
+ first = i;
found = true;
}
if (found && amp > limit) {
- last = i / format_channels;
+ last = i;
}
}
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 918f3a2149..5e8fb8e059 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -195,7 +195,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
//add triangle!
if (blend_space->has_triangle(making_triangle[0], making_triangle[1], making_triangle[2])) {
making_triangle.clear();
- EditorNode::get_singleton()->show_warning(TTR("Triangle already exists"));
+ EditorNode::get_singleton()->show_warning(TTR("Triangle already exists."));
return;
}
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index f13c2170ea..bfee76492b 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -949,7 +949,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
filter_dialog->add_child(filter_vbox);
filter_enabled = memnew(CheckBox);
- filter_enabled->set_text(TTR("Enable filtering"));
+ filter_enabled->set_text(TTR("Enable Filtering"));
filter_enabled->connect("pressed", this, "_filter_toggled");
filter_vbox->add_child(filter_enabled);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index e5228ff1e7..88bb8e38fe 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -3433,7 +3433,7 @@ void CanvasItemEditor::_notification(int p_what) {
p->add_separator();
p->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), "Full Rect", ANCHORS_AND_MARGINS_PRESET_WIDE);
p->add_separator();
- p->add_submenu_item(TTR("Anchors only"), "Anchors");
+ p->add_submenu_item(TTR("Anchors Only"), "Anchors");
p->set_item_icon(20, get_icon("Anchor", "EditorIcons"));
anchors_popup->clear();
@@ -3916,6 +3916,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
viewport->update();
} break;
case LOCK_SELECTED: {
+ undo_redo->create_action(TTR("Lock Selected"));
+
List<Node *> selection = editor_selection->get_selected_node_list();
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
@@ -3924,12 +3926,18 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
continue;
- canvas_item->set_meta("_edit_lock_", true);
- emit_signal("item_lock_status_changed");
+ undo_redo->add_do_method(canvas_item, "set_meta", "_edit_lock_", true);
+ undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_lock_");
+ undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- viewport->update();
+ undo_redo->add_do_method(viewport, "update", Variant());
+ undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->commit_action();
} break;
case UNLOCK_SELECTED: {
+ undo_redo->create_action(TTR("Unlock Selected"));
+
List<Node *> selection = editor_selection->get_selected_node_list();
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
@@ -3938,12 +3946,18 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
continue;
- canvas_item->set_meta("_edit_lock_", Variant());
- emit_signal("item_lock_status_changed");
+ undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_lock_");
+ undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_lock_", true);
+ undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- viewport->update();
+ undo_redo->add_do_method(viewport, "update", Variant());
+ undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->commit_action();
} break;
case GROUP_SELECTED: {
+ undo_redo->create_action(TTR("Group Selected"));
+
List<Node *> selection = editor_selection->get_selected_node_list();
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
@@ -3952,12 +3966,18 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
continue;
- canvas_item->set_meta("_edit_group_", true);
- emit_signal("item_group_status_changed");
+ undo_redo->add_do_method(canvas_item, "set_meta", "_edit_group_", true);
+ undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_group_");
+ undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- viewport->update();
+ undo_redo->add_do_method(viewport, "update", Variant());
+ undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->commit_action();
} break;
case UNGROUP_SELECTED: {
+ undo_redo->create_action(TTR("Ungroup Selected"));
+
List<Node *> selection = editor_selection->get_selected_node_list();
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
@@ -3966,10 +3986,14 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root())
continue;
- canvas_item->set_meta("_edit_group_", Variant());
- emit_signal("item_group_status_changed");
+ undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_group_");
+ undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_group_", true);
+ undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- viewport->update();
+ undo_redo->add_do_method(viewport, "update", Variant());
+ undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->commit_action();
} break;
case ANCHORS_AND_MARGINS_PRESET_TOP_LEFT: {
_set_anchors_and_margins_preset(PRESET_TOP_LEFT);
@@ -4787,24 +4811,24 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
PopupMenu *p = snap_config_menu->get_popup();
p->connect("id_pressed", this, "_popup_callback");
p->set_hide_on_checkable_item_selection(false);
- p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_grid", TTR("Snap to grid")), SNAP_USE_GRID);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_grid", TTR("Snap to Grid")), SNAP_USE_GRID);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/configure_snap", TTR("Configure Snap...")), SNAP_CONFIGURE);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_relative", TTR("Snap Relative")), SNAP_RELATIVE);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_pixel_snap", TTR("Use Pixel Snap")), SNAP_USE_PIXEL);
- p->add_submenu_item(TTR("Smart snapping"), "SmartSnapping");
+ p->add_submenu_item(TTR("Smart Snapping"), "SmartSnapping");
smartsnap_config_popup = memnew(PopupMenu);
p->add_child(smartsnap_config_popup);
smartsnap_config_popup->set_name("SmartSnapping");
smartsnap_config_popup->connect("id_pressed", this, "_popup_callback");
smartsnap_config_popup->set_hide_on_checkable_item_selection(false);
- smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_parent", TTR("Snap to parent")), SNAP_USE_NODE_PARENT);
- smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to node anchor")), SNAP_USE_NODE_ANCHORS);
- smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_sides", TTR("Snap to node sides")), SNAP_USE_NODE_SIDES);
- smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_center", TTR("Snap to node center")), SNAP_USE_NODE_CENTER);
- smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to other nodes")), SNAP_USE_OTHER_NODES);
- smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to guides")), SNAP_USE_GUIDES);
+ smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_parent", TTR("Snap to Parent")), SNAP_USE_NODE_PARENT);
+ smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to Node Anchor")), SNAP_USE_NODE_ANCHORS);
+ smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_sides", TTR("Snap to Node Sides")), SNAP_USE_NODE_SIDES);
+ smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_center", TTR("Snap to Node Center")), SNAP_USE_NODE_CENTER);
+ smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to Other Nodes")), SNAP_USE_OTHER_NODES);
+ smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to Guides")), SNAP_USE_GUIDES);
hb->add_child(memnew(VSeparator));
@@ -5442,7 +5466,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
selector = memnew(AcceptDialog);
editor->get_gui_base()->add_child(selector);
- selector->set_title(TTR("Change default type"));
+ selector->set_title(TTR("Change Default Type"));
selector->connect("confirmed", this, "_on_change_type_confirmed");
selector->connect("popup_hide", this, "_on_change_type_closed");
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index 559558cdb8..1622ce17b2 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -267,6 +267,7 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) {
menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
// menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
menu->set_text(TTR("Particles"));
+ menu->set_switch_on_hover(true);
toolbar->add_child(menu);
file = memnew(EditorFileDialog);
diff --git a/editor/plugins/cpu_particles_editor_plugin.cpp b/editor/plugins/cpu_particles_editor_plugin.cpp
index 7222525dd7..70be9b95bb 100644
--- a/editor/plugins/cpu_particles_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_editor_plugin.cpp
@@ -101,6 +101,7 @@ CPUParticlesEditor::CPUParticlesEditor() {
particles_editor_hb = memnew(HBoxContainer);
SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
options = memnew(MenuButton);
+ options->set_switch_on_hover(true);
particles_editor_hb->add_child(options);
particles_editor_hb->hide();
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 3d76b5da21..55feb40c2c 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -53,11 +53,11 @@ CurveEditor::CurveEditor() {
_presets_menu = memnew(PopupMenu);
_presets_menu->set_name("_presets_menu");
- _presets_menu->add_item(TTR("Flat0"), PRESET_FLAT0);
- _presets_menu->add_item(TTR("Flat1"), PRESET_FLAT1);
+ _presets_menu->add_item(TTR("Flat 0"), PRESET_FLAT0);
+ _presets_menu->add_item(TTR("Flat 1"), PRESET_FLAT1);
_presets_menu->add_item(TTR("Linear"), PRESET_LINEAR);
- _presets_menu->add_item(TTR("Ease in"), PRESET_EASE_IN);
- _presets_menu->add_item(TTR("Ease out"), PRESET_EASE_OUT);
+ _presets_menu->add_item(TTR("Ease In"), PRESET_EASE_IN);
+ _presets_menu->add_item(TTR("Ease Out"), PRESET_EASE_OUT);
_presets_menu->add_item(TTR("Smoothstep"), PRESET_SMOOTHSTEP);
_presets_menu->connect("id_pressed", this, "_on_preset_item_selected");
_context_menu->add_child(_presets_menu);
@@ -194,7 +194,7 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) {
Vector2 dir = (control_pos - point_pos).normalized();
real_t tangent;
- if (Math::abs(dir.x) > CMP_EPSILON)
+ if (!Math::is_zero_approx(dir.x))
tangent = dir.y / dir.x;
else
tangent = 9999 * (dir.y >= 0 ? 1 : -1);
@@ -330,10 +330,10 @@ void CurveEditor::open_context_menu(Vector2 pos) {
_context_menu->clear();
if (_curve_ref.is_valid()) {
- _context_menu->add_item(TTR("Add point"), CONTEXT_ADD_POINT);
+ _context_menu->add_item(TTR("Add Point"), CONTEXT_ADD_POINT);
if (_selected_point >= 0) {
- _context_menu->add_item(TTR("Remove point"), CONTEXT_REMOVE_POINT);
+ _context_menu->add_item(TTR("Remove Point"), CONTEXT_REMOVE_POINT);
if (_selected_tangent != TANGENT_NONE) {
_context_menu->add_separator();
@@ -351,12 +351,12 @@ void CurveEditor::open_context_menu(Vector2 pos) {
_context_menu->add_separator();
if (_selected_point > 0) {
- _context_menu->add_check_item(TTR("Left linear"), CONTEXT_LEFT_LINEAR);
+ _context_menu->add_check_item(TTR("Left Linear"), CONTEXT_LEFT_LINEAR);
_context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_LEFT_LINEAR),
_curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR);
}
if (_selected_point + 1 < _curve_ref->get_point_count()) {
- _context_menu->add_check_item(TTR("Right linear"), CONTEXT_RIGHT_LINEAR);
+ _context_menu->add_check_item(TTR("Right Linear"), CONTEXT_RIGHT_LINEAR);
_context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_RIGHT_LINEAR),
_curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR);
}
@@ -366,7 +366,7 @@ void CurveEditor::open_context_menu(Vector2 pos) {
_context_menu->add_separator();
}
- _context_menu->add_submenu_item(TTR("Load preset"), _presets_menu->get_name());
+ _context_menu->add_submenu_item(TTR("Load Preset"), _presets_menu->get_name());
_context_menu->set_size(Size2(0, 0));
_context_menu->popup();
diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp
index cf111dc4ce..635b934333 100644
--- a/editor/plugins/mesh_instance_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_editor_plugin.cpp
@@ -412,6 +412,7 @@ void MeshInstanceEditor::_bind_methods() {
MeshInstanceEditor::MeshInstanceEditor() {
options = memnew(MenuButton);
+ options->set_switch_on_hover(true);
SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text(TTR("Mesh"));
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index 8ff6080443..fc0a425bfc 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -293,6 +293,7 @@ void MultiMeshEditor::_bind_methods() {
MultiMeshEditor::MultiMeshEditor() {
options = memnew(MenuButton);
+ options->set_switch_on_hover(true);
SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text("MultiMesh");
diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp
index 70d4919e9f..50bdf4512b 100644
--- a/editor/plugins/particles_2d_editor_plugin.cpp
+++ b/editor/plugins/particles_2d_editor_plugin.cpp
@@ -375,6 +375,7 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
menu->get_popup()->add_separator();
menu->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
menu->set_text(TTR("Particles"));
+ menu->set_switch_on_hover(true);
toolbar->add_child(menu);
file = memnew(EditorFileDialog);
diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp
index 0032850535..09180edf2a 100644
--- a/editor/plugins/particles_editor_plugin.cpp
+++ b/editor/plugins/particles_editor_plugin.cpp
@@ -454,6 +454,7 @@ ParticlesEditor::ParticlesEditor() {
particles_editor_hb = memnew(HBoxContainer);
SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
options = memnew(MenuButton);
+ options->set_switch_on_hover(true);
particles_editor_hb->add_child(options);
particles_editor_hb->hide();
diff --git a/editor/plugins/physical_bone_plugin.cpp b/editor/plugins/physical_bone_plugin.cpp
index 9ea37aceb9..96681a105f 100644
--- a/editor/plugins/physical_bone_plugin.cpp
+++ b/editor/plugins/physical_bone_plugin.cpp
@@ -61,7 +61,7 @@ PhysicalBoneEditor::PhysicalBoneEditor(EditorNode *p_editor) :
button_transform_joint = memnew(ToolButton);
spatial_editor_hb->add_child(button_transform_joint);
- button_transform_joint->set_text(TTR("Move joint"));
+ button_transform_joint->set_text(TTR("Move Joint"));
button_transform_joint->set_icon(SpatialEditor::get_singleton()->get_icon("PhysicalBone", "EditorIcons"));
button_transform_joint->set_toggle_mode(true);
button_transform_joint->connect("toggled", this, "_on_toggle_button_transform_joint");
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index af43f679fd..712b1a0ae4 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -1060,8 +1060,7 @@ void Polygon2DEditor::_uv_draw() {
polygon_fill_color.push_back(pf);
}
Color prev_color = Color(0.5, 0.5, 0.5);
- Rect2 rect(Point2(), mtx.basis_xform(base_tex->get_size()));
- rect.expand_to(mtx.basis_xform(uv_edit_draw->get_size()));
+ Rect2 rect;
int uv_draw_max = uvs.size();
@@ -1204,7 +1203,8 @@ void Polygon2DEditor::_uv_draw() {
uv_edit_draw->draw_circle(bone_paint_pos, bone_paint_radius->get_value() * EDSCALE, Color(1, 1, 1, 0.1));
}
- rect = rect.grow(200);
+ rect.position -= uv_edit_draw->get_size();
+ rect.size += uv_edit_draw->get_size() * 2.0;
updating_uv_scroll = true;
uv_hscroll->set_min(rect.position.x);
uv_hscroll->set_max(rect.position.x + rect.size.x);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 03287b8cf9..0982da784f 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -312,6 +312,38 @@ void ScriptEditor::_goto_script_line(REF p_script, int p_line) {
}
}
+void ScriptEditor::_set_execution(REF p_script, int p_line) {
+ Ref<Script> script = Object::cast_to<Script>(*p_script);
+ if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
+ for (int i = 0; i < tab_container->get_child_count(); i++) {
+
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ if (!se)
+ continue;
+
+ if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) {
+ se->set_executing_line(p_line);
+ }
+ }
+ }
+}
+
+void ScriptEditor::_clear_execution(REF p_script) {
+ Ref<Script> script = Object::cast_to<Script>(*p_script);
+ if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
+ for (int i = 0; i < tab_container->get_child_count(); i++) {
+
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ if (!se)
+ continue;
+
+ if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) {
+ se->clear_executing_line();
+ }
+ }
+ }
+}
+
ScriptEditorBase *ScriptEditor::_get_current_editor() const {
int selected = tab_container->get_current_tab();
@@ -2878,6 +2910,8 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method("_res_saved_callback", &ScriptEditor::_res_saved_callback);
ClassDB::bind_method("_goto_script_line", &ScriptEditor::_goto_script_line);
ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2);
+ ClassDB::bind_method("_set_execution", &ScriptEditor::_set_execution);
+ ClassDB::bind_method("_clear_execution", &ScriptEditor::_clear_execution);
ClassDB::bind_method("_help_search", &ScriptEditor::_help_search);
ClassDB::bind_method("_save_history", &ScriptEditor::_save_history);
ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path);
@@ -2916,6 +2950,7 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw);
ClassDB::bind_method(D_METHOD("drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("goto_line", "line_number"), &ScriptEditor::_goto_script_line2);
ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script);
ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts);
ClassDB::bind_method(D_METHOD("open_script_create_dialog", "base_name", "base_path"), &ScriptEditor::open_script_create_dialog);
@@ -3168,6 +3203,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
debugger = memnew(ScriptEditorDebugger(editor));
debugger->connect("goto_script_line", this, "_goto_script_line");
+ debugger->connect("set_execution", this, "_set_execution");
+ debugger->connect("clear_execution", this, "_clear_execution");
debugger->connect("show_debugger", this, "_show_debugger");
disk_changed = memnew(ConfirmationDialog);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index f13308dec7..a17fed1e06 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -96,6 +96,8 @@ public:
virtual Variant get_edit_state() = 0;
virtual void set_edit_state(const Variant &p_state) = 0;
virtual void goto_line(int p_line, bool p_with_error = false) = 0;
+ virtual void set_executing_line(int p_line) = 0;
+ virtual void clear_executing_line() = 0;
virtual void trim_trailing_whitespace() = 0;
virtual void convert_indent_to_spaces() = 0;
virtual void convert_indent_to_tabs() = 0;
@@ -318,6 +320,8 @@ class ScriptEditor : public PanelContainer {
void _goto_script_line2(int p_line);
void _goto_script_line(REF p_script, int p_line);
+ void _set_execution(REF p_script, int p_line);
+ void _clear_execution(REF p_script);
void _breaked(bool p_breaked, bool p_can_debug);
void _show_debugger(bool p_show);
void _update_window_menu();
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 46b2e8a5f8..d40e67cc8c 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -214,6 +214,7 @@ void ScriptTextEditor::_load_theme_settings() {
Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color");
Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color");
Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color");
+ Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color");
Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color");
Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color");
Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color");
@@ -245,6 +246,7 @@ void ScriptTextEditor::_load_theme_settings() {
text_edit->add_color_override("function_color", function_color);
text_edit->add_color_override("member_variable_color", member_variable_color);
text_edit->add_color_override("breakpoint_color", breakpoint_color);
+ text_edit->add_color_override("executing_line_color", executing_line_color);
text_edit->add_color_override("mark_color", mark_color);
text_edit->add_color_override("code_folding_color", code_folding_color);
text_edit->add_color_override("search_result_color", search_result_color);
@@ -479,6 +481,14 @@ void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) {
code_editor->goto_line_selection(p_line, p_begin, p_end);
}
+void ScriptTextEditor::set_executing_line(int p_line) {
+ code_editor->set_executing_line(p_line);
+}
+
+void ScriptTextEditor::clear_executing_line() {
+ code_editor->clear_executing_line();
+}
+
void ScriptTextEditor::ensure_focus() {
code_editor->get_text_edit()->grab_focus();
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 4edb1c3c67..0dbc884594 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -196,6 +196,8 @@ public:
virtual void goto_line(int p_line, bool p_with_error = false);
void goto_line_selection(int p_line, int p_begin, int p_end);
+ virtual void set_executing_line(int p_line);
+ virtual void clear_executing_line();
virtual void reload(bool p_soft);
virtual void get_breakpoints(List<int> *p_breakpoints);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index d39e521113..31660a9e19 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -85,6 +85,7 @@ void ShaderTextEditor::_load_theme_settings() {
Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color");
Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color");
Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color");
+ Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color");
Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color");
Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color");
Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color");
@@ -113,6 +114,7 @@ void ShaderTextEditor::_load_theme_settings() {
get_text_edit()->add_color_override("member_variable_color", member_variable_color);
get_text_edit()->add_color_override("mark_color", mark_color);
get_text_edit()->add_color_override("breakpoint_color", breakpoint_color);
+ get_text_edit()->add_color_override("executing_line_color", executing_line_color);
get_text_edit()->add_color_override("code_folding_color", code_folding_color);
get_text_edit()->add_color_override("search_result_color", search_result_color);
get_text_edit()->add_color_override("search_result_border_color", search_result_border_color);
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 47f00dc480..5a733f6509 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -2473,7 +2473,7 @@ void SpatialEditorViewport::_draw() {
real_t max_speed = camera->get_zfar();
real_t scale_length = (max_speed - min_speed);
- if (Math::abs(scale_length) > CMP_EPSILON) {
+ if (!Math::is_zero_approx(scale_length)) {
real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length);
// There is no real maximum speed so that factor can become negative,
@@ -2491,7 +2491,7 @@ void SpatialEditorViewport::_draw() {
real_t max_distance = camera->get_zfar();
real_t scale_length = (max_distance - min_distance);
- if (Math::abs(scale_length) > CMP_EPSILON) {
+ if (!Math::is_zero_approx(scale_length)) {
real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length);
// There is no real maximum distance so that factor can become negative,
@@ -4515,6 +4515,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
snap_selected_nodes_to_floor();
} break;
case MENU_LOCK_SELECTED: {
+ undo_redo->create_action(TTR("Lock Selected"));
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -4527,13 +4528,18 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
continue;
- spatial->set_meta("_edit_lock_", true);
- emit_signal("item_lock_status_changed");
+ undo_redo->add_do_method(spatial, "set_meta", "_edit_lock_", true);
+ undo_redo->add_undo_method(spatial, "remove_meta", "_edit_lock_");
+ undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- _refresh_menu_icons();
+ undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->commit_action();
} break;
case MENU_UNLOCK_SELECTED: {
+ undo_redo->create_action(TTR("Unlock Selected"));
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -4546,13 +4552,18 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
continue;
- spatial->set_meta("_edit_lock_", Variant());
- emit_signal("item_lock_status_changed");
+ undo_redo->add_do_method(spatial, "remove_meta", "_edit_lock_");
+ undo_redo->add_undo_method(spatial, "set_meta", "_edit_lock_", true);
+ undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- _refresh_menu_icons();
+ undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->commit_action();
} break;
case MENU_GROUP_SELECTED: {
+ undo_redo->create_action(TTR("Group Selected"));
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -4565,14 +4576,18 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
continue;
- spatial->set_meta("_edit_group_", true);
- emit_signal("item_group_status_changed");
+ undo_redo->add_do_method(spatial, "set_meta", "_edit_group_", true);
+ undo_redo->add_undo_method(spatial, "remove_meta", "_edit_group_");
+ undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- _refresh_menu_icons();
+ undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->commit_action();
} break;
case MENU_UNGROUP_SELECTED: {
-
+ undo_redo->create_action(TTR("Ungroup Selected"));
List<Node *> &selection = editor_selection->get_selected_node_list();
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
@@ -4584,11 +4599,15 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
continue;
- spatial->set_meta("_edit_group_", Variant());
- emit_signal("item_group_status_changed");
+ undo_redo->add_do_method(spatial, "remove_meta", "_edit_group_");
+ undo_redo->add_undo_method(spatial, "set_meta", "_edit_group_", true);
+ undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- _refresh_menu_icons();
+ undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->commit_action();
} break;
}
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index afe0b23fd9..6edd19901b 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -89,10 +89,10 @@ void SpriteFramesEditor::_sheet_preview_draw() {
if (frames_selected.size() == 0) {
split_sheet_dialog->get_ok()->set_disabled(true);
- split_sheet_dialog->get_ok()->set_text(TTR("No frames selected"));
+ split_sheet_dialog->get_ok()->set_text(TTR("No Frames Selected"));
} else {
split_sheet_dialog->get_ok()->set_disabled(false);
- split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d frame(s)"), frames_selected.size()));
+ split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d Frame(s)"), frames_selected.size()));
}
}
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
@@ -168,7 +168,24 @@ void SpriteFramesEditor::_sheet_add_frames() {
undo_redo->commit_action();
}
+void SpriteFramesEditor::_sheet_select_clear_all_frames() {
+
+ bool should_clear = true;
+ for (int i = 0; i < split_sheet_h->get_value() * split_sheet_v->get_value(); i++) {
+ if (!frames_selected.has(i)) {
+ frames_selected.insert(i);
+ should_clear = false;
+ }
+ }
+ if (should_clear) {
+ frames_selected.clear();
+ }
+
+ split_sheet_preview->update();
+}
+
void SpriteFramesEditor::_sheet_spin_changed(double) {
+
frames_selected.clear();
last_frame_selected = -1;
split_sheet_preview->update();
@@ -195,22 +212,26 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
void SpriteFramesEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
-
- load->set_icon(get_icon("Load", "EditorIcons"));
- load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons"));
- copy->set_icon(get_icon("ActionCopy", "EditorIcons"));
- paste->set_icon(get_icon("ActionPaste", "EditorIcons"));
- empty->set_icon(get_icon("InsertBefore", "EditorIcons"));
- empty2->set_icon(get_icon("InsertAfter", "EditorIcons"));
- move_up->set_icon(get_icon("MoveLeft", "EditorIcons"));
- move_down->set_icon(get_icon("MoveRight", "EditorIcons"));
- _delete->set_icon(get_icon("Remove", "EditorIcons"));
- new_anim->set_icon(get_icon("New", "EditorIcons"));
- remove_anim->set_icon(get_icon("Remove", "EditorIcons"));
- } else if (p_what == NOTIFICATION_READY) {
-
- add_constant_override("autohide", 1); // Fixes the dragger always showing up.
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ load->set_icon(get_icon("Load", "EditorIcons"));
+ load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons"));
+ copy->set_icon(get_icon("ActionCopy", "EditorIcons"));
+ paste->set_icon(get_icon("ActionPaste", "EditorIcons"));
+ empty->set_icon(get_icon("InsertBefore", "EditorIcons"));
+ empty2->set_icon(get_icon("InsertAfter", "EditorIcons"));
+ move_up->set_icon(get_icon("MoveLeft", "EditorIcons"));
+ move_down->set_icon(get_icon("MoveRight", "EditorIcons"));
+ _delete->set_icon(get_icon("Remove", "EditorIcons"));
+ new_anim->set_icon(get_icon("New", "EditorIcons"));
+ remove_anim->set_icon(get_icon("Remove", "EditorIcons"));
+ } // Fallthrough.
+ case NOTIFICATION_THEME_CHANGED: {
+ splite_sheet_scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
+ } break;
+ case NOTIFICATION_READY: {
+ add_constant_override("autohide", 1); // Fixes the dragger always showing up.
+ } break;
}
}
@@ -818,6 +839,7 @@ void SpriteFramesEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_sheet_preview_input"), &SpriteFramesEditor::_sheet_preview_input);
ClassDB::bind_method(D_METHOD("_sheet_spin_changed"), &SpriteFramesEditor::_sheet_spin_changed);
ClassDB::bind_method(D_METHOD("_sheet_add_frames"), &SpriteFramesEditor::_sheet_add_frames);
+ ClassDB::bind_method(D_METHOD("_sheet_select_clear_all_frames"), &SpriteFramesEditor::_sheet_select_clear_all_frames);
}
SpriteFramesEditor::SpriteFramesEditor() {
@@ -879,7 +901,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
hbc->add_child(load);
load_sheet = memnew(ToolButton);
- load_sheet->set_tooltip(TTR("Add frames from a Sprite Sheet"));
+ load_sheet->set_tooltip(TTR("Add Frames from a Sprite Sheet"));
hbc->add_child(load_sheet);
hbc->add_child(memnew(VSeparator));
@@ -960,25 +982,8 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_dialog->set_title(TTR("Select Frames"));
split_sheet_dialog->connect("confirmed", this, "_sheet_add_frames");
- ScrollContainer *scroll = memnew(ScrollContainer);
- split_sheet_preview = memnew(TextureRect);
- split_sheet_preview->set_expand(false);
- split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS);
- split_sheet_preview->connect("draw", this, "_sheet_preview_draw");
- split_sheet_preview->connect("gui_input", this, "_sheet_preview_input");
-
- scroll->set_enable_h_scroll(true);
- scroll->set_enable_v_scroll(true);
- CenterContainer *cc = memnew(CenterContainer);
- cc->add_child(split_sheet_preview);
- cc->set_h_size_flags(SIZE_EXPAND_FILL);
- cc->set_v_size_flags(SIZE_EXPAND_FILL);
- scroll->add_child(cc);
-
- split_sheet_vb->add_margin_child(TTR("Base Image:"), scroll, true);
-
HBoxContainer *split_sheet_hb = memnew(HBoxContainer);
- split_sheet_hb->add_spacer();
+
Label *ss_label = memnew(Label(TTR("Horizontal:")));
split_sheet_hb->add_child(ss_label);
split_sheet_h = memnew(SpinBox);
@@ -986,7 +991,6 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_h->set_max(128);
split_sheet_h->set_step(1);
split_sheet_hb->add_child(split_sheet_h);
- split_sheet_hb->add_spacer();
split_sheet_h->connect("value_changed", this, "_sheet_spin_changed");
ss_label = memnew(Label(TTR("Vertical:")));
@@ -996,13 +1000,37 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_v->set_max(128);
split_sheet_v->set_step(1);
split_sheet_hb->add_child(split_sheet_v);
- split_sheet_hb->add_spacer();
split_sheet_v->connect("value_changed", this, "_sheet_spin_changed");
- split_sheet_vb->add_margin_child(TTR("Split Settings:"), split_sheet_hb);
+ split_sheet_hb->add_spacer();
+
+ Button *select_clear_all = memnew(Button);
+ select_clear_all->set_text(TTR("Select/Clear All Frames"));
+ select_clear_all->connect("pressed", this, "_sheet_select_clear_all_frames");
+ split_sheet_hb->add_child(select_clear_all);
+
+ split_sheet_vb->add_child(split_sheet_hb);
+
+ split_sheet_preview = memnew(TextureRect);
+ split_sheet_preview->set_expand(false);
+ split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS);
+ split_sheet_preview->connect("draw", this, "_sheet_preview_draw");
+ split_sheet_preview->connect("gui_input", this, "_sheet_preview_input");
+
+ splite_sheet_scroll = memnew(ScrollContainer);
+ splite_sheet_scroll->set_enable_h_scroll(true);
+ splite_sheet_scroll->set_enable_v_scroll(true);
+ splite_sheet_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ CenterContainer *cc = memnew(CenterContainer);
+ cc->add_child(split_sheet_preview);
+ cc->set_h_size_flags(SIZE_EXPAND_FILL);
+ cc->set_v_size_flags(SIZE_EXPAND_FILL);
+ splite_sheet_scroll->add_child(cc);
+
+ split_sheet_vb->add_child(splite_sheet_scroll);
file_split_sheet = memnew(EditorFileDialog);
- file_split_sheet->set_title(TTR("Create frames from Sprite Sheet"));
+ file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet"));
file_split_sheet->set_mode(EditorFileDialog::MODE_OPEN_FILE);
add_child(file_split_sheet);
file_split_sheet->connect("file_selected", this, "_prepare_sprite_sheet");
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 383e99f87e..d64431cde7 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -74,6 +74,7 @@ class SpriteFramesEditor : public HSplitContainer {
StringName edited_anim;
ConfirmationDialog *split_sheet_dialog;
+ ScrollContainer *splite_sheet_scroll;
TextureRect *split_sheet_preview;
SpinBox *split_sheet_h;
SpinBox *split_sheet_v;
@@ -115,6 +116,7 @@ class SpriteFramesEditor : public HSplitContainer {
void _sheet_spin_changed(double);
void _sheet_preview_input(const Ref<InputEvent> &p_event);
void _sheet_add_frames();
+ void _sheet_select_clear_all_frames();
protected:
void _notification(int p_what);
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 2886b3dc51..becaae3567 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -94,6 +94,7 @@ void TextEditor::_load_theme_settings() {
Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color");
Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color");
Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color");
+ Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color");
Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color");
Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color");
Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color");
@@ -124,6 +125,7 @@ void TextEditor::_load_theme_settings() {
text_edit->add_color_override("function_color", function_color);
text_edit->add_color_override("member_variable_color", member_variable_color);
text_edit->add_color_override("breakpoint_color", breakpoint_color);
+ text_edit->add_color_override("executing_line_color", executing_line_color);
text_edit->add_color_override("mark_color", mark_color);
text_edit->add_color_override("code_folding_color", code_folding_color);
text_edit->add_color_override("search_result_color", search_result_color);
@@ -268,6 +270,15 @@ void TextEditor::goto_line(int p_line, bool p_with_error) {
code_editor->goto_line(p_line);
}
+void TextEditor::set_executing_line(int p_line) {
+
+ code_editor->set_executing_line(p_line);
+}
+
+void TextEditor::clear_executing_line() {
+ code_editor->clear_executing_line();
+}
+
void TextEditor::ensure_focus() {
code_editor->get_text_edit()->grab_focus();
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index 3c136277df..767001e2f6 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -123,6 +123,8 @@ public:
virtual Vector<String> get_functions();
virtual void get_breakpoints(List<int> *p_breakpoints);
virtual void goto_line(int p_line, bool p_with_error = false);
+ virtual void set_executing_line(int p_line);
+ virtual void clear_executing_line();
virtual void trim_trailing_whitespace();
virtual void convert_indent_to_spaces();
virtual void convert_indent_to_tabs();
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index f741040fa8..4e15bd5116 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -135,8 +135,7 @@ void TextureRegionEditor::_region_draw() {
Ref<Texture> select_handle = get_icon("EditorHandle", "EditorIcons");
- Rect2 scroll_rect(Point2(), mtx.basis_xform(base_tex->get_size()));
- scroll_rect.expand_to(mtx.basis_xform(edit_draw->get_size()));
+ Rect2 scroll_rect;
Vector2 endpoints[4] = {
mtx.basis_xform(rect.position),
@@ -167,7 +166,9 @@ void TextureRegionEditor::_region_draw() {
scroll_rect.expand_to(endpoints[i]);
}
- scroll_rect = scroll_rect.grow(200);
+ scroll_rect.position -= edit_draw->get_size();
+ scroll_rect.size += edit_draw->get_size() * 2.0;
+
updating_scroll = true;
hscroll->set_min(scroll_rect.position.x);
hscroll->set_max(scroll_rect.position.x + scroll_rect.size.x);
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index abb52f8359..29a54f815d 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -115,6 +115,9 @@ void TileMapEditor::_update_button_tool() {
default:
break;
}
+
+ if (tool != TOOL_PICKING)
+ last_tool = tool;
}
void TileMapEditor::_button_tool_select(int p_tool) {
@@ -237,22 +240,23 @@ void TileMapEditor::set_selected_tiles(Vector<int> p_tiles) {
palette->ensure_current_is_visible();
}
-void TileMapEditor::_create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) {
+Dictionary TileMapEditor::_create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord) {
+
+ Dictionary cell;
- Dictionary cell_old;
- Dictionary cell_new;
+ cell["id"] = tile;
+ cell["flip_h"] = flip_x;
+ cell["flip_y"] = flip_y;
+ cell["transpose"] = transpose;
+ cell["auto_coord"] = autotile_coord;
- cell_old["id"] = p_cell_old.idx;
- cell_old["flip_h"] = p_cell_old.xf;
- cell_old["flip_y"] = p_cell_old.yf;
- cell_old["transpose"] = p_cell_old.tr;
- cell_old["auto_coord"] = p_cell_old.ac;
+ return cell;
+}
- cell_new["id"] = p_cell_new.idx;
- cell_new["flip_h"] = p_cell_new.xf;
- cell_new["flip_y"] = p_cell_new.yf;
- cell_new["transpose"] = p_cell_new.tr;
- cell_new["auto_coord"] = p_cell_new.ac;
+void TileMapEditor::_create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) {
+
+ Dictionary cell_old = _create_cell_dictionary(p_cell_old.idx, p_cell_old.xf, p_cell_old.yf, p_cell_old.tr, p_cell_old.ac);
+ Dictionary cell_new = _create_cell_dictionary(p_cell_new.idx, p_cell_new.xf, p_cell_new.yf, p_cell_new.tr, p_cell_new.ac);
undo_redo->add_undo_method(node, "_set_celld", p_vec, cell_old);
undo_redo->add_do_method(node, "_set_celld", p_vec, cell_new);
@@ -268,7 +272,7 @@ void TileMapEditor::_finish_undo() {
if (undo_data.size()) {
for (Map<Point2i, CellOp>::Element *E = undo_data.front(); E; E = E->next()) {
- _create_set_cell_undo(E->key(), E->get(), _get_op_from_cell(E->key()));
+ _create_set_cell_undo_redo(E->key(), E->get(), _get_op_from_cell(E->key()));
}
undo_data.clear();
@@ -316,10 +320,7 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p
}
}
- Variant v_pos_x = p_pos.x, v_pos_y = p_pos.y, v_tile = p_value, v_flip_h = p_flip_h, v_flip_v = p_flip_v, v_transpose = p_transpose, v_autotile_coord = Vector2(p_autotile_coord.x, p_autotile_coord.y);
- const Variant *args[7] = { &v_pos_x, &v_pos_y, &v_tile, &v_flip_h, &v_flip_v, &v_transpose, &v_autotile_coord };
- Variant::CallError ce;
- node->call("set_cell", args, 7, ce);
+ node->_set_celld(p_pos, _create_cell_dictionary(p_value, p_flip_h, p_flip_v, p_transpose, p_autotile_coord));
if (manual_autotile || (p_value != -1 && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) {
if (current != -1) {
@@ -949,11 +950,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (mb->get_shift()) {
-#ifdef APPLE_STYLE_KEYS
if (mb->get_command())
-#else
- if (mb->get_control())
-#endif
tool = TOOL_RECTANGLE_PAINT;
else
tool = TOOL_LINE_PAINT;
@@ -964,11 +961,8 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_update_button_tool();
return true;
}
-#ifdef APPLE_STYLE_KEYS
+
if (mb->get_command()) {
-#else
- if (mb->get_control()) {
-#endif
tool = TOOL_PICKING;
_pick_tile(over_tile);
_update_button_tool();
@@ -1136,11 +1130,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_start_undo(TTR("Erase TileMap"));
if (mb->get_shift()) {
-#ifdef APPLE_STYLE_KEYS
if (mb->get_command())
-#else
- if (mb->get_control())
-#endif
tool = TOOL_RECTANGLE_ERASE;
else
tool = TOOL_LINE_ERASE;
@@ -1344,6 +1334,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (k.is_valid() && k->is_pressed()) {
+ if (last_tool == TOOL_NONE && tool == TOOL_PICKING && k->get_scancode() == KEY_SHIFT && k->get_command()) {
+ // trying to draw a rectangle with the painting tool, so change to the correct tool
+ tool = last_tool;
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+ _update_button_tool();
+ }
+
if (k->get_scancode() == KEY_ESCAPE) {
if (tool == TOOL_PASTING)
@@ -1448,8 +1446,30 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
- }
+ } else if (k.is_valid()) { // release event
+
+ if (tool == TOOL_NONE) {
+
+ if (k->get_scancode() == KEY_SHIFT && k->get_command()) {
+ tool = TOOL_PICKING;
+ _update_button_tool();
+ }
+ } else if (tool == TOOL_PICKING) {
+
+#ifdef APPLE_STYLE_KEYS
+ if (k->get_scancode() == KEY_META) {
+#else
+ if (k->get_scancode() == KEY_CONTROL) {
+#endif
+ // go back to that last tool if KEY_CONTROL was released
+ tool = last_tool;
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+ _update_button_tool();
+ }
+ }
+ }
return false;
}
@@ -1923,6 +1943,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
// Tools
paint_button = memnew(ToolButton);
paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P));
+ paint_button->set_tooltip(TTR("Shift+RMB: Line Draw\nShift+Ctrl+RMB: Rectangle Paint"));
paint_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_NONE));
paint_button->set_toggle_mode(true);
toolbar->add_child(paint_button);
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index 3bc10861f0..fcdada1111 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -105,6 +105,7 @@ class TileMapEditor : public VBoxContainer {
CheckBox *manual_button;
Tool tool;
+ Tool last_tool;
bool selection_active;
bool mouse_over;
@@ -192,9 +193,10 @@ class TileMapEditor : public VBoxContainer {
void _palette_selected(int index);
void _palette_multi_selected(int index, bool selected);
+ Dictionary _create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord);
void _start_undo(const String &p_action);
void _finish_undo();
- void _create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new);
+ void _create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new);
void _set_cell(const Point2i &p_pos, Vector<int> p_values, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, const Point2i p_autotile_coord = Point2());
void _canvas_mouse_enter();
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index e91b83bcd8..964303ba22 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -310,6 +310,21 @@ static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_
return style;
}
+void VisualShaderEditor::_update_created_node(GraphNode *node) {
+
+ if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
+ Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode");
+ Color c = sb->get_border_color();
+ Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
+ mono_color.a = 0.85;
+ c = mono_color;
+
+ node->add_color_override("title_color", c);
+ c.a = 0.7;
+ node->add_color_override("close_color", c);
+ }
+}
+
void VisualShaderEditor::_update_graph() {
if (updating)
@@ -374,6 +389,7 @@ void VisualShaderEditor::_update_graph() {
Ref<VisualShaderNodeUniform> uniform = vsnode;
if (uniform.is_valid()) {
graph->add_child(node);
+ _update_created_node(node);
LineEdit *uniform_name = memnew(LineEdit);
uniform_name->set_text(uniform->get_uniform_name());
@@ -529,18 +545,7 @@ void VisualShaderEditor::_update_graph() {
if (!uniform.is_valid()) {
graph->add_child(node);
- }
-
- if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode");
- Color c = sb->get_border_color();
- Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
- mono_color.a = 0.85;
- c = mono_color;
-
- node->add_color_override("title_color", c);
- c.a = 0.7;
- node->add_color_override("close_color", c);
+ _update_created_node(node);
}
}
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index a00f020ebd..35041da2bd 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -179,6 +179,7 @@ class VisualShaderEditor : public VBoxContainer {
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
bool _is_available(int p_flags);
+ void _update_created_node(GraphNode *node);
protected:
void _notification(int p_what);
diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp
index 09203a70a0..8dac5fa6b5 100644
--- a/editor/progress_dialog.cpp
+++ b/editor/progress_dialog.cpp
@@ -220,9 +220,8 @@ bool ProgressDialog::task_step(const String &p_task, const String &p_state, int
last_progress_tick = OS::get_singleton()->get_ticks_usec();
if (cancel_hb->is_visible()) {
OS::get_singleton()->force_process_input();
- } else {
- OS::get_singleton()->process_and_drop_events();
}
+
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
return cancelled;
}
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 095ec891cd..0a6e4c0607 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -798,7 +798,7 @@ public:
create_dir = memnew(Button);
pnhb->add_child(create_dir);
- create_dir->set_text(TTR("Create folder"));
+ create_dir->set_text(TTR("Create Folder"));
create_dir->connect("pressed", this, "_create_folder");
path_container = memnew(VBoxContainer);
@@ -1530,13 +1530,13 @@ void ProjectManager::_open_selected_projects_ask() {
// Check if the config_version property was empty or 0
if (config_version == 0) {
- ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You will not be able to open the project with previous versions of the engine anymore."), conf));
+ ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
ask_update_settings->popup_centered_minsize();
return;
}
// Check if we need to convert project settings from an earlier engine version
if (config_version < ProjectSettings::CONFIG_VERSION) {
- ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it?\nWarning: You will not be able to open the project with previous versions of the engine anymore."), conf));
+ ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it?\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
ask_update_settings->popup_centered_minsize();
return;
}
@@ -1557,7 +1557,7 @@ void ProjectManager::_run_project_confirm() {
const String &selected_main = E->get();
if (selected_main == "") {
- run_error_diag->set_text(TTR("Can't run project: no main scene defined.\nPlease edit the project and set the main scene in \"Project Settings\" under the \"Application\" category."));
+ run_error_diag->set_text(TTR("Can't run project: no main scene defined.\nPlease edit the project and set the main scene in the Project Settings under the \"Application\" category."));
run_error_diag->popup_centered();
return;
}
@@ -1597,7 +1597,7 @@ void ProjectManager::_run_project() {
}
if (selected_list.size() > 1) {
- multi_run_ask->set_text(TTR("Are you sure to run more than one project?"));
+ multi_run_ask->set_text(vformat(TTR("Are you sure to run %d projects at once?"), selected_list.size()));
multi_run_ask->popup_centered_minsize();
} else {
_run_project_confirm();
@@ -1705,7 +1705,14 @@ void ProjectManager::_erase_project() {
if (selected_list.size() == 0)
return;
- erase_ask->set_text(TTR("Remove project from the list? (Folder contents will not be modified)"));
+ String confirm_message;
+ if (selected_list.size() >= 2) {
+ confirm_message = vformat(TTR("Remove %d projects from the list?\nThe project folders' contents won't be modified."), selected_list.size());
+ } else {
+ confirm_message = TTR("Remove this project from the list?\nThe project folder's contents won't be modified.");
+ }
+
+ erase_ask->set_text(confirm_message);
erase_ask->popup_centered_minsize();
}
@@ -1716,7 +1723,7 @@ void ProjectManager::_language_selected(int p_id) {
language_btn->set_text(lang);
language_btn->set_icon(get_icon("Environment", "EditorIcons"));
- language_restart_ask->set_text(TTR("Language changed.\nThe UI will update next time the editor or project manager starts."));
+ language_restart_ask->set_text(TTR("Language changed.\nThe interface will update after restarting the editor or project manager."));
language_restart_ask->popup_centered();
}
@@ -1777,7 +1784,8 @@ void ProjectManager::_files_dropped(PoolStringArray p_files, int p_screen) {
if (confirm) {
multi_scan_ask->get_ok()->disconnect("pressed", this, "_scan_multiple_folders");
multi_scan_ask->get_ok()->connect("pressed", this, "_scan_multiple_folders", varray(folders));
- multi_scan_ask->set_text(vformat(TTR("You are about the scan %s folders for existing Godot projects. Do you confirm?"), folders.size()));
+ multi_scan_ask->set_text(
+ vformat(TTR("Are you sure to scan %s folders for existing Godot projects?\nThis could take a while."), folders.size()));
multi_scan_ask->popup_centered_minsize();
} else {
_scan_multiple_folders(folders);
@@ -2153,7 +2161,7 @@ ProjectManager::ProjectManager() {
gui_base->add_child(dialog_error);
open_templates = memnew(ConfirmationDialog);
- open_templates->set_text(TTR("You don't currently have any projects.\nWould you like to explore the official example projects in the Asset Library?"));
+ open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?"));
open_templates->get_ok()->set_text(TTR("Open Asset Library"));
open_templates->connect("confirmed", this, "_open_asset_library");
add_child(open_templates);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 2d7ad8bc04..f8f48d01ad 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -181,7 +181,7 @@ void ProjectSettingsEditor::_action_edited() {
ti->set_text(0, old_name);
add_at = "input/" + old_name;
- message->set_text(vformat(TTR("Action '%s' already exists!"), new_name));
+ message->set_text(vformat(TTR("An action with the name '%s' already exists."), new_name));
message->popup_centered(Size2(300, 100) * EDSCALE);
return;
}
@@ -927,7 +927,7 @@ void ProjectSettingsEditor::_action_check(String p_action) {
}
if (ProjectSettings::get_singleton()->has_setting("input/" + p_action)) {
- action_add_error->set_text(TTR("Already existing"));
+ action_add_error->set_text(vformat(TTR("An action with the name '%s' already exists."), p_action));
action_add_error->show();
action_add->set_disabled(true);
return;
@@ -1785,7 +1785,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
restart_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
restart_hb->add_child(restart_icon);
restart_label = memnew(Label);
- restart_label->set_text(TTR("Editor must be restarted for changes to take effect"));
+ restart_label->set_text(TTR("The editor must be restarted for changes to take effect."));
restart_hb->add_child(restart_label);
restart_hb->add_spacer();
Button *restart_button = memnew(Button);
@@ -2003,8 +2003,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
tvb->add_child(tmc);
translation_locale_filter_mode = memnew(OptionButton);
- translation_locale_filter_mode->add_item(TTR("Show all locales"), SHOW_ALL_LOCALES);
- translation_locale_filter_mode->add_item(TTR("Show only selected locales"), SHOW_ONLY_SELECTED_LOCALES);
+ translation_locale_filter_mode->add_item(TTR("Show All Locales"), SHOW_ALL_LOCALES);
+ translation_locale_filter_mode->add_item(TTR("Show Selected Locales Only"), SHOW_ONLY_SELECTED_LOCALES);
translation_locale_filter_mode->select(0);
tmc->add_margin_child(TTR("Filter mode:"), translation_locale_filter_mode);
translation_locale_filter_mode->connect("item_selected", this, "_translation_filter_mode_changed");
diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp
index c197248c35..dc2f098333 100644
--- a/editor/quick_open.cpp
+++ b/editor/quick_open.cpp
@@ -255,14 +255,19 @@ void EditorQuickOpen::_confirmed() {
void EditorQuickOpen::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
+ switch (p_what) {
- connect("confirmed", this, "_confirmed");
+ case NOTIFICATION_ENTER_TREE: {
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
- search_box->set_clear_button_enabled(true);
- } else if (p_what == NOTIFICATION_EXIT_TREE) {
- disconnect("confirmed", this, "_confirmed");
+ connect("confirmed", this, "_confirmed");
+
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ disconnect("confirmed", this, "_confirmed");
+ } break;
}
}
@@ -297,6 +302,7 @@ EditorQuickOpen::EditorQuickOpen() {
set_hide_on_ok(false);
search_options->connect("item_activated", this, "_confirmed");
search_options->set_hide_root(true);
+ search_options->add_constant_override("draw_guides", 1);
ei = "EditorIcons";
ot = "Object";
add_directories = false;
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index ed1eec95dc..858b14a733 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -113,7 +113,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
collapse_theme->set_icon("unchecked", "CheckBox", collapse_theme->get_icon("GuiTreeArrowRight", "EditorIcons"));
CheckBox *chk_collapse_features = memnew(CheckBox);
- chk_collapse_features->set_text(TTR("Advanced options"));
+ chk_collapse_features->set_text(TTR("Advanced Options"));
chk_collapse_features->set_theme(collapse_theme);
chk_collapse_features->set_focus_mode(FOCUS_NONE);
vbc->add_child(chk_collapse_features);
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 1dca542138..a41f10607b 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -2625,6 +2625,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
add_child(rename_dialog);
script_create_dialog = memnew(ScriptCreateDialog);
+ script_create_dialog->set_inheritance_base_type("Node");
add_child(script_create_dialog);
script_create_dialog->connect("script_created", this, "_script_created");
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 879d072b10..62845bfb9b 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -88,12 +88,18 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
}
undo_redo->commit_action();
} else if (p_id == BUTTON_LOCK) {
+ undo_redo->create_action(TTR("Unlock Node"));
if (n->is_class("CanvasItem") || n->is_class("Spatial")) {
- n->set_meta("_edit_lock_", Variant());
- _update_tree();
- emit_signal("node_changed");
+
+ undo_redo->add_do_method(n, "remove_meta", "_edit_lock_");
+ undo_redo->add_undo_method(n, "set_meta", "_edit_lock_", true);
+ undo_redo->add_do_method(this, "_update_tree", Variant());
+ undo_redo->add_undo_method(this, "_update_tree", Variant());
+ undo_redo->add_do_method(this, "emit_signal", "node_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "node_changed");
}
+ undo_redo->commit_action();
} else if (p_id == BUTTON_PIN) {
if (n->is_class("AnimationPlayer")) {
@@ -102,11 +108,18 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
}
} else if (p_id == BUTTON_GROUP) {
+ undo_redo->create_action(TTR("Button Group"));
+
if (n->is_class("CanvasItem") || n->is_class("Spatial")) {
- n->set_meta("_edit_group_", Variant());
- _update_tree();
- emit_signal("node_changed");
+
+ undo_redo->add_do_method(n, "remove_meta", "_edit_group_");
+ undo_redo->add_undo_method(n, "set_meta", "_edit_group_", true);
+ undo_redo->add_do_method(this, "_update_tree", Variant());
+ undo_redo->add_undo_method(this, "_update_tree", Variant());
+ undo_redo->add_do_method(this, "emit_signal", "node_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "node_changed");
}
+ undo_redo->commit_action();
} else if (p_id == BUTTON_WARNING) {
String config_err = n->get_configuration_warning();
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 5ab0efaee3..d76afcd2f4 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -34,6 +34,7 @@
#include "core/os/file_access.h"
#include "core/project_settings.h"
#include "core/script_language.h"
+#include "editor/create_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor_file_system.h"
@@ -45,6 +46,7 @@ void ScriptCreateDialog::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
path_button->set_icon(get_icon("Folder", "EditorIcons"));
parent_browse_button->set_icon(get_icon("Folder", "EditorIcons"));
+ parent_search_button->set_icon(get_icon("ClassList", "EditorIcons"));
status_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
} break;
}
@@ -77,6 +79,11 @@ void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_
_path_changed(file_path->get_text());
}
+void ScriptCreateDialog::set_inheritance_base_type(const String &p_base) {
+
+ base_type = p_base;
+}
+
bool ScriptCreateDialog::_validate(const String &p_string) {
if (p_string.length() == 0)
@@ -322,7 +329,7 @@ void ScriptCreateDialog::_browse_path(bool browse_parent, bool p_save) {
if (p_save) {
file_browse->set_mode(EditorFileDialog::MODE_SAVE_FILE);
- file_browse->set_title(TTR("Open Script/Choose Location"));
+ file_browse->set_title(TTR("Open Script / Choose Location"));
file_browse->get_ok()->set_text(TTR("Open"));
} else {
file_browse->set_mode(EditorFileDialog::MODE_OPEN_FILE);
@@ -362,6 +369,17 @@ void ScriptCreateDialog::_file_selected(const String &p_file) {
}
}
+void ScriptCreateDialog::_create() {
+
+ parent_name->set_text(select_class->get_selected_type());
+}
+
+void ScriptCreateDialog::_browse_class_in_tree() {
+
+ select_class->set_base_type(base_type);
+ select_class->popup_create(true);
+}
+
void ScriptCreateDialog::_path_changed(const String &p_path) {
is_path_valid = false;
@@ -369,27 +387,27 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
String p = p_path.strip_edges();
if (p == "") {
- _msg_path_valid(false, TTR("Path is empty"));
+ _msg_path_valid(false, TTR("Path is empty."));
_update_dialog();
return;
}
if (p.get_file().get_basename() == "") {
- _msg_path_valid(false, TTR("Filename is empty"));
+ _msg_path_valid(false, TTR("Filename is empty."));
_update_dialog();
return;
}
p = ProjectSettings::get_singleton()->localize_path(p);
if (!p.begins_with("res://")) {
- _msg_path_valid(false, TTR("Path is not local"));
+ _msg_path_valid(false, TTR("Path is not local."));
_update_dialog();
return;
}
DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (d->change_dir(p.get_base_dir()) != OK) {
- _msg_path_valid(false, TTR("Invalid base path"));
+ _msg_path_valid(false, TTR("Invalid base path."));
memdelete(d);
_update_dialog();
return;
@@ -402,11 +420,11 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
if (f->dir_exists(p)) {
is_new_script_created = false;
is_path_valid = false;
- _msg_path_valid(false, TTR("Directory of the same name exists"));
+ _msg_path_valid(false, TTR("A directory with the same name exists."));
} else if (f->file_exists(p)) {
is_new_script_created = false;
is_path_valid = true;
- _msg_path_valid(true, TTR("File exists, will be reused"));
+ _msg_path_valid(true, TTR("File exists, it will be reused."));
}
memdelete(f);
_update_dialog();
@@ -438,13 +456,13 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
}
if (!found) {
- _msg_path_valid(false, TTR("Invalid extension"));
+ _msg_path_valid(false, TTR("Invalid extension."));
_update_dialog();
return;
}
if (!match) {
- _msg_path_valid(false, TTR("Wrong extension chosen"));
+ _msg_path_valid(false, TTR("Wrong extension chosen."));
_update_dialog();
return;
}
@@ -496,20 +514,20 @@ void ScriptCreateDialog::_update_dialog() {
get_ok()->set_disabled(true);
if (!is_built_in) {
if (!is_path_valid) {
- _msg_script_valid(false, TTR("Invalid Path"));
+ _msg_script_valid(false, TTR("Invalid path."));
script_ok = false;
}
}
if (has_named_classes && (is_new_script_created && !is_class_name_valid)) {
- _msg_script_valid(false, TTR("Invalid class name"));
+ _msg_script_valid(false, TTR("Invalid class name."));
script_ok = false;
}
if (!is_parent_name_valid) {
- _msg_script_valid(false, TTR("Invalid inherited parent name or path"));
+ _msg_script_valid(false, TTR("Invalid inherited parent name or path."));
script_ok = false;
}
if (script_ok) {
- _msg_script_valid(true, TTR("Script valid"));
+ _msg_script_valid(true, TTR("Script is valid."));
get_ok()->set_disabled(false);
}
@@ -562,7 +580,7 @@ void ScriptCreateDialog::_update_dialog() {
parent_name->set_editable(true);
parent_browse_button->set_disabled(false);
internal->set_disabled(!_can_be_built_in());
- _msg_path_valid(true, TTR("Built-in script (into scene file)"));
+ _msg_path_valid(true, TTR("Built-in script (into scene file)."));
} else if (is_new_script_created) {
// New Script Created
get_ok()->set_text(TTR("Create"));
@@ -570,7 +588,7 @@ void ScriptCreateDialog::_update_dialog() {
parent_browse_button->set_disabled(false);
internal->set_disabled(!_can_be_built_in());
if (is_path_valid) {
- _msg_path_valid(true, TTR("Create new script file"));
+ _msg_path_valid(true, TTR("Will create a new script file."));
}
} else {
// Script Loaded
@@ -579,7 +597,7 @@ void ScriptCreateDialog::_update_dialog() {
parent_browse_button->set_disabled(true);
internal->set_disabled(!_can_be_built_in());
if (is_path_valid) {
- _msg_path_valid(true, TTR("Load existing script file"));
+ _msg_path_valid(true, TTR("Will load an existing script file."));
}
}
}
@@ -595,6 +613,8 @@ void ScriptCreateDialog::_bind_methods() {
ClassDB::bind_method("_path_changed", &ScriptCreateDialog::_path_changed);
ClassDB::bind_method("_path_entered", &ScriptCreateDialog::_path_entered);
ClassDB::bind_method("_template_changed", &ScriptCreateDialog::_template_changed);
+ ClassDB::bind_method("_create", &ScriptCreateDialog::_create);
+ ClassDB::bind_method("_browse_class_in_tree", &ScriptCreateDialog::_browse_class_in_tree);
ClassDB::bind_method(D_METHOD("config", "inherits", "path", "built_in_enabled"), &ScriptCreateDialog::config, DEFVAL(true));
@@ -707,12 +727,18 @@ ScriptCreateDialog::ScriptCreateDialog() {
/* Inherits */
+ base_type = "Object";
+
hb = memnew(HBoxContainer);
hb->set_h_size_flags(SIZE_EXPAND_FILL);
parent_name = memnew(LineEdit);
parent_name->connect("text_changed", this, "_parent_name_changed");
parent_name->set_h_size_flags(SIZE_EXPAND_FILL);
hb->add_child(parent_name);
+ parent_search_button = memnew(Button);
+ parent_search_button->set_flat(true);
+ parent_search_button->connect("pressed", this, "_browse_class_in_tree");
+ hb->add_child(parent_search_button);
parent_browse_button = memnew(Button);
parent_browse_button->set_flat(true);
parent_browse_button->connect("pressed", this, "_browse_path", varray(true, false));
@@ -777,6 +803,10 @@ ScriptCreateDialog::ScriptCreateDialog() {
/* Dialog Setup */
+ select_class = memnew(CreateDialog);
+ select_class->connect("create", this, "_create");
+ add_child(select_class);
+
file_browse = memnew(EditorFileDialog);
file_browse->connect("file_selected", this, "_file_selected");
file_browse->set_mode(EditorFileDialog::MODE_OPEN_FILE);
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index 15e838d69f..7473e77c29 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -40,6 +40,8 @@
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
+class CreateDialog;
+
class ScriptCreateDialog : public ConfirmationDialog {
GDCLASS(ScriptCreateDialog, ConfirmationDialog);
@@ -49,6 +51,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
PanelContainer *status_panel;
LineEdit *parent_name;
Button *parent_browse_button;
+ Button *parent_search_button;
OptionButton *language_menu;
OptionButton *template_menu;
LineEdit *file_path;
@@ -57,6 +60,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
CheckButton *internal;
VBoxContainer *path_vb;
AcceptDialog *alert;
+ CreateDialog *select_class;
bool path_valid;
bool create_new;
bool is_browsing_parent;
@@ -74,6 +78,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
bool re_check_path;
String script_template;
Vector<String> template_list;
+ String base_type;
bool _can_be_built_in();
void _path_changed(const String &p_path = String());
@@ -86,6 +91,8 @@ class ScriptCreateDialog : public ConfirmationDialog {
void _template_changed(int p_template = 0);
void _browse_path(bool browse_parent, bool p_save);
void _file_selected(const String &p_file);
+ void _create();
+ void _browse_class_in_tree();
virtual void ok_pressed();
void _create_new();
void _load_exist();
@@ -99,6 +106,7 @@ protected:
public:
void config(const String &p_base_name, const String &p_base_path, bool p_built_in_enabled = true);
+ void set_inheritance_base_type(const String &p_base);
ScriptCreateDialog();
};
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index 717d6bc8f6..1da8bf874c 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -209,8 +209,8 @@ void ScriptEditorDebugger::debug_next() {
Array msg;
msg.push_back("next");
ppeer->put_var(msg);
+ _clear_execution();
stack_dump->clear();
- inspector->edit(NULL);
}
void ScriptEditorDebugger::debug_step() {
@@ -221,8 +221,8 @@ void ScriptEditorDebugger::debug_step() {
Array msg;
msg.push_back("step");
ppeer->put_var(msg);
+ _clear_execution();
stack_dump->clear();
- inspector->edit(NULL);
}
void ScriptEditorDebugger::debug_break() {
@@ -245,6 +245,7 @@ void ScriptEditorDebugger::debug_continue() {
OS::get_singleton()->enable_for_stealing_focus(EditorNode::get_singleton()->get_child_process_id());
Array msg;
+ _clear_execution();
msg.push_back("continue");
ppeer->put_var(msg);
}
@@ -424,6 +425,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
} else if (p_msg == "debug_exit") {
breaked = false;
+ _clear_execution();
copy->set_disabled(true);
step->set_disabled(true);
next->set_disabled(true);
@@ -436,7 +438,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
emit_signal("breaked", false, false, Variant());
profiler->set_enabled(true);
profiler->disable_seeking();
- inspector->edit(NULL);
EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
} else if (p_msg == "message:click_ctrl") {
@@ -1273,6 +1274,18 @@ void ScriptEditorDebugger::_notification(int p_what) {
}
}
+void ScriptEditorDebugger::_clear_execution() {
+ TreeItem *ti = stack_dump->get_selected();
+ if (!ti)
+ return;
+
+ Dictionary d = ti->get_metadata(0);
+
+ stack_script = ResourceLoader::load(d["file"]);
+ emit_signal("clear_execution", stack_script);
+ stack_script.unref();
+}
+
void ScriptEditorDebugger::start() {
stop();
@@ -1313,6 +1326,7 @@ void ScriptEditorDebugger::stop() {
set_process(false);
breaked = false;
+ _clear_execution();
server->stop();
_clear_remote_objects();
@@ -1337,7 +1351,7 @@ void ScriptEditorDebugger::stop() {
profiler->set_enabled(true);
inspect_scene_tree->clear();
-
+ inspector->edit(NULL);
EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
EditorNode::get_singleton()->get_pause_button()->set_disabled(true);
EditorNode::get_singleton()->get_scene_tree_dock()->hide_remote_tree();
@@ -1393,6 +1407,7 @@ void ScriptEditorDebugger::_stack_dump_frame_selected() {
stack_script = ResourceLoader::load(d["file"]);
emit_signal("goto_script_line", stack_script, int(d["line"]) - 1);
+ emit_signal("set_execution", stack_script, int(d["line"]) - 1);
stack_script.unref();
if (connection.is_valid() && connection->is_connected_to_host()) {
@@ -1966,6 +1981,8 @@ void ScriptEditorDebugger::_bind_methods() {
ClassDB::bind_method(D_METHOD("_scene_tree_property_value_edited"), &ScriptEditorDebugger::_scene_tree_property_value_edited);
ADD_SIGNAL(MethodInfo("goto_script_line"));
+ ADD_SIGNAL(MethodInfo("set_execution", PropertyInfo("script"), PropertyInfo(Variant::INT, "line")));
+ ADD_SIGNAL(MethodInfo("clear_execution", PropertyInfo("script")));
ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug")));
ADD_SIGNAL(MethodInfo("show_debugger", PropertyInfo(Variant::BOOL, "reallydid")));
}
diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h
index 5f21602579..f7afe6bf72 100644
--- a/editor/script_editor_debugger.h
+++ b/editor/script_editor_debugger.h
@@ -205,6 +205,8 @@ class ScriptEditorDebugger : public Control {
void _export_csv();
+ void _clear_execution();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index d6756b2bb3..68a1117364 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -449,7 +449,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
restart_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
restart_hb->add_child(restart_icon);
restart_label = memnew(Label);
- restart_label->set_text(TTR("Editor must be restarted for changes to take effect"));
+ restart_label->set_text(TTR("The editor must be restarted for changes to take effect."));
restart_hb->add_child(restart_label);
restart_hb->add_spacer();
Button *restart_button = memnew(Button);
diff --git a/main/input_default.cpp b/main/input_default.cpp
index 6c3252ad1a..a939d77a1e 100644
--- a/main/input_default.cpp
+++ b/main/input_default.cpp
@@ -677,6 +677,19 @@ void InputDefault::set_use_accumulated_input(bool p_enable) {
use_accumulated_input = p_enable;
}
+void InputDefault::release_pressed_events() {
+
+ flush_accumulated_events(); // this is needed to release actions strengths
+
+ keys_pressed.clear();
+ joy_buttons_pressed.clear();
+ _joy_axis.clear();
+
+ for (Map<StringName, InputDefault::Action>::Element *E = action_state.front(); E; E = E->next()) {
+ action_release(E->key());
+ }
+}
+
InputDefault::InputDefault() {
use_accumulated_input = true;
diff --git a/main/input_default.h b/main/input_default.h
index f9b4cbbd57..80ee17656c 100644
--- a/main/input_default.h
+++ b/main/input_default.h
@@ -272,6 +272,7 @@ public:
virtual void flush_accumulated_events();
virtual void set_use_accumulated_input(bool p_enable);
+ virtual void release_pressed_events();
InputDefault();
};
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 44ea061f51..b21bdee052 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -279,14 +279,14 @@ PhysicsServer::AreaSpaceOverrideMode BulletPhysicsServer::area_get_space_overrid
return area->get_spOv_mode();
}
-void BulletPhysicsServer::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform) {
+void BulletPhysicsServer::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) {
AreaBullet *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
ShapeBullet *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- area->add_shape(shape, p_transform);
+ area->add_shape(shape, p_transform, p_disabled);
}
void BulletPhysicsServer::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
@@ -498,7 +498,7 @@ PhysicsServer::BodyMode BulletPhysicsServer::body_get_mode(RID p_body) const {
return body->get_mode();
}
-void BulletPhysicsServer::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform) {
+void BulletPhysicsServer::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) {
RigidBodyBullet *body = rigid_body_owner.get(p_body);
ERR_FAIL_COND(!body);
@@ -506,7 +506,7 @@ void BulletPhysicsServer::body_add_shape(RID p_body, RID p_shape, const Transfor
ShapeBullet *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- body->add_shape(shape, p_transform);
+ body->add_shape(shape, p_transform, p_disabled);
}
void BulletPhysicsServer::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 1b74cbf3fc..5bcb0d244b 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -133,7 +133,7 @@ public:
virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode);
virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform());
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform);
virtual int area_get_shape_count(RID p_area) const;
@@ -174,7 +174,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode);
virtual BodyMode body_get_mode(RID p_body) const;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform());
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
// Not supported, Please remove and add new shape
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform);
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index ef5f21fc21..3a90bdc6ae 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -216,8 +216,8 @@ RigidCollisionObjectBullet::~RigidCollisionObjectBullet() {
}
}
-void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform &p_transform) {
- shapes.push_back(ShapeWrapper(p_shape, p_transform, true));
+void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform &p_transform, bool p_disabled) {
+ shapes.push_back(ShapeWrapper(p_shape, p_transform, !p_disabled));
p_shape->add_owner(this);
reload_shapes();
}
@@ -299,6 +299,8 @@ Transform RigidCollisionObjectBullet::get_shape_transform(int p_index) const {
}
void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled) {
+ if (shapes[p_index].active != p_disabled)
+ return;
shapes.write[p_index].active = !p_disabled;
shape_changed(p_index);
}
diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h
index 2d4e5c4f1a..e65bc52caf 100644
--- a/modules/bullet/collision_object_bullet.h
+++ b/modules/bullet/collision_object_bullet.h
@@ -224,7 +224,7 @@ public:
_FORCE_INLINE_ btCollisionShape *get_main_shape() const { return mainShape; }
- void add_shape(ShapeBullet *p_shape, const Transform &p_transform = Transform());
+ void add_shape(ShapeBullet *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
void set_shape(int p_index, ShapeBullet *p_shape);
int get_shape_count() const;
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 0eb539b182..7e1cc937cd 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -242,7 +242,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_
//check if edge and poly share a vertex, of so, assign it to segment_idx
for (int i = 0; i < points.size(); i++) {
for (int j = 0; j < 2; j++) {
- if (segment[j].distance_to(points[i].point) < CMP_EPSILON) {
+ if (Math::is_zero_approx(segment[j].distance_to(points[i].point))) {
segment_idx[j] = i;
inserted_points.push_back(i);
break;
@@ -310,7 +310,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_
Vector2 edgeseg[2] = { points[edges[i].points[0]].point, points[edges[i].points[1]].point };
Vector2 closest = Geometry::get_closest_point_to_segment_2d(segment[j], edgeseg);
- if (closest.distance_to(segment[j]) < CMP_EPSILON) {
+ if (Math::is_zero_approx(closest.distance_to(segment[j]))) {
//point rest of this edge
res = closest;
found = true;
@@ -439,7 +439,7 @@ void CSGBrushOperation::BuildPoly::clip(const CSGBrush *p_brush, int p_face, Mes
//transform A points to 2D
- if (segment[0].distance_to(segment[1]) < CMP_EPSILON)
+ if (Math::is_zero_approx(segment[0].distance_to(segment[1])))
return; //too small
_clip_segment(p_brush, p_face, segment, mesh_merge, p_for_B);
@@ -461,10 +461,10 @@ void CSGBrushOperation::_collision_callback(const CSGBrush *A, int p_face_a, Map
{
//check if either is a degenerate
- if (va[0].distance_to(va[1]) < CMP_EPSILON || va[0].distance_to(va[2]) < CMP_EPSILON || va[1].distance_to(va[2]) < CMP_EPSILON)
+ if (Math::is_zero_approx(va[0].distance_to(va[1])) || Math::is_zero_approx(va[0].distance_to(va[2])) || Math::is_zero_approx(va[1].distance_to(va[2])))
return;
- if (vb[0].distance_to(vb[1]) < CMP_EPSILON || vb[0].distance_to(vb[2]) < CMP_EPSILON || vb[1].distance_to(vb[2]) < CMP_EPSILON)
+ if (Math::is_zero_approx(vb[0].distance_to(vb[1])) || Math::is_zero_approx(vb[0].distance_to(vb[2])) || Math::is_zero_approx(vb[1].distance_to(vb[2])))
return;
}
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.cpp b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
index 8c602e0cba..eac8e26160 100644
--- a/modules/gdnative/arvr/arvr_interface_gdnative.cpp
+++ b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
@@ -222,6 +222,15 @@ void ARVRInterfaceGDNative::process() {
interface->process(data);
}
+void ARVRInterfaceGDNative::notification(int p_what) {
+ ERR_FAIL_COND(interface == NULL);
+
+ // this is only available in interfaces that implement 1.1 or later
+ if ((interface->version.major > 1) || ((interface->version.major == 1) && (interface->version.minor > 0))) {
+ interface->notification(p_what);
+ }
+}
+
/////////////////////////////////////////////////////////////////////////////////////
// some helper callbacks
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.h b/modules/gdnative/arvr/arvr_interface_gdnative.h
index 3f966ece51..86396b067a 100644
--- a/modules/gdnative/arvr/arvr_interface_gdnative.h
+++ b/modules/gdnative/arvr/arvr_interface_gdnative.h
@@ -82,6 +82,7 @@ public:
virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
virtual void process();
+ virtual void notification(int p_what);
};
#endif // ARVR_INTERFACE_GDNATIVE_H
diff --git a/modules/gdnative/include/arvr/godot_arvr.h b/modules/gdnative/include/arvr/godot_arvr.h
index 321b471d0e..60bad27618 100644
--- a/modules/gdnative/include/arvr/godot_arvr.h
+++ b/modules/gdnative/include/arvr/godot_arvr.h
@@ -63,6 +63,7 @@ typedef struct {
void (*process)(void *);
// only in 1.1 onwards
godot_int (*get_external_texture_for_eye)(void *, godot_int);
+ void (*notification)(godot_int);
} godot_arvr_interface_gdnative;
void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface);
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 4577c7327a..e0cf990f83 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -139,6 +139,34 @@ static String get_type_name(const PropertyInfo &info) {
}
/*
+ * Some comparison helper functions we need
+ */
+
+struct MethodInfoComparator {
+ StringName::AlphCompare compare;
+ bool operator()(const MethodInfo &p_a, const MethodInfo &p_b) const {
+
+ return compare(p_a.name, p_b.name);
+ }
+};
+
+struct PropertyInfoComparator {
+ StringName::AlphCompare compare;
+ bool operator()(const PropertyInfo &p_a, const PropertyInfo &p_b) const {
+
+ return compare(p_a.name, p_b.name);
+ }
+};
+
+struct ConstantAPIComparator {
+ NoCaseComparator compare;
+ bool operator()(const ConstantAPI &p_a, const ConstantAPI &p_b) const {
+
+ return compare(p_a.constant_name, p_b.constant_name);
+ }
+};
+
+/*
* Reads the entire Godot API to a list
*/
List<ClassAPI> generate_c_api_classes() {
@@ -147,6 +175,7 @@ List<ClassAPI> generate_c_api_classes() {
List<StringName> classes;
ClassDB::get_class_list(&classes);
+ classes.sort_custom<StringName::AlphCompare>();
// Register global constants as a fake GlobalConstants singleton class
{
@@ -162,6 +191,7 @@ List<ClassAPI> generate_c_api_classes() {
constant_api.constant_value = GlobalConstants::get_global_constant_value(i);
global_constants_api.constants.push_back(constant_api);
}
+ global_constants_api.constants.sort_custom<ConstantAPIComparator>();
api.push_back(global_constants_api);
}
@@ -193,6 +223,7 @@ List<ClassAPI> generate_c_api_classes() {
{
List<String> constant;
ClassDB::get_integer_constant_list(class_name, &constant, true);
+ constant.sort_custom<NoCaseComparator>();
for (List<String>::Element *c = constant.front(); c != NULL; c = c->next()) {
ConstantAPI constant_api;
constant_api.constant_name = c->get();
@@ -206,6 +237,7 @@ List<ClassAPI> generate_c_api_classes() {
{
List<MethodInfo> signals_;
ClassDB::get_signal_list(class_name, &signals_, true);
+ signals_.sort_custom<MethodInfoComparator>();
for (int i = 0; i < signals_.size(); i++) {
SignalAPI signal;
@@ -245,6 +277,7 @@ List<ClassAPI> generate_c_api_classes() {
{
List<PropertyInfo> properties;
ClassDB::get_property_list(class_name, &properties, true);
+ properties.sort_custom<PropertyInfoComparator>();
for (List<PropertyInfo>::Element *p = properties.front(); p != NULL; p = p->next()) {
PropertyAPI property_api;
@@ -272,6 +305,7 @@ List<ClassAPI> generate_c_api_classes() {
{
List<MethodInfo> methods;
ClassDB::get_method_list(class_name, &methods, true);
+ methods.sort_custom<MethodInfoComparator>();
for (List<MethodInfo>::Element *m = methods.front(); m != NULL; m = m->next()) {
MethodAPI method_api;
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 4fd136d5cc..7552bc6bff 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -68,6 +68,8 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"exp",
"is_nan",
"is_inf",
+ "is_equal_approx",
+ "is_zero_approx",
"ease",
"decimals",
"stepify",
@@ -316,6 +318,17 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(0);
r_ret = Math::is_inf((double)*p_args[0]);
} break;
+ case MATH_ISEQUALAPPROX: {
+ VALIDATE_ARG_COUNT(2);
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ r_ret = Math::is_equal_approx((real_t)*p_args[0], (real_t)*p_args[1]);
+ } break;
+ case MATH_ISZEROAPPROX: {
+ VALIDATE_ARG_COUNT(1);
+ VALIDATE_ARG_NUM(0);
+ r_ret = Math::is_zero_approx((real_t)*p_args[0]);
+ } break;
case MATH_EASE: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
@@ -1596,6 +1609,16 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
mi.return_val.type = Variant::BOOL;
return mi;
} break;
+ case MATH_ISEQUALAPPROX: {
+ MethodInfo mi("is_equal_approx", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b"));
+ mi.return_val.type = Variant::BOOL;
+ return mi;
+ } break;
+ case MATH_ISZEROAPPROX: {
+ MethodInfo mi("is_zero_approx", PropertyInfo(Variant::REAL, "s"));
+ mi.return_val.type = Variant::BOOL;
+ return mi;
+ } break;
case MATH_EASE: {
MethodInfo mi("ease", PropertyInfo(Variant::REAL, "s"), PropertyInfo(Variant::REAL, "curve"));
mi.return_val.type = Variant::REAL;
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h
index 14bf3d7560..0dbd172acf 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_functions.h
@@ -59,6 +59,8 @@ public:
MATH_EXP,
MATH_ISNAN,
MATH_ISINF,
+ MATH_ISEQUALAPPROX,
+ MATH_ISZEROAPPROX,
MATH_EASE,
MATH_DECIMALS,
MATH_STEPIFY,
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index dc7ed03548..fe107d3683 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -440,6 +440,12 @@ void MobileVRInterface::process() {
};
};
+void MobileVRInterface::notification(int p_what){
+ _THREAD_SAFE_METHOD_
+
+ // nothing to do here, I guess we could pauze our sensors...
+}
+
MobileVRInterface::MobileVRInterface() {
initialized = false;
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index e595daf16e..7fa51eecb7 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -142,6 +142,7 @@ public:
virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
virtual void process();
+ virtual void notification(int p_what);
MobileVRInterface();
~MobileVRInterface();
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 3c9644127c..27e579935f 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -131,14 +131,6 @@ void CSharpLanguage::finish() {
finalizing = true;
-#ifdef TOOLS_ENABLED
- // Must be here, to avoid StringName leaks
- if (BindingsGenerator::singleton) {
- memdelete(BindingsGenerator::singleton);
- BindingsGenerator::singleton = NULL;
- }
-#endif
-
// Make sure all script binding gchandles are released before finalizing GDMono
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
CSharpScriptBinding &script_binding = E->value();
@@ -919,7 +911,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
#endif
-void CSharpLanguage::project_assembly_loaded() {
+void CSharpLanguage::_load_scripts_metadata() {
scripts_metadata.clear();
@@ -953,6 +945,7 @@ void CSharpLanguage::project_assembly_loaded() {
}
scripts_metadata = old_dict_var.operator Dictionary();
+ scripts_metadata_invalidated = false;
print_verbose("Successfully loaded scripts metadata");
} else {
@@ -1024,11 +1017,13 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) {
}
}
-void CSharpLanguage::_uninitialize_script_bindings() {
+void CSharpLanguage::_on_scripts_domain_unloaded() {
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
CSharpScriptBinding &script_binding = E->value();
script_binding.inited = false;
}
+
+ scripts_metadata_invalidated = true;
}
void CSharpLanguage::set_language_index(int p_idx) {
@@ -1086,6 +1081,8 @@ CSharpLanguage::CSharpLanguage() {
#endif
lang_idx = -1;
+
+ scripts_metadata_invalidated = true;
}
CSharpLanguage::~CSharpLanguage() {
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 050527d52b..fe4eed2e24 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -309,14 +309,17 @@ class CSharpLanguage : public ScriptLanguage {
int lang_idx;
Dictionary scripts_metadata;
+ bool scripts_metadata_invalidated;
// For debug_break and debug_break_parse
int _debug_parse_err_line;
String _debug_parse_err_file;
String _debug_error;
+ void _load_scripts_metadata();
+
friend class GDMono;
- void _uninitialize_script_bindings();
+ void _on_scripts_domain_unloaded();
public:
StringNameCache string_names;
@@ -341,9 +344,15 @@ public:
void reload_assemblies(bool p_soft_reload);
#endif
- void project_assembly_loaded();
+ _FORCE_INLINE_ Dictionary get_scripts_metadata_or_nothing() {
+ return scripts_metadata_invalidated ? Dictionary() : scripts_metadata;
+ }
- _FORCE_INLINE_ const Dictionary &get_scripts_metadata() { return scripts_metadata; }
+ _FORCE_INLINE_ const Dictionary &get_scripts_metadata() {
+ if (scripts_metadata_invalidated)
+ _load_scripts_metadata();
+ return scripts_metadata;
+ }
virtual String get_name() const;
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 259c0ffece..a408716641 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -97,14 +97,10 @@
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
-#define BINDINGS_GENERATOR_VERSION UINT32_C(8)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(9)
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
-bool BindingsGenerator::verbose_output = false;
-
-BindingsGenerator *BindingsGenerator::singleton = NULL;
-
static String fix_doc_description(const String &p_bbcode) {
// This seems to be the correct way to do this. It's the same EditorHelp does.
@@ -816,9 +812,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
CRASH_COND(enum_class_name != "Variant"); // Hard-coded...
- if (verbose_output) {
- WARN_PRINTS("Declaring global enum `" + enum_proxy_name + "` inside static class `" + enum_class_name + "`");
- }
+ _log("Declaring global enum `%s` inside static class `%s`\n", enum_proxy_name.utf8().get_data(), enum_class_name.utf8().get_data());
p_output.append("\n" INDENT1 "public static partial class ");
p_output.append(enum_class_name);
@@ -867,9 +861,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append("\n#pragma warning restore CS1591\n");
}
-Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
-
- verbose_output = p_verbose_output;
+Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution) {
String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME);
@@ -1001,15 +993,12 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info);
- if (verbose_output)
- OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n");
+ _log("The solution and C# project for the Core API was generated successfully\n");
return OK;
}
-Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
-
- verbose_output = p_verbose_output;
+Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution) {
String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
@@ -1100,13 +1089,12 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir
r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info);
- if (verbose_output)
- OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n");
+ _log("The solution and C# project for the Editor API was generated successfully\n");
return OK;
}
-Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verbose_output) {
+Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
@@ -1123,13 +1111,13 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verb
Error proj_err;
- proj_err = generate_cs_core_project(p_output_dir, solution, p_verbose_output);
+ proj_err = generate_cs_core_project(p_output_dir, solution);
if (proj_err != OK) {
ERR_PRINT("Generation of the Core API C# project failed");
return proj_err;
}
- proj_err = generate_cs_editor_project(p_output_dir, solution, p_verbose_output);
+ proj_err = generate_cs_editor_project(p_output_dir, solution);
if (proj_err != OK) {
ERR_PRINT("Generation of the Editor API C# project failed");
return proj_err;
@@ -1168,8 +1156,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
- if (verbose_output)
- OS::get_singleton()->print("Generating %s.cs...\n", itype.proxy_name.utf8().get_data());
+ _log("Generating %s.cs...\n", itype.proxy_name.utf8().get_data());
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
@@ -1477,7 +1464,13 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append("\n" INDENT2 OPEN_BLOCK);
if (getter) {
- p_output.append(INDENT3 "get\n" OPEN_BLOCK_L3);
+ p_output.append(INDENT3 "get\n"
+
+ // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
+ "#pragma warning disable CS0618 // Disable warning about obsolete method\n"
+
+ OPEN_BLOCK_L3);
+
p_output.append("return ");
p_output.append(getter->proxy_name + "(");
if (p_iprop.index != -1) {
@@ -1491,11 +1484,22 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(itos(p_iprop.index));
}
}
- p_output.append(");\n" CLOSE_BLOCK_L3);
+ p_output.append(");\n"
+
+ CLOSE_BLOCK_L3
+
+ // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
+ "#pragma warning restore CS0618\n");
}
if (setter) {
- p_output.append(INDENT3 "set\n" OPEN_BLOCK_L3);
+ p_output.append(INDENT3 "set\n"
+
+ // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
+ "#pragma warning disable CS0618 // Disable warning about obsolete method\n"
+
+ OPEN_BLOCK_L3);
+
p_output.append(setter->proxy_name + "(");
if (p_iprop.index != -1) {
const ArgumentInterface &idx_arg = setter->arguments.front()->get();
@@ -1508,7 +1512,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(itos(p_iprop.index) + ", ");
}
}
- p_output.append("value);\n" CLOSE_BLOCK_L3);
+ p_output.append("value);\n"
+
+ CLOSE_BLOCK_L3
+
+ // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
+ "#pragma warning restore CS0618\n");
}
p_output.append(CLOSE_BLOCK_L2);
@@ -1636,6 +1645,15 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append("\")]");
}
+ if (p_imethod.is_deprecated) {
+ if (p_imethod.deprecation_message.empty())
+ WARN_PRINTS("An empty deprecation message is discouraged. Method: " + p_imethod.proxy_name);
+
+ p_output.append(MEMBER_BEGIN "[Obsolete(\"");
+ p_output.append(p_imethod.deprecation_message);
+ p_output.append("\")]");
+ }
+
p_output.append(MEMBER_BEGIN);
p_output.append(p_imethod.is_internal ? "internal " : "public ");
@@ -1710,8 +1728,6 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
Error BindingsGenerator::generate_glue(const String &p_output_dir) {
- verbose_output = true;
-
bool dir_exists = DirAccess::exists(p_output_dir);
ERR_EXPLAIN("The output directory does not exist.");
ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
@@ -2109,6 +2125,58 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol
return &placeholder_types.insert(placeholder.cname, placeholder)->get();
}
+StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta) {
+
+ switch (p_meta) {
+ case GodotTypeInfo::METADATA_INT_IS_INT8:
+ return "sbyte";
+ break;
+ case GodotTypeInfo::METADATA_INT_IS_INT16:
+ return "short";
+ break;
+ case GodotTypeInfo::METADATA_INT_IS_INT32:
+ return "int";
+ break;
+ case GodotTypeInfo::METADATA_INT_IS_INT64:
+ return "long";
+ break;
+ case GodotTypeInfo::METADATA_INT_IS_UINT8:
+ return "byte";
+ break;
+ case GodotTypeInfo::METADATA_INT_IS_UINT16:
+ return "ushort";
+ break;
+ case GodotTypeInfo::METADATA_INT_IS_UINT32:
+ return "uint";
+ break;
+ case GodotTypeInfo::METADATA_INT_IS_UINT64:
+ return "ulong";
+ break;
+ default:
+ // Assume INT32
+ return "int";
+ }
+}
+
+StringName BindingsGenerator::_get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta) {
+
+ switch (p_meta) {
+ case GodotTypeInfo::METADATA_REAL_IS_FLOAT:
+ return "float";
+ break;
+ case GodotTypeInfo::METADATA_REAL_IS_DOUBLE:
+ return "double";
+ break;
+ default:
+ // Assume real_t (float or double depending of REAL_T_IS_DOUBLE)
+#ifdef REAL_T_IS_DOUBLE
+ return "double";
+#else
+ return "float";
+#endif
+ }
+}
+
void BindingsGenerator::_populate_object_type_interfaces() {
obj_types.clear();
@@ -2128,15 +2196,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
}
if (!ClassDB::is_class_exposed(type_cname)) {
- if (verbose_output)
- WARN_PRINTS("Ignoring type " + type_cname.operator String() + " because it's not exposed");
+ _log("Ignoring type `%s` because it's not exposed\n", String(type_cname).utf8().get_data());
class_list.pop_front();
continue;
}
if (!ClassDB::is_class_enabled(type_cname)) {
- if (verbose_output)
- WARN_PRINTS("Ignoring type " + type_cname.operator String() + " because it's not enabled");
+ _log("Ignoring type `%s` because it's not enabled\n", String(type_cname).utf8().get_data());
class_list.pop_front();
continue;
}
@@ -2164,10 +2230,12 @@ void BindingsGenerator::_populate_object_type_interfaces() {
itype.im_type_in = "IntPtr";
itype.im_type_out = itype.proxy_name;
+ // Populate properties
+
List<PropertyInfo> property_list;
ClassDB::get_property_list(type_cname, &property_list, true);
- // Populate properties
+ Map<StringName, StringName> accessor_methods;
for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
const PropertyInfo &property = E->get();
@@ -2180,18 +2248,21 @@ void BindingsGenerator::_populate_object_type_interfaces() {
iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname);
iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname);
+ if (iprop.setter != StringName())
+ accessor_methods[iprop.setter] = iprop.cname;
+ if (iprop.getter != StringName())
+ accessor_methods[iprop.getter] = iprop.cname;
+
bool valid = false;
iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid);
ERR_FAIL_COND(!valid);
iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
- // Prevent property and enclosing type from sharing the same name
+ // Prevent the property and its enclosing type from sharing the same name
if (iprop.proxy_name == itype.proxy_name) {
- if (verbose_output) {
- WARN_PRINTS("Name of property `" + iprop.proxy_name + "` is ambiguous with the name of its class `" +
- itype.proxy_name + "`. Renaming property to `" + iprop.proxy_name + "_`");
- }
+ _log("Name of property `%s` is ambiguous with the name of its enclosing class `%s`. Renaming property to `%s_`\n",
+ iprop.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), iprop.proxy_name.utf8().get_data());
iprop.proxy_name += "_";
}
@@ -2258,14 +2329,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
// which could actually will return something different.
// Let's put this to notify us if that ever happens.
if (itype.cname != name_cache.type_Object || imethod.name != "free") {
- if (verbose_output) {
- WARN_PRINTS("Notification: New unexpected virtual non-overridable method found.\n"
- "We only expected Object.free, but found " +
- itype.name + "." + imethod.name);
- }
+ ERR_PRINTS("Notification: New unexpected virtual non-overridable method found.\n"
+ "We only expected Object.free, but found " +
+ itype.name + "." + imethod.name);
}
} else {
- ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
+ ERR_EXPLAIN("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
+ ERR_FAIL();
}
} else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
imethod.return_type.cname = return_info.class_name;
@@ -2279,7 +2349,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
} else if (return_info.type == Variant::NIL) {
imethod.return_type.cname = name_cache.type_void;
} else {
- imethod.return_type.cname = Variant::get_type_name(return_info.type);
+ if (return_info.type == Variant::INT) {
+ imethod.return_type.cname = _get_int_type_name_from_meta(m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE);
+ } else if (return_info.type == Variant::REAL) {
+ imethod.return_type.cname = _get_float_type_name_from_meta(m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE);
+ } else {
+ imethod.return_type.cname = Variant::get_type_name(return_info.type);
+ }
}
for (int i = 0; i < argc; i++) {
@@ -2298,7 +2374,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.type == Variant::NIL) {
iarg.type.cname = name_cache.type_Variant;
} else {
- iarg.type.cname = Variant::get_type_name(arginfo.type);
+ if (arginfo.type == Variant::INT) {
+ iarg.type.cname = _get_int_type_name_from_meta(m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE);
+ } else if (arginfo.type == Variant::REAL) {
+ iarg.type.cname = _get_float_type_name_from_meta(m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE);
+ } else {
+ iarg.type.cname = Variant::get_type_name(arginfo.type);
+ }
}
iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
@@ -2319,16 +2401,24 @@ void BindingsGenerator::_populate_object_type_interfaces() {
imethod.proxy_name = escape_csharp_keyword(snake_to_pascal_case(imethod.name));
- // Prevent naming the property and its enclosing type from sharing the same name
+ // Prevent the method and its enclosing type from sharing the same name
if (imethod.proxy_name == itype.proxy_name) {
- if (verbose_output) {
- WARN_PRINTS("Name of method `" + imethod.proxy_name + "` is ambiguous with the name of its class `" +
- itype.proxy_name + "`. Renaming method to `" + imethod.proxy_name + "_`");
- }
+ _log("Name of method `%s` is ambiguous with the name of its enclosing class `%s`. Renaming method to `%s_`\n",
+ imethod.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), imethod.proxy_name.utf8().get_data());
imethod.proxy_name += "_";
}
+ Map<StringName, StringName>::Element *accessor = accessor_methods.find(imethod.cname);
+ if (accessor) {
+ const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value());
+
+ // We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also
+ // we don't know if an accessor method in a different class could have other purposes, so better leave those untouched.
+ imethod.is_deprecated = true;
+ imethod.deprecation_message = imethod.proxy_name + " is deprecated. Use the " + accessor_property->proxy_name + " property instead.";
+ }
+
if (itype.class_doc) {
for (int i = 0; i < itype.class_doc->methods.size(); i++) {
if (itype.class_doc->methods[i].name == imethod.name) {
@@ -2556,7 +2646,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// bool
itype = TypeInterface::create_value_type(String("bool"));
-
{
// MonoBoolean <---> bool
itype.c_in = "\t%0 %1_in = (%0)%1;\n";
@@ -2570,45 +2659,73 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_out = itype.name;
builtin_types.insert(itype.cname, itype);
- // int
- // C interface is the same as that of enums. Remember to apply any
- // changes done here to TypeInterface::postsetup_enum_type as well
- itype = TypeInterface::create_value_type(String("int"));
- itype.c_arg_in = "&%s_in";
+ // Integer types
{
- // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "int64_t";
+ // C interface for 'uint32_t' is the same as that of enums. Remember to apply
+ // any of the changes done here to 'TypeInterface::postsetup_enum_type' as well.
+#define INSERT_INT_TYPE(m_name, m_c_type_in_out, m_c_type) \
+ { \
+ itype = TypeInterface::create_value_type(String(m_name)); \
+ { \
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n"; \
+ itype.c_out = "\treturn (%0)%1;\n"; \
+ itype.c_type = #m_c_type; \
+ itype.c_arg_in = "&%s_in"; \
+ } \
+ itype.c_type_in = #m_c_type_in_out; \
+ itype.c_type_out = itype.c_type_in; \
+ itype.im_type_in = itype.name; \
+ itype.im_type_out = itype.name; \
+ builtin_types.insert(itype.cname, itype); \
}
- itype.c_type_in = "int32_t";
- itype.c_type_out = itype.c_type_in;
- itype.im_type_in = itype.name;
- itype.im_type_out = itype.name;
- builtin_types.insert(itype.cname, itype);
- // real_t
- itype = TypeInterface();
- itype.name = "float"; // The name is always "float" in Variant, even with REAL_T_IS_DOUBLE.
- itype.cname = itype.name;
-#ifdef REAL_T_IS_DOUBLE
- itype.proxy_name = "double";
-#else
- itype.proxy_name = "float";
-#endif
+ // The expected type for all integers in ptrcall is 'int64_t', so that's what we use for 'c_type'
+
+ INSERT_INT_TYPE("sbyte", int8_t, int64_t);
+ INSERT_INT_TYPE("short", int16_t, int64_t);
+ INSERT_INT_TYPE("int", int32_t, int64_t);
+ INSERT_INT_TYPE("long", int64_t, int64_t);
+ INSERT_INT_TYPE("byte", uint8_t, int64_t);
+ INSERT_INT_TYPE("ushort", uint16_t, int64_t);
+ INSERT_INT_TYPE("uint", uint32_t, int64_t);
+ INSERT_INT_TYPE("ulong", uint64_t, int64_t);
+ }
+
+ // Floating point types
{
- // The expected type for parameters and return value in ptrcall is 'double'.
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
+ // float
+ itype = TypeInterface();
+ itype.name = "float";
+ itype.cname = itype.name;
+ itype.proxy_name = "float";
+ {
+ // The expected type for 'float' in ptrcall is 'double'
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "double";
+ itype.c_type_in = "float";
+ itype.c_type_out = "float";
+ itype.c_arg_in = "&%s_in";
+ }
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
+ builtin_types.insert(itype.cname, itype);
+
+ // double
+ itype = TypeInterface();
+ itype.name = "double";
+ itype.cname = itype.name;
+ itype.proxy_name = "double";
itype.c_type = "double";
- itype.c_type_in = "real_t";
- itype.c_type_out = "real_t";
- itype.c_arg_in = "&%s_in";
+ itype.c_type_in = "double";
+ itype.c_type_out = "double";
+ itype.c_arg_in = "&%s";
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
+ builtin_types.insert(itype.cname, itype);
}
- itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
- builtin_types.insert(itype.cname, itype);
// String
itype = TypeInterface();
@@ -2858,7 +2975,18 @@ void BindingsGenerator::_populate_global_constants() {
}
}
-void BindingsGenerator::initialize() {
+void BindingsGenerator::_log(const char *p_format, ...) {
+
+ if (log_print_enabled) {
+ va_list list;
+
+ va_start(list, p_format);
+ OS::get_singleton()->print("%s", str_format(p_format, list).utf8().get_data());
+ va_end(list);
+ }
+}
+
+void BindingsGenerator::_initialize() {
EditorHelp::generate_doc();
@@ -2881,12 +3009,13 @@ void BindingsGenerator::initialize() {
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
const int NUM_OPTIONS = 2;
- int options_left = NUM_OPTIONS;
-
String mono_glue_option = "--generate-mono-glue";
String cs_api_option = "--generate-cs-api";
- verbose_output = true;
+ String mono_glue_path;
+ String cs_api_path;
+
+ int options_left = NUM_OPTIONS;
const List<String>::Element *elem = p_cmdline_args.front();
@@ -2895,8 +3024,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
- if (get_singleton()->generate_glue(path_elem->get()) != OK)
- ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue");
+ mono_glue_path = path_elem->get();
elem = elem->next();
} else {
ERR_PRINTS(mono_glue_option + ": No output directory specified");
@@ -2907,8 +3035,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
- if (get_singleton()->generate_cs_api(path_elem->get()) != OK)
- ERR_PRINTS(cs_api_option + ": Failed to generate the C# API");
+ cs_api_path = path_elem->get();
elem = elem->next();
} else {
ERR_PRINTS(cs_api_option + ": No output directory specified");
@@ -2920,10 +3047,23 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
}
- verbose_output = false;
+ if (mono_glue_path.length() || cs_api_path.length()) {
+ BindingsGenerator bindings_generator;
+ bindings_generator.set_log_print_enabled(true);
+
+ if (mono_glue_path.length()) {
+ if (bindings_generator.generate_glue(mono_glue_path) != OK)
+ ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue");
+ }
+
+ if (cs_api_path.length()) {
+ if (bindings_generator.generate_cs_api(cs_api_path) != OK)
+ ERR_PRINTS(cs_api_option + ": Failed to generate the C# API");
+ }
- if (options_left != NUM_OPTIONS)
+ // Exit once done
::exit(0);
+ }
}
#endif
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index a073c09910..bdba28c267 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -159,17 +159,20 @@ class BindingsGenerator {
const DocData::MethodDoc *method_doc;
+ bool is_deprecated;
+ String deprecation_message;
+
void add_argument(const ArgumentInterface &argument) {
arguments.push_back(argument);
}
MethodInterface() {
- return_type.cname = BindingsGenerator::get_singleton()->name_cache.type_void;
is_vararg = false;
is_virtual = false;
requires_object_call = false;
is_internal = false;
method_doc = NULL;
+ is_deprecated = false;
}
};
@@ -400,8 +403,8 @@ class BindingsGenerator {
}
static void postsetup_enum_type(TypeInterface &r_enum_itype) {
- // C interface is the same as that of 'int'. Remember to apply any
- // changes done here to the 'int' type interface as well
+ // C interface for enums is the same as that of 'uint32_t'. Remember to apply
+ // any of the changes done here to the 'uint32_t' type interface as well.
r_enum_itype.c_arg_in = "&%s_in";
{
@@ -469,7 +472,7 @@ class BindingsGenerator {
}
};
- static bool verbose_output;
+ bool log_print_enabled;
OrderedHashMap<StringName, TypeInterface> obj_types;
@@ -490,7 +493,6 @@ class BindingsGenerator {
struct NameCache {
StringName type_void;
- StringName type_int;
StringName type_Array;
StringName type_Dictionary;
StringName type_Variant;
@@ -501,9 +503,19 @@ class BindingsGenerator {
StringName type_at_GlobalScope;
StringName enum_Error;
+ StringName type_sbyte;
+ StringName type_short;
+ StringName type_int;
+ StringName type_long;
+ StringName type_byte;
+ StringName type_ushort;
+ StringName type_uint;
+ StringName type_ulong;
+ StringName type_float;
+ StringName type_double;
+
NameCache() {
type_void = StaticCString::create("void");
- type_int = StaticCString::create("int");
type_Array = StaticCString::create("Array");
type_Dictionary = StaticCString::create("Dictionary");
type_Variant = StaticCString::create("Variant");
@@ -513,8 +525,20 @@ class BindingsGenerator {
type_String = StaticCString::create("String");
type_at_GlobalScope = StaticCString::create("@GlobalScope");
enum_Error = StaticCString::create("Error");
+
+ type_sbyte = StaticCString::create("sbyte");
+ type_short = StaticCString::create("short");
+ type_int = StaticCString::create("int");
+ type_long = StaticCString::create("long");
+ type_byte = StaticCString::create("byte");
+ type_ushort = StaticCString::create("ushort");
+ type_uint = StaticCString::create("uint");
+ type_ulong = StaticCString::create("ulong");
+ type_float = StaticCString::create("float");
+ type_double = StaticCString::create("double");
}
+ private:
NameCache(const NameCache &);
NameCache &operator=(const NameCache &);
};
@@ -560,6 +584,9 @@ class BindingsGenerator {
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
+ StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
+ StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
+
void _default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg);
void _populate_object_type_interfaces();
@@ -578,33 +605,26 @@ class BindingsGenerator {
Error _save_file(const String &p_path, const StringBuilder &p_content);
- BindingsGenerator() {}
-
- BindingsGenerator(const BindingsGenerator &);
- BindingsGenerator &operator=(const BindingsGenerator &);
+ void _log(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
- friend class CSharpLanguage;
- static BindingsGenerator *singleton;
+ void _initialize();
public:
- Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true);
- Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true);
- Error generate_cs_api(const String &p_output_dir, bool p_verbose_output = true);
+ Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution);
+ Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution);
+ Error generate_cs_api(const String &p_output_dir);
Error generate_glue(const String &p_output_dir);
+ void set_log_print_enabled(bool p_enabled) { log_print_enabled = p_enabled; }
+
static uint32_t get_version();
- void initialize();
+ static void handle_cmdline_args(const List<String> &p_cmdline_args);
- _FORCE_INLINE_ static BindingsGenerator *get_singleton() {
- if (!singleton) {
- singleton = memnew(BindingsGenerator);
- singleton->initialize();
- }
- return singleton;
+ BindingsGenerator() :
+ log_print_enabled(true) {
+ _initialize();
}
-
- static void handle_cmdline_args(const List<String> &p_cmdline_args);
};
#endif
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
index beeff51bc2..fe79286556 100644
--- a/modules/mono/editor/csharp_project.cpp
+++ b/modules/mono/editor/csharp_project.cpp
@@ -158,7 +158,7 @@ Error generate_scripts_metadata(const String &p_project_path, const String &p_ou
PoolStringArray project_files = GDMonoMarshal::mono_array_to_PoolStringArray(ret);
PoolStringArray::Read r = project_files.read();
- Dictionary old_dict = CSharpLanguage::get_singleton()->get_scripts_metadata();
+ Dictionary old_dict = CSharpLanguage::get_singleton()->get_scripts_metadata_or_nothing();
Dictionary new_dict;
for (int i = 0; i < project_files.size(); i++) {
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index 00c780d1b7..de3fd91223 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -323,10 +323,13 @@ bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) {
String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
- BindingsGenerator *gen = BindingsGenerator::get_singleton();
- bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
+ BindingsGenerator bindings_generator;
- Error err = gen->generate_cs_api(api_sln_dir, gen_verbose);
+ if (!OS::get_singleton()->is_stdout_verbose()) {
+ bindings_generator.set_log_print_enabled(false);
+ }
+
+ Error err = bindings_generator.generate_cs_api(api_sln_dir);
if (err != OK) {
show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err));
return false;
diff --git a/modules/mono/glue/Managed/Files/Color.cs b/modules/mono/glue/Managed/Files/Color.cs
index 88fa3323c2..84ff19fc54 100644
--- a/modules/mono/glue/Managed/Files/Color.cs
+++ b/modules/mono/glue/Managed/Files/Color.cs
@@ -168,7 +168,7 @@ namespace Godot
int max = Mathf.Max(color.r8, Mathf.Max(color.g8, color.b8));
int min = Mathf.Min(color.r8, Mathf.Min(color.g8, color.b8));
- float delta = max - min;
+ int delta = max - min;
if (delta == 0)
{
@@ -591,11 +591,11 @@ namespace Godot
public static bool operator <(Color left, Color right)
{
- if (left.r == right.r)
+ if (Mathf.IsEqualApprox(left.r, right.r))
{
- if (left.g == right.g)
+ if (Mathf.IsEqualApprox(left.g, right.g))
{
- if (left.b == right.b)
+ if (Mathf.IsEqualApprox(left.b, right.b))
return left.a < right.a;
return left.b < right.b;
}
@@ -608,11 +608,11 @@ namespace Godot
public static bool operator >(Color left, Color right)
{
- if (left.r == right.r)
+ if (Mathf.IsEqualApprox(left.r, right.r))
{
- if (left.g == right.g)
+ if (Mathf.IsEqualApprox(left.g, right.g))
{
- if (left.b == right.b)
+ if (Mathf.IsEqualApprox(left.b, right.b))
return left.a > right.a;
return left.b > right.b;
}
@@ -635,7 +635,7 @@ namespace Godot
public bool Equals(Color other)
{
- return r == other.r && g == other.g && b == other.b && a == other.a;
+ return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a);
}
public override int GetHashCode()
diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs
index 5b591646ea..2068099ac6 100644
--- a/modules/mono/glue/Managed/Files/GD.cs
+++ b/modules/mono/glue/Managed/Files/GD.cs
@@ -111,7 +111,7 @@ namespace Godot
godot_icall_GD_printt(Array.ConvertAll(what, x => x.ToString()));
}
- public static double Randf()
+ public static float Randf()
{
return godot_icall_GD_randf();
}
@@ -224,7 +224,7 @@ namespace Godot
internal extern static void godot_icall_GD_printt(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static double godot_icall_GD_randf();
+ internal extern static float godot_icall_GD_randf();
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static uint godot_icall_GD_randi();
@@ -232,6 +232,7 @@ namespace Godot
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_randomize();
+
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static double godot_icall_GD_rand_range(double from, double to);
diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs
index a064278237..947fbb6665 100644
--- a/modules/mono/glue/Managed/Files/Mathf.cs
+++ b/modules/mono/glue/Managed/Files/Mathf.cs
@@ -143,6 +143,15 @@ namespace Godot
return (weight - from) / (to - from);
}
+ public static bool IsEqualApprox(real_t a, real_t b)
+ {
+ real_t tolerance = Epsilon * Abs(a);
+ if (tolerance < Epsilon) {
+ tolerance = Epsilon;
+ }
+ return Abs(a - b) < tolerance;
+ }
+
public static bool IsInf(real_t s)
{
return real_t.IsInfinity(s);
@@ -153,6 +162,11 @@ namespace Godot
return real_t.IsNaN(s);
}
+ public static bool IsZeroApprox(real_t s)
+ {
+ return Abs(s) < Epsilon;
+ }
+
public static real_t Lerp(real_t from, real_t to, real_t weight)
{
return from + (to - from) * weight;
diff --git a/modules/mono/glue/Managed/Files/MathfEx.cs b/modules/mono/glue/Managed/Files/MathfEx.cs
index 414762f7b1..d6eb65b097 100644
--- a/modules/mono/glue/Managed/Files/MathfEx.cs
+++ b/modules/mono/glue/Managed/Files/MathfEx.cs
@@ -36,9 +36,9 @@ namespace Godot
return (int)Math.Round(s);
}
- public static bool IsEqualApprox(real_t a, real_t b, real_t ratio = Mathf.Epsilon)
+ public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance)
{
- return Abs(a - b) < ratio;
+ return Abs(a - b) < tolerance;
}
}
} \ No newline at end of file
diff --git a/modules/mono/glue/Managed/Files/Plane.cs b/modules/mono/glue/Managed/Files/Plane.cs
index f11cd490a9..e16d4315be 100644
--- a/modules/mono/glue/Managed/Files/Plane.cs
+++ b/modules/mono/glue/Managed/Files/Plane.cs
@@ -200,7 +200,7 @@ namespace Godot
public bool Equals(Plane other)
{
- return _normal == other._normal && D == other.D;
+ return _normal == other._normal && Mathf.IsEqualApprox(D, other.D);
}
public override int GetHashCode()
diff --git a/modules/mono/glue/Managed/Files/Quat.cs b/modules/mono/glue/Managed/Files/Quat.cs
index d0c15146a5..0d4349084a 100644
--- a/modules/mono/glue/Managed/Files/Quat.cs
+++ b/modules/mono/glue/Managed/Files/Quat.cs
@@ -358,7 +358,7 @@ namespace Godot
public bool Equals(Quat other)
{
- return x == other.x && y == other.y && z == other.z && w == other.w;
+ return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);
}
public override int GetHashCode()
diff --git a/modules/mono/glue/Managed/Files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs
index 908162ec45..bb1950e1a8 100644
--- a/modules/mono/glue/Managed/Files/Vector2.cs
+++ b/modules/mono/glue/Managed/Files/Vector2.cs
@@ -52,11 +52,15 @@ namespace Godot
internal void Normalize()
{
- real_t length = x * x + y * y;
+ real_t lengthsq = LengthSquared();
- if (length != 0f)
+ if (lengthsq == 0)
{
- length = Mathf.Sqrt(length);
+ x = y = 0f;
+ }
+ else
+ {
+ real_t length = Mathf.Sqrt(lengthsq);
x /= length;
y /= length;
}
@@ -184,9 +188,9 @@ namespace Godot
public Vector2 Normalized()
{
- var result = this;
- result.Normalize();
- return result;
+ var v = this;
+ v.Normalize();
+ return v;
}
public Vector2 Project(Vector2 onNormal)
@@ -343,7 +347,7 @@ namespace Godot
public static bool operator <(Vector2 left, Vector2 right)
{
- if (left.x.Equals(right.x))
+ if (Mathf.IsEqualApprox(left.x, right.x))
{
return left.y < right.y;
}
@@ -353,7 +357,7 @@ namespace Godot
public static bool operator >(Vector2 left, Vector2 right)
{
- if (left.x.Equals(right.x))
+ if (Mathf.IsEqualApprox(left.x, right.x))
{
return left.y > right.y;
}
@@ -363,7 +367,7 @@ namespace Godot
public static bool operator <=(Vector2 left, Vector2 right)
{
- if (left.x.Equals(right.x))
+ if (Mathf.IsEqualApprox(left.x, right.x))
{
return left.y <= right.y;
}
@@ -373,7 +377,7 @@ namespace Godot
public static bool operator >=(Vector2 left, Vector2 right)
{
- if (left.x.Equals(right.x))
+ if (Mathf.IsEqualApprox(left.x, right.x))
{
return left.y >= right.y;
}
@@ -393,7 +397,7 @@ namespace Godot
public bool Equals(Vector2 other)
{
- return x == other.x && y == other.y;
+ return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y);
}
public override int GetHashCode()
diff --git a/modules/mono/glue/Managed/Files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs
index 0c96d346a9..283cb6341a 100644
--- a/modules/mono/glue/Managed/Files/Vector3.cs
+++ b/modules/mono/glue/Managed/Files/Vector3.cs
@@ -65,14 +65,15 @@ namespace Godot
internal void Normalize()
{
- real_t length = Length();
+ real_t lengthsq = LengthSquared();
- if (length == 0f)
+ if (lengthsq == 0)
{
x = y = z = 0f;
}
else
{
+ real_t length = Mathf.Sqrt(lengthsq);
x /= length;
y /= length;
z /= length;
@@ -397,9 +398,9 @@ namespace Godot
public static bool operator <(Vector3 left, Vector3 right)
{
- if (left.x == right.x)
+ if (Mathf.IsEqualApprox(left.x, right.x))
{
- if (left.y == right.y)
+ if (Mathf.IsEqualApprox(left.y, right.y))
return left.z < right.z;
return left.y < right.y;
}
@@ -409,9 +410,9 @@ namespace Godot
public static bool operator >(Vector3 left, Vector3 right)
{
- if (left.x == right.x)
+ if (Mathf.IsEqualApprox(left.x, right.x))
{
- if (left.y == right.y)
+ if (Mathf.IsEqualApprox(left.y, right.y))
return left.z > right.z;
return left.y > right.y;
}
@@ -421,9 +422,9 @@ namespace Godot
public static bool operator <=(Vector3 left, Vector3 right)
{
- if (left.x == right.x)
+ if (Mathf.IsEqualApprox(left.x, right.x))
{
- if (left.y == right.y)
+ if (Mathf.IsEqualApprox(left.y, right.y))
return left.z <= right.z;
return left.y < right.y;
}
@@ -433,9 +434,9 @@ namespace Godot
public static bool operator >=(Vector3 left, Vector3 right)
{
- if (left.x == right.x)
+ if (Mathf.IsEqualApprox(left.x, right.x))
{
- if (left.y == right.y)
+ if (Mathf.IsEqualApprox(left.y, right.y))
return left.z >= right.z;
return left.y > right.y;
}
@@ -455,7 +456,7 @@ namespace Godot
public bool Equals(Vector3 other)
{
- return x == other.x && y == other.y && z == other.z;
+ return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z);
}
public override int GetHashCode()
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index d756131ac9..7c30092855 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -115,7 +115,7 @@ void godot_icall_GD_printt(MonoArray *p_what) {
print_line(str);
}
-double godot_icall_GD_randf() {
+float godot_icall_GD_randf() {
return Math::randf();
}
diff --git a/modules/mono/glue/gd_glue.h b/modules/mono/glue/gd_glue.h
index 910979aae3..d4e20e2887 100644
--- a/modules/mono/glue/gd_glue.h
+++ b/modules/mono/glue/gd_glue.h
@@ -53,7 +53,7 @@ void godot_icall_GD_prints(MonoArray *p_what);
void godot_icall_GD_printt(MonoArray *p_what);
-double godot_icall_GD_randf();
+float godot_icall_GD_randf();
uint32_t godot_icall_GD_randi();
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index bfb6c13224..19e49d29f9 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -658,8 +658,6 @@ bool GDMono::_load_project_assembly() {
if (success) {
mono_assembly_set_main(project_assembly->get_assembly());
-
- CSharpLanguage::get_singleton()->project_assembly_loaded();
} else {
if (OS::get_singleton()->is_stdout_verbose())
print_error("Mono: Failed to load project assembly");
@@ -866,7 +864,7 @@ Error GDMono::reload_scripts_domain() {
}
}
- CSharpLanguage::get_singleton()->_uninitialize_script_bindings();
+ CSharpLanguage::get_singleton()->_on_scripts_domain_unloaded();
Error err = _load_scripts_domain();
if (err != OK) {
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index 087a7a2e5c..a6e04e561d 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -37,6 +37,7 @@
#include "core/os/os.h"
#include "../godotsharp_dirs.h"
+#include "../utils/string_utils.h"
static int log_level_get_id(const char *p_log_level) {
@@ -125,27 +126,6 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
da->list_dir_end();
}
-static String format(const char *p_fmt, ...) {
- va_list args;
-
- va_start(args, p_fmt);
- int len = vsnprintf(NULL, 0, p_fmt, args);
- va_end(args);
-
- len += 1; // for the trailing '/0'
-
- char *buffer(memnew_arr(char, len));
-
- va_start(args, p_fmt);
- vsnprintf(buffer, len, p_fmt, args);
- va_end(args);
-
- String res(buffer);
- memdelete_arr(buffer);
-
- return res;
-}
-
void GDMonoLog::initialize() {
CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
@@ -172,7 +152,7 @@ void GDMonoLog::initialize() {
OS::Time time_now = OS::get_singleton()->get_time();
int pid = OS::get_singleton()->get_process_id();
- String log_file_name = format("%d_%02d_%02d %02d.%02d.%02d (%d).txt",
+ String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d (%d).txt",
date_now.year, date_now.month, date_now.day,
time_now.hour, time_now.min, time_now.sec, pid);
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index c390f8b9c2..0ef66577fe 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -32,6 +32,8 @@
#include "core/os/file_access.h"
+#include <stdio.h>
+
namespace {
int sfind(const String &p_text, int p_from) {
@@ -184,3 +186,50 @@ Error read_all_file_utf8(const String &p_path, String &r_content) {
r_content = source;
return OK;
}
+
+// TODO: Move to variadic templates once we upgrade to C++11
+
+String str_format(const char *p_format, ...) {
+ va_list list;
+
+ va_start(list, p_format);
+ String res = str_format(p_format, list);
+ va_end(list);
+
+ return res;
+}
+// va_copy was defined in the C99, but not in C++ standards before C++11.
+// When you compile C++ without --std=c++<XX> option, compilers still define
+// va_copy, otherwise you have to use the internal version (__va_copy).
+#if !defined(va_copy)
+#if defined(__GNUC__)
+#define va_copy(d, s) __va_copy((d), (s))
+#else
+#define va_copy(d, s) ((d) = (s))
+#endif
+#endif
+
+#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#define vsnprintf vsnprintf_s
+#endif
+
+String str_format(const char *p_format, va_list p_list) {
+ va_list list;
+
+ va_copy(list, p_list);
+ int len = vsnprintf(NULL, 0, p_format, list);
+ va_end(list);
+
+ len += 1; // for the trailing '/0'
+
+ char *buffer(memnew_arr(char, len));
+
+ va_copy(list, p_list);
+ vsnprintf(buffer, len, p_format, list);
+ va_end(list);
+
+ String res(buffer);
+ memdelete_arr(buffer);
+
+ return res;
+}
diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h
index 61765ccfd8..565b9bb644 100644
--- a/modules/mono/utils/string_utils.h
+++ b/modules/mono/utils/string_utils.h
@@ -34,6 +34,8 @@
#include "core/ustring.h"
#include "core/variant.h"
+#include <stdarg.h>
+
String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
#ifdef TOOLS_ENABLED
@@ -44,4 +46,15 @@ String escape_csharp_keyword(const String &p_name);
Error read_all_file_utf8(const String &p_path, String &r_content);
+#if defined(__GNUC__)
+#define _PRINTF_FORMAT_ATTRIBUTE_1_0 __attribute__((format(printf, 1, 0)))
+#define _PRINTF_FORMAT_ATTRIBUTE_1_2 __attribute__((format(printf, 1, 2)))
+#else
+#define _PRINTF_FORMAT_ATTRIBUTE_1_0
+#define _PRINTF_FORMAT_ATTRIBUTE_1_2
+#endif
+
+String str_format(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_1_2;
+String str_format(const char *p_format, va_list p_list) _PRINTF_FORMAT_ATTRIBUTE_1_0;
+
#endif // STRING_FORMAT_H
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 14c5ddd7f2..ae542713ea 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -94,15 +94,15 @@ void VideoStreamPlaybackTheora::video_write(void) {
if (px_fmt == TH_PF_444) {
- yuv444_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);
+ yuv444_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2);
} else if (px_fmt == TH_PF_422) {
- yuv422_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);
+ yuv422_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2);
} else if (px_fmt == TH_PF_420) {
- yuv420_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[2].data, (uint8_t *)yuv[1].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);
+ yuv420_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2);
};
format = Image::FORMAT_RGBA8;
@@ -365,7 +365,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
float VideoStreamPlaybackTheora::get_time() const {
- return time - AudioServer::get_singleton()->get_output_delay() - delay_compensation; //-((get_total())/(float)vi.rate);
+ return time - AudioServer::get_singleton()->get_output_latency() - delay_compensation; //-((get_total())/(float)vi.rate);
};
Ref<Texture> VideoStreamPlaybackTheora::get_texture() {
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index efd471eed1..28c9a11cb8 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -2101,6 +2101,14 @@ void VisualScriptEditor::goto_line(int p_line, bool p_with_error) {
}
}
+void VisualScriptEditor::set_executing_line(int p_line) {
+ // todo: add a way to show which node is executing right now.
+}
+
+void VisualScriptEditor::clear_executing_line() {
+ // todo: add a way to show which node is executing right now.
+}
+
void VisualScriptEditor::trim_trailing_whitespace() {
}
@@ -3566,7 +3574,7 @@ VisualScriptEditor::VisualScriptEditor() {
graph->connect("scroll_offset_changed", this, "_graph_ofs_changed");
select_func_text = memnew(Label);
- select_func_text->set_text(TTR("Select or create a function to edit graph"));
+ select_func_text->set_text(TTR("Select or create a function to edit its graph."));
select_func_text->set_align(Label::ALIGN_CENTER);
select_func_text->set_valign(Label::VALIGN_CENTER);
select_func_text->set_h_size_flags(SIZE_EXPAND_FILL);
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index f4b4a6981d..9387a09c78 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -263,6 +263,8 @@ public:
virtual Variant get_edit_state();
virtual void set_edit_state(const Variant &p_state);
virtual void goto_line(int p_line, bool p_with_error = false);
+ virtual void set_executing_line(int p_line);
+ virtual void clear_executing_line();
virtual void trim_trailing_whitespace();
virtual void convert_indent_to_spaces();
virtual void convert_indent_to_tabs();
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index 06f9e39dc7..f6397483e8 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -32,6 +32,7 @@
#include "OpusVorbisDecoder.hpp"
#include "VPXDecoder.hpp"
+#include <vpx/vpx_image.h>
#include "mkvparser/mkvparser.h"
@@ -314,19 +315,37 @@ void VideoStreamPlaybackWebm::update(float p_delta) {
PoolVector<uint8_t>::Write w = frame_data.write();
bool converted = false;
- if (image.chromaShiftW == 1 && image.chromaShiftH == 1) {
+ if (image.chromaShiftW == 0 && image.chromaShiftH == 0 && image.cs == VPX_CS_SRGB) {
+
+ uint8_t *wp = w.ptr();
+ unsigned char *rRow = image.planes[2];
+ unsigned char *gRow = image.planes[0];
+ unsigned char *bRow = image.planes[1];
+ for (size_t i = 0; i < image.h; i++) {
+ for (size_t j = 0; j < image.w; j++) {
+ *wp++ = rRow[j];
+ *wp++ = gRow[j];
+ *wp++ = bRow[j];
+ *wp++ = 255;
+ }
+ rRow += image.linesize[2];
+ gRow += image.linesize[0];
+ bRow += image.linesize[1];
+ }
+ converted = true;
+ } else if (image.chromaShiftW == 1 && image.chromaShiftH == 1) {
- yuv420_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+ yuv420_2_rgb8888(w.ptr(), image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
// libyuv::I420ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
converted = true;
} else if (image.chromaShiftW == 1 && image.chromaShiftH == 0) {
- yuv422_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+ yuv422_2_rgb8888(w.ptr(), image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
// libyuv::I422ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
converted = true;
} else if (image.chromaShiftW == 0 && image.chromaShiftH == 0) {
- yuv444_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+ yuv444_2_rgb8888(w.ptr(), image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
// libyuv::I444ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
converted = true;
} else if (image.chromaShiftW == 2 && image.chromaShiftH == 0) {
@@ -375,7 +394,7 @@ int VideoStreamPlaybackWebm::get_mix_rate() const {
inline bool VideoStreamPlaybackWebm::has_enough_video_frames() const {
if (video_frames_pos > 0) {
- const double audio_delay = AudioServer::get_singleton()->get_output_delay();
+ const double audio_delay = AudioServer::get_singleton()->get_output_latency();
const double video_time = video_frames[video_frames_pos - 1]->time;
return video_time >= time + audio_delay + delay_compensation;
}
@@ -383,7 +402,7 @@ inline bool VideoStreamPlaybackWebm::has_enough_video_frames() const {
}
bool VideoStreamPlaybackWebm::should_process(WebMFrame &video_frame) {
- const double audio_delay = AudioServer::get_singleton()->get_output_delay();
+ const double audio_delay = AudioServer::get_singleton()->get_output_latency();
return video_frame.time >= time + audio_delay + delay_compensation;
}
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index f70cee2964..2a3d0843a8 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -1735,8 +1735,8 @@ public:
new_file += l + "\n";
} else {
String base = l.substr(0, last_tag_pos + last_tag.length());
- if (manifest_sections.has("application_tags")) {
- for (List<String>::Element *E = manifest_sections["application_tags"].front(); E; E = E->next()) {
+ if (manifest_sections.has("application_attribs")) {
+ for (List<String>::Element *E = manifest_sections["application_attribs"].front(); E; E = E->next()) {
String to_add = E->get().strip_edges();
base += " " + to_add + " ";
}
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 5a4c0593bc..fec524c04b 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -337,6 +337,11 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
}
- (void)windowDidMove:(NSNotification *)notification {
+
+ if (OS_OSX::singleton->get_main_loop()) {
+ OS_OSX::singleton->input->release_pressed_events();
+ }
+
/*
[window->nsgl.context update];
@@ -965,10 +970,10 @@ static const _KeyCodeMap _keycodes[55] = {
{ 'i', KEY_I },
{ 'o', KEY_O },
{ 'p', KEY_P },
- { '[', KEY_BRACERIGHT },
- { ']', KEY_BRACELEFT },
- { '{', KEY_BRACERIGHT },
- { '}', KEY_BRACELEFT },
+ { '[', KEY_BRACELEFT },
+ { ']', KEY_BRACERIGHT },
+ { '{', KEY_BRACELEFT },
+ { '}', KEY_BRACERIGHT },
{ 'a', KEY_A },
{ 's', KEY_S },
{ 'd', KEY_D },
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 193a3fa2c6..0b61770d87 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -346,6 +346,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
control_mem = false;
shift_mem = false;
} else { // WM_INACTIVE
+ input->release_pressed_events();
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
alt_mem = false;
};
@@ -786,6 +787,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} break;
case WM_ENTERSIZEMOVE: {
+ input->release_pressed_events();
move_timer_id = SetTimer(hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC)NULL);
} break;
case WM_EXITSIZEMOVE: {
@@ -1411,26 +1413,29 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
void OS_Windows::set_clipboard(const String &p_text) {
+ // Convert LF line endings to CRLF in clipboard content
+ // Otherwise, line endings won't be visible when pasted in other software
+ String text = p_text.replace("\n", "\r\n");
+
if (!OpenClipboard(hWnd)) {
ERR_EXPLAIN("Unable to open clipboard.");
ERR_FAIL();
};
EmptyClipboard();
- HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (p_text.length() + 1) * sizeof(CharType));
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(CharType));
if (mem == NULL) {
ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
ERR_FAIL();
};
LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
- memcpy(lptstrCopy, p_text.c_str(), (p_text.length() + 1) * sizeof(CharType));
- //memset((lptstrCopy + p_text.length()), 0, sizeof(CharType));
+ memcpy(lptstrCopy, text.c_str(), (text.length() + 1) * sizeof(CharType));
GlobalUnlock(mem);
SetClipboardData(CF_UNICODETEXT, mem);
// set the CF_TEXT version (not needed?)
- CharString utf8 = p_text.utf8();
+ CharString utf8 = text.utf8();
mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
if (mem == NULL) {
ERR_EXPLAIN("Unable to allocate memory for clipboard contents.");
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 1905b035e6..f8ae5e9acb 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -1,7 +1,7 @@
import os
import platform
import sys
-from methods import get_compiler_version, using_gcc
+from methods import get_compiler_version, using_gcc, using_clang
def is_active():
@@ -59,6 +59,7 @@ def get_opts():
return [
BoolVariable('use_llvm', 'Use the LLVM compiler', False),
BoolVariable('use_lld', 'Use the LLD linker', False),
+ BoolVariable('use_thinlto', 'Use ThinLTO', False),
BoolVariable('use_static_cpp', 'Link libgcc and libstdc++ statically for better portability', False),
BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False),
BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False),
@@ -136,6 +137,9 @@ def configure(env):
if env['use_lld']:
if env['use_llvm']:
env.Append(LINKFLAGS=['-fuse-ld=lld'])
+ if env['use_thinlto']:
+ # A convenience so you don't need to write use_lto too when using SCons
+ env['use_lto'] = True
else:
print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.")
sys.exit(255)
@@ -156,12 +160,17 @@ def configure(env):
env.Append(LINKFLAGS=['-fsanitize=leak'])
if env['use_lto']:
- env.Append(CCFLAGS=['-flto'])
-
if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
+ env.Append(CCFLAGS=['-flto'])
env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
else:
- env.Append(LINKFLAGS=['-flto'])
+ if env['use_lld'] and env['use_thinlto']:
+ env.Append(CCFLAGS=['-flto=thin'])
+ env.Append(LINKFLAGS=['-flto=thin'])
+ else:
+ env.Append(CCFLAGS=['-flto'])
+ env.Append(LINKFLAGS=['-flto'])
+
if not env['use_llvm']:
env['RANLIB'] = 'gcc-ranlib'
env['AR'] = 'gcc-ar'
@@ -175,6 +184,12 @@ def configure(env):
if version != None and version[0] >= '6':
env.Append(CCFLAGS=['-fpie'])
env.Append(LINKFLAGS=['-no-pie'])
+ # Do the same for clang should be fine with Clang 4 and higher
+ if using_clang(env):
+ version = get_compiler_version(env)
+ if version != None and version[0] >= '4':
+ env.Append(CCFLAGS=['-fpie'])
+ env.Append(LINKFLAGS=['-no-pie'])
## Dependencies
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index f6161a9485..267ac08a72 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -1176,15 +1176,28 @@ Point2 OS_X11::get_window_position() const {
int x, y;
Window child;
XTranslateCoordinates(x11_display, x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
-
- int screen = get_current_screen();
- Point2i screen_position = get_screen_position(screen);
-
- return Point2i(x - screen_position.x, y - screen_position.y);
+ return Point2i(x, y);
}
void OS_X11::set_window_position(const Point2 &p_position) {
- XMoveWindow(x11_display, x11_window, p_position.x, p_position.y);
+ int x = 0;
+ int y = 0;
+ if (get_borderless_window() == false) {
+ //exclude window decorations
+ XSync(x11_display, False);
+ Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = NULL;
+ if (XGetWindowProperty(x11_display, x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+ long *extents = (long *)data;
+ x = extents[0];
+ y = extents[2];
+ }
+ }
+ XMoveWindow(x11_display, x11_window, p_position.x - x, p_position.y - y);
update_real_mouse_position();
}
@@ -2076,7 +2089,9 @@ void OS_X11::process_xevents() {
case FocusOut:
window_has_focus = false;
+ input->release_pressed_events();
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+
if (mouse_mode_grab) {
//dear X11, I try, I really try, but you never work, you do whathever you want.
if (mouse_mode == MOUSE_MODE_CAPTURED) {
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index faefd85968..73f583111b 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -37,7 +37,7 @@
void AudioStreamPlayer2D::_mix_audio() {
if (!stream_playback.is_valid() || !active ||
- (stream_paused && !stream_fade_out)) {
+ (stream_paused && !stream_paused_fade_out)) {
return;
}
@@ -50,7 +50,7 @@ void AudioStreamPlayer2D::_mix_audio() {
AudioFrame *buffer = mix_buffer.ptrw();
int buffer_size = mix_buffer.size();
- if (stream_fade_out) {
+ if (stream_paused_fade_out) {
// Short fadeout ramp
buffer_size = MIN(buffer_size, 128);
}
@@ -84,10 +84,10 @@ void AudioStreamPlayer2D::_mix_audio() {
}
//mix!
- AudioFrame target_volume = stream_fade_out ? AudioFrame(0.f, 0.f) : current.vol;
- AudioFrame vol_prev = stream_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol;
+ AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol;
+ AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol;
AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
- AudioFrame vol = stream_fade_in ? AudioFrame(0.f, 0.f) : current.vol;
+ AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol;
int cc = AudioServer::get_singleton()->get_channel_count();
@@ -139,15 +139,9 @@ void AudioStreamPlayer2D::_mix_audio() {
active = false;
}
- if (stream_stop) {
- active = false;
- set_physics_process_internal(false);
- setplay = -1;
- }
-
output_ready = false;
- stream_fade_in = false;
- stream_fade_out = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
}
void AudioStreamPlayer2D::_notification(int p_what) {
@@ -329,7 +323,6 @@ void AudioStreamPlayer2D::play(float p_from_pos) {
}
if (stream_playback.is_valid()) {
- stream_stop = false;
active = true;
setplay = p_from_pos;
output_ready = false;
@@ -347,8 +340,9 @@ void AudioStreamPlayer2D::seek(float p_seconds) {
void AudioStreamPlayer2D::stop() {
if (stream_playback.is_valid()) {
- stream_stop = true;
- stream_fade_out = true;
+ active = false;
+ set_physics_process_internal(false);
+ setplay = -1;
}
}
@@ -463,8 +457,8 @@ void AudioStreamPlayer2D::set_stream_paused(bool p_pause) {
if (p_pause != stream_paused) {
stream_paused = p_pause;
- stream_fade_in = p_pause ? false : true;
- stream_fade_out = p_pause ? true : false;
+ stream_paused_fade_in = p_pause ? false : true;
+ stream_paused_fade_out = p_pause ? true : false;
}
}
@@ -549,9 +543,8 @@ AudioStreamPlayer2D::AudioStreamPlayer2D() {
output_ready = false;
area_mask = 1;
stream_paused = false;
- stream_fade_in = false;
- stream_fade_out = false;
- stream_stop = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
}
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index 0cd18fb93b..e9cdfa2303 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -73,9 +73,8 @@ private:
float pitch_scale;
bool autoplay;
bool stream_paused;
- bool stream_fade_in;
- bool stream_fade_out;
- bool stream_stop;
+ bool stream_paused_fade_in;
+ bool stream_paused_fade_out;
StringName bus;
void _mix_audio();
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index f43d97eb2a..375375285d 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -251,9 +251,9 @@ void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2
s.index = total_subshapes;
s.shape = p_shape;
if (area) {
- Physics2DServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform);
+ Physics2DServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
} else {
- Physics2DServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform);
+ Physics2DServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
}
sd.shapes.push_back(s);
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 73692e0535..ba06b3ebff 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -120,8 +120,12 @@ void Line2D::clear_points() {
}
}
-void Line2D::add_point(Vector2 pos) {
- _points.append(pos);
+void Line2D::add_point(Vector2 pos, int atpos) {
+ if (atpos < 0 || _points.size() < atpos) {
+ _points.append(pos);
+ } else {
+ _points.insert(atpos, pos);
+ }
update();
}
@@ -318,7 +322,7 @@ void Line2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Line2D::get_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position"), &Line2D::add_point);
+ ClassDB::bind_method(D_METHOD("add_point", "position", "at_position"), &Line2D::add_point, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("remove_point", "i"), &Line2D::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points);
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index 32befab2d3..8a6f7b2dc5 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -72,7 +72,7 @@ public:
void clear_points();
- void add_point(Vector2 pos);
+ void add_point(Vector2 pos, int atpos = -1);
void remove_point(int i);
void set_width(float width);
diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp
index 57e0a5b118..72b5f2fb12 100644
--- a/scene/2d/navigation_2d.cpp
+++ b/scene/2d/navigation_2d.cpp
@@ -542,7 +542,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (CLOCK_TANGENT(apex_point, portal_left, left) >= 0) {
//process
- if (portal_left.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, left, portal_right) > 0) {
+ if (Math::is_zero_approx(portal_left.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, left, portal_right) > 0) {
left_poly = p;
portal_left = left;
} else {
@@ -552,7 +552,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
left_poly = p;
portal_left = apex_point;
portal_right = apex_point;
- if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON)
+ if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point)))
path.push_back(apex_point);
skip = true;
}
@@ -560,7 +560,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (!skip && CLOCK_TANGENT(apex_point, portal_right, right) <= 0) {
//process
- if (portal_right.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, right, portal_left) < 0) {
+ if (Math::is_zero_approx(portal_right.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, right, portal_left) < 0) {
right_poly = p;
portal_right = right;
} else {
@@ -570,7 +570,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
right_poly = p;
portal_right = apex_point;
portal_left = apex_point;
- if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON)
+ if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point)))
path.push_back(apex_point);
}
}
@@ -596,7 +596,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
}
}
- if (!path.size() || path[path.size() - 1].distance_squared_to(begin_point) > CMP_EPSILON) {
+ if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(begin_point))) {
path.push_back(begin_point); // Add the begin point
} else {
path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point
@@ -604,7 +604,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
path.invert();
- if (path.size() <= 1 || path[path.size() - 1].distance_squared_to(end_point) > CMP_EPSILON) {
+ if (path.size() <= 1 || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(end_point))) {
path.push_back(end_point); // Add the end point
} else {
path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 885c9ea8bc..b321bcf3ce 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -749,7 +749,10 @@ void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_
void TileMap::_set_celld(const Vector2 &p_pos, const Dictionary &p_data) {
- set_cell(p_pos.x, p_pos.y, p_data["id"], p_data["flip_h"], p_data["flip_y"], p_data["transpose"], p_data["auto_coord"]);
+ Variant v_pos_x = p_pos.x, v_pos_y = p_pos.y, v_tile = p_data["id"], v_flip_h = p_data["flip_h"], v_flip_v = p_data["flip_y"], v_transpose = p_data["transpose"], v_autotile_coord = p_data["auto_coord"];
+ const Variant *args[7] = { &v_pos_x, &v_pos_y, &v_tile, &v_flip_h, &v_flip_v, &v_transpose, &v_autotile_coord };
+ Variant::CallError ce;
+ call("set_cell", args, 7, ce);
}
void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose, Vector2 p_autotile_coord) {
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index e5346c4c53..52fa96ee4a 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -379,11 +379,11 @@ String ARVRController::get_configuration_warning() const {
// must be child node of ARVROrigin!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin == NULL) {
- return TTR("ARVRController must have an ARVROrigin node as its parent");
+ return TTR("ARVRController must have an ARVROrigin node as its parent.");
};
if (controller_id == 0) {
- return TTR("The controller id must not be 0 or this controller will not be bound to an actual controller");
+ return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
};
return String();
@@ -506,11 +506,11 @@ String ARVRAnchor::get_configuration_warning() const {
// must be child node of ARVROrigin!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin == NULL) {
- return TTR("ARVRAnchor must have an ARVROrigin node as its parent");
+ return TTR("ARVRAnchor must have an ARVROrigin node as its parent.");
};
if (anchor_id == 0) {
- return TTR("The anchor id must not be 0 or this anchor will not be bound to an actual anchor");
+ return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
};
return String();
@@ -545,7 +545,7 @@ String ARVROrigin::get_configuration_warning() const {
return String();
if (tracked_camera == NULL)
- return TTR("ARVROrigin requires an ARVRCamera child node");
+ return TTR("ARVROrigin requires an ARVRCamera child node.");
return String();
};
@@ -583,6 +583,10 @@ void ARVROrigin::set_world_scale(float p_world_scale) {
};
void ARVROrigin::_notification(int p_what) {
+ // get our ARVRServer
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
set_process_internal(true);
@@ -591,10 +595,6 @@ void ARVROrigin::_notification(int p_what) {
set_process_internal(false);
}; break;
case NOTIFICATION_INTERNAL_PROCESS: {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
// set our world origin to our node transform
arvr_server->set_world_origin(get_global_transform());
@@ -611,6 +611,14 @@ void ARVROrigin::_notification(int p_what) {
default:
break;
};
+
+ // send our notification to all active ARVR interfaces, they may need to react to it also
+ for (int i = 0; i < arvr_server->get_interface_count(); i++) {
+ Ref<ARVRInterface> interface = arvr_server->get_interface(i);
+ if (interface.is_valid() && interface->is_initialized()) {
+ interface->notification(p_what);
+ }
+ }
};
ARVROrigin::ARVROrigin() {
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 8bc48914d5..ff8c218575 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -38,7 +38,7 @@
void AudioStreamPlayer3D::_mix_audio() {
if (!stream_playback.is_valid() || !active ||
- (stream_paused && !stream_fade_out)) {
+ (stream_paused && !stream_paused_fade_out)) {
return;
}
@@ -53,7 +53,7 @@ void AudioStreamPlayer3D::_mix_audio() {
AudioFrame *buffer = mix_buffer.ptrw();
int buffer_size = mix_buffer.size();
- if (stream_fade_out) {
+ if (stream_paused_fade_out) {
// Short fadeout ramp
buffer_size = MIN(buffer_size, 128);
}
@@ -109,10 +109,10 @@ void AudioStreamPlayer3D::_mix_audio() {
int buffers = AudioServer::get_singleton()->get_channel_count();
for (int k = 0; k < buffers; k++) {
- AudioFrame target_volume = stream_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k];
- AudioFrame vol_prev = stream_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k];
+ AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k];
+ AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k];
AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
- AudioFrame vol = stream_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k];
+ AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k];
if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, k))
continue; //may have been deleted, will be updated on process
@@ -198,15 +198,9 @@ void AudioStreamPlayer3D::_mix_audio() {
active = false;
}
- if (stream_stop) {
- active = false;
- set_physics_process_internal(false);
- setplay = -1;
- }
-
output_ready = false;
- stream_fade_in = false;
- stream_fade_out = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
}
float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
@@ -663,7 +657,6 @@ float AudioStreamPlayer3D::get_pitch_scale() const {
void AudioStreamPlayer3D::play(float p_from_pos) {
if (stream_playback.is_valid()) {
- stream_stop = false;
active = true;
setplay = p_from_pos;
output_ready = false;
@@ -681,8 +674,9 @@ void AudioStreamPlayer3D::seek(float p_seconds) {
void AudioStreamPlayer3D::stop() {
if (stream_playback.is_valid()) {
- stream_stop = true;
- stream_fade_out = true;
+ active = false;
+ set_physics_process_internal(false);
+ setplay = -1;
}
}
@@ -878,8 +872,8 @@ void AudioStreamPlayer3D::set_stream_paused(bool p_pause) {
if (p_pause != stream_paused) {
stream_paused = p_pause;
- stream_fade_in = stream_paused ? false : true;
- stream_fade_out = stream_paused ? true : false;
+ stream_paused_fade_in = stream_paused ? false : true;
+ stream_paused_fade_out = stream_paused ? true : false;
}
}
@@ -1024,9 +1018,8 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() {
out_of_range_mode = OUT_OF_RANGE_MIX;
doppler_tracking = DOPPLER_TRACKING_DISABLED;
stream_paused = false;
- stream_fade_in = false;
- stream_fade_out = false;
- stream_stop = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
velocity_tracker.instance();
AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index ad83c47afc..98bc74b2e4 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -110,9 +110,8 @@ private:
float pitch_scale;
bool autoplay;
bool stream_paused;
- bool stream_fade_in;
- bool stream_fade_out;
- bool stream_stop;
+ bool stream_paused_fade_in;
+ bool stream_paused_fade_out;
StringName bus;
void _mix_audio();
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index f542b021be..fc46cf5bdb 100644
--- a/scene/3d/collision_object.cpp
+++ b/scene/3d/collision_object.cpp
@@ -259,9 +259,9 @@ void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &
s.index = total_subshapes;
s.shape = p_shape;
if (area) {
- PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform);
+ PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
} else {
- PhysicsServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform);
+ PhysicsServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
}
sd.shapes.push_back(s);
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index 190967d76c..84078911cb 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -173,7 +173,7 @@ void PathFollow::_update_transform() {
float dot = t_prev.dot(t_cur);
float angle = Math::acos(CLAMP(dot, -1, 1));
- if (likely(Math::abs(angle) > CMP_EPSILON)) {
+ if (likely(!Math::is_zero_approx(angle))) {
if (rotation_mode == ROTATION_Y) {
// assuming we're referring to global Y-axis. is this correct?
axis.x = 0;
@@ -184,7 +184,7 @@ void PathFollow::_update_transform() {
// all components are allowed
}
- if (likely(axis.length() > CMP_EPSILON)) {
+ if (likely(!Math::is_zero_approx(axis.length()))) {
t.rotate_basis(axis.normalized(), angle);
}
}
@@ -193,7 +193,7 @@ void PathFollow::_update_transform() {
float tilt_angle = c->interpolate_baked_tilt(o);
Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct??
- if (likely(Math::abs(tilt_angle) > CMP_EPSILON)) {
+ if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) {
if (rotation_mode == ROTATION_Y) {
tilt_axis.x = 0;
tilt_axis.z = 0;
@@ -203,7 +203,7 @@ void PathFollow::_update_transform() {
// all components are allowed
}
- if (likely(tilt_axis.length() > CMP_EPSILON)) {
+ if (likely(!Math::is_zero_approx(tilt_axis.length()))) {
t.rotate_basis(tilt_axis.normalized(), tilt_angle);
}
}
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index d6a0595519..909d4fda34 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -405,7 +405,7 @@ String SoftBody::get_configuration_warning() const {
if (!warning.empty())
warning += "\n\n";
- warning += TTR("This body will be ignored until you set a mesh");
+ warning += TTR("This body will be ignored until you set a mesh.");
}
Transform t = get_transform();
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index 395f7b9b35..05fd984f93 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -676,8 +676,7 @@ void Spatial::set_identity() {
void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) {
- Transform lookat;
- lookat.origin = get_global_transform().origin;
+ Transform lookat(get_global_transform());
if (lookat.origin == p_target) {
ERR_EXPLAIN("Node origin and target are in the same position, look_at() failed");
ERR_FAIL();
@@ -687,7 +686,10 @@ void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) {
ERR_EXPLAIN("Up vector and direction between node origin and target are aligned, look_at() failed");
ERR_FAIL();
}
+ Vector3 original_scale(lookat.basis.get_scale());
lookat = lookat.looking_at(p_target, p_up);
+ // as basis was normalized, we just need to apply original scale back
+ lookat.basis.scale(original_scale);
set_global_transform(lookat);
}
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 750ed97ae6..75b419ca58 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -835,7 +835,7 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
for (int i = 0; i < 3; i++) {
- if (ABS(light_axis[i]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[i]))
continue;
clip[clip_planes].normal[i] = 1.0;
@@ -978,7 +978,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
for (int c = 0; c < 3; c++) {
- if (ABS(light_axis[c]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;
@@ -1113,7 +1113,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
for (int c = 0; c < 3; c++) {
- if (ABS(light_axis[c]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 47278b8fc1..144e58d8b9 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -32,33 +32,10 @@
#include "core/engine.h"
-void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
-
- int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
-
- //get data
- AudioFrame *buffer = mix_buffer.ptrw();
- int buffer_size = mix_buffer.size();
-
- if (p_fadeout) {
- // Short fadeout ramp
- buffer_size = MIN(buffer_size, 128);
- }
-
- stream_playback->mix(buffer, pitch_scale, buffer_size);
-
- //multiply volume interpolating to avoid clicks if this changes
- float target_volume = p_fadeout ? -80.0 : volume_db;
- float vol = Math::db2linear(mix_volume_db);
- float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size);
- for (int i = 0; i < buffer_size; i++) {
- buffer[i] *= vol;
- vol += vol_inc;
- }
+void AudioStreamPlayer::_mix_to_bus(const AudioFrame *p_frames,int p_amount) {
- //set volume for next mix
- mix_volume_db = target_volume;
+ int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
AudioFrame *targets[4] = { NULL, NULL, NULL, NULL };
@@ -83,42 +60,84 @@ void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
for (int c = 0; c < 4; c++) {
if (!targets[c])
break;
- for (int i = 0; i < buffer_size; i++) {
- targets[c][i] += buffer[i];
+ for (int i = 0; i < p_amount; i++) {
+ targets[c][i] += p_frames[i];
}
}
}
+
+void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
+
+
+ //get data
+ AudioFrame *buffer = mix_buffer.ptrw();
+ int buffer_size = mix_buffer.size();
+
+ if (p_fadeout) {
+ // Short fadeout ramp
+ buffer_size = MIN(buffer_size, 128);
+ }
+
+ stream_playback->mix(buffer, pitch_scale, buffer_size);
+
+ //multiply volume interpolating to avoid clicks if this changes
+ float target_volume = p_fadeout ? -80.0 : volume_db;
+ float vol = Math::db2linear(mix_volume_db);
+ float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size);
+
+ for (int i = 0; i < buffer_size; i++) {
+ buffer[i] *= vol;
+ vol += vol_inc;
+ }
+
+ //set volume for next mix
+ mix_volume_db = target_volume;
+
+ _mix_to_bus(buffer,buffer_size);
+
+}
+
void AudioStreamPlayer::_mix_audio() {
+ if (use_fadeout) {
+ _mix_to_bus(fadeout_buffer.ptr(),fadeout_buffer.size());
+ use_fadeout=false;
+ }
+
if (!stream_playback.is_valid() || !active ||
- (stream_paused && !stream_fade)) {
+ (stream_paused && !stream_paused_fade)) {
return;
}
- if (stream_fade) {
- _mix_internal(true);
- stream_fade = false;
-
- if (stream_stop) {
- stream_playback->stop();
- active = false;
- set_process_internal(false);
+ if (stream_paused) {
+ if (stream_paused_fade) {
+ _mix_internal(true);
+ stream_paused_fade = false;
}
return;
}
- if (setseek >= 0.0) {
+ if (setstop) {
+ _mix_internal(true);
+ stream_playback->stop();
+ setstop=false;
+ }
+
+ if (setseek >= 0.0 && !stop_has_priority) {
if (stream_playback->is_playing()) {
//fade out to avoid pops
_mix_internal(true);
}
+
stream_playback->start(setseek);
setseek = -1.0; //reset seek
mix_volume_db = volume_db; //reset ramp
}
+ stop_has_priority = false;
+
_mix_internal(false);
}
@@ -135,7 +154,7 @@ void AudioStreamPlayer::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
if (!active || (setseek < 0 && !stream_playback->is_playing())) {
- active = false;
+ active = false;
set_process_internal(false);
emit_signal("finished");
}
@@ -162,6 +181,28 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
AudioServer::get_singleton()->lock();
+ if (active && stream_playback.is_valid() && !stream_paused) {
+ //changing streams out of the blue is not a great idea, but at least
+ //lets try to somehow avoid a click
+
+ AudioFrame *buffer = fadeout_buffer.ptrw();
+ int buffer_size = fadeout_buffer.size();
+
+ stream_playback->mix(buffer, pitch_scale, buffer_size);
+
+ //multiply volume interpolating to avoid clicks if this changes
+ float target_volume = -80.0;
+ float vol = Math::db2linear(mix_volume_db);
+ float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size);
+
+ for (int i = 0; i < buffer_size; i++) {
+ buffer[i] *= vol;
+ vol += vol_inc;
+ }
+
+ use_fadeout=true;
+ }
+
mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
if (stream_playback.is_valid()) {
@@ -169,6 +210,7 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
stream.unref();
active = false;
setseek = -1;
+ setstop = false;
}
if (p_stream.is_valid()) {
@@ -209,8 +251,8 @@ void AudioStreamPlayer::play(float p_from_pos) {
if (stream_playback.is_valid()) {
//mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks
- stream_stop = false;
setseek = p_from_pos;
+ stop_has_priority=false;
active = true;
set_process_internal(true);
}
@@ -225,16 +267,16 @@ void AudioStreamPlayer::seek(float p_seconds) {
void AudioStreamPlayer::stop() {
- if (stream_playback.is_valid()) {
- stream_stop = true;
- stream_fade = true;
+ if (stream_playback.is_valid() && active) {
+ setstop=true;
+ stop_has_priority=true;
}
}
bool AudioStreamPlayer::is_playing() const {
if (stream_playback.is_valid()) {
- return active; //&& stream_playback->is_playing();
+ return active && !setstop; //&& stream_playback->is_playing();
}
return false;
@@ -301,7 +343,7 @@ void AudioStreamPlayer::set_stream_paused(bool p_pause) {
if (p_pause != stream_paused) {
stream_paused = p_pause;
- stream_fade = p_pause ? true : false;
+ stream_paused_fade = p_pause ? true : false;
}
}
@@ -315,7 +357,7 @@ void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
if (property.name == "bus") {
String options;
- for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ for (int i = 0; i <AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0)
options += ",";
String name = AudioServer::get_singleton()->get_bus_name(i);
@@ -397,9 +439,11 @@ AudioStreamPlayer::AudioStreamPlayer() {
setseek = -1;
active = false;
stream_paused = false;
- stream_fade = false;
- stream_stop = false;
+ stream_paused_fade = false;
mix_target = MIX_TARGET_STEREO;
+ fadeout_buffer.resize(512);
+ setstop=false;
+ use_fadeout=false;
AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
}
diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h
index 590bef95b0..0b782b67e7 100644
--- a/scene/audio/audio_stream_player.h
+++ b/scene/audio/audio_stream_player.h
@@ -49,17 +49,20 @@ private:
Ref<AudioStreamPlayback> stream_playback;
Ref<AudioStream> stream;
Vector<AudioFrame> mix_buffer;
+ Vector<AudioFrame> fadeout_buffer;
+ bool use_fadeout;
volatile float setseek;
volatile bool active;
+ volatile bool setstop;
+ volatile bool stop_has_priority;
float mix_volume_db;
float pitch_scale;
float volume_db;
bool autoplay;
bool stream_paused;
- bool stream_fade;
- bool stream_stop;
+ bool stream_paused_fade;
StringName bus;
MixTarget mix_target;
@@ -72,6 +75,7 @@ private:
bool _is_active() const;
void _bus_layout_changed();
+ void _mix_to_bus(const AudioFrame *p_frames, int p_amount);
protected:
void _validate_property(PropertyInfo &property) const;
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index d68cdd5f8d..f808d6c234 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -282,10 +282,7 @@ void BaseButton::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
}
- if (p_what == NOTIFICATION_EXIT_TREE) {
- }
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED && !is_visible_in_tree()) {
+ if (p_what == NOTIFICATION_EXIT_TREE || (p_what == NOTIFICATION_VISIBILITY_CHANGED && !is_visible_in_tree())) {
if (!toggle_mode) {
status.pressed = false;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index c78f29dd50..bca3471091 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -38,8 +38,6 @@
#include "editor_scale.h"
#include "editor_settings.h"
#endif
-
-#include "scene/gui/separator.h"
#include "scene/main/viewport.h"
void ColorPicker::_notification(int p_what) {
@@ -469,7 +467,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
set_pick_color(presets[index]);
_update_color();
emit_signal("color_changed", color);
- } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT) {
+ } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) {
int index = bev->get_position().x / (preset->get_size().x / presets.size());
Color clicked_preset = presets[index];
erase_preset(clicked_preset);
@@ -565,6 +563,31 @@ void ColorPicker::_html_focus_exit() {
_focus_exit();
}
+void ColorPicker::set_presets_enabled(bool p_enabled) {
+ presets_enabled = p_enabled;
+ if (!p_enabled) {
+ bt_add_preset->set_disabled(true);
+ bt_add_preset->set_focus_mode(FOCUS_NONE);
+ } else {
+ bt_add_preset->set_disabled(false);
+ bt_add_preset->set_focus_mode(FOCUS_ALL);
+ }
+}
+
+bool ColorPicker::are_presets_enabled() const {
+ return presets_enabled;
+}
+
+void ColorPicker::set_presets_visible(bool p_visible) {
+ presets_visible = p_visible;
+ preset_separator->set_visible(p_visible);
+ preset_container->set_visible(p_visible);
+}
+
+bool ColorPicker::are_presets_visible() const {
+ return presets_visible;
+}
+
void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color);
@@ -575,6 +598,10 @@ void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_deferred_mode"), &ColorPicker::is_deferred_mode);
ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha);
ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha);
+ ClassDB::bind_method(D_METHOD("set_presets_enabled", "enabled"), &ColorPicker::set_presets_enabled);
+ ClassDB::bind_method(D_METHOD("are_presets_enabled"), &ColorPicker::are_presets_enabled);
+ ClassDB::bind_method(D_METHOD("set_presets_visible", "visible"), &ColorPicker::set_presets_visible);
+ ClassDB::bind_method(D_METHOD("are_presets_visible"), &ColorPicker::are_presets_visible);
ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset);
ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset);
ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets);
@@ -598,6 +625,8 @@ void ColorPicker::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible"), "set_presets_visible", "are_presets_visible");
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("preset_added", PropertyInfo(Variant::COLOR, "color")));
@@ -613,6 +642,8 @@ ColorPicker::ColorPicker() :
raw_mode_enabled = false;
deferred_mode_enabled = false;
changing_color = false;
+ presets_enabled = true;
+ presets_visible = true;
screen = NULL;
HBoxContainer *hb_smpl = memnew(HBoxContainer);
@@ -725,18 +756,19 @@ ColorPicker::ColorPicker() :
set_pick_color(Color(1, 1, 1));
- add_child(memnew(HSeparator));
+ preset_separator = memnew(HSeparator);
+ add_child(preset_separator);
- HBoxContainer *bbc = memnew(HBoxContainer);
- add_child(bbc);
+ preset_container = memnew(HBoxContainer);
+ add_child(preset_container);
preset = memnew(TextureRect);
- bbc->add_child(preset);
+ preset_container->add_child(preset);
preset->connect("gui_input", this, "_preset_input");
preset->connect("draw", this, "_update_presets");
bt_add_preset = memnew(Button);
- bbc->add_child(bt_add_preset);
+ preset_container->add_child(bt_add_preset);
bt_add_preset->set_tooltip(TTR("Add current color as a preset."));
bt_add_preset->connect("pressed", this, "_add_preset_pressed");
}
@@ -758,23 +790,33 @@ void ColorPickerButton::_modal_closed() {
void ColorPickerButton::pressed() {
_update_picker();
- popup->set_position(get_global_position() - picker->get_combined_minimum_size());
+ popup->set_position(get_global_position() - picker->get_combined_minimum_size() * get_global_transform().get_scale());
+ popup->set_scale(get_global_transform().get_scale());
popup->popup();
picker->set_focus_on_line_edit();
}
void ColorPickerButton::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
+ switch (p_what) {
+ case NOTIFICATION_DRAW: {
- Ref<StyleBox> normal = get_stylebox("normal");
- Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
- draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
- draw_rect(r, color);
+ Ref<StyleBox> normal = get_stylebox("normal");
+ Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
+ draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
+ draw_rect(r, color);
+ } break;
+ case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
+
+ if (popup)
+ popup->hide();
+ } break;
}
- if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST && popup) {
- popup->hide();
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ if (popup && !is_visible_in_tree()) {
+ popup->hide();
+ }
}
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index b78844839a..b5ddf2d0c2 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -37,6 +37,7 @@
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/popup.h"
+#include "scene/gui/separator.h"
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
#include "scene/gui/texture_rect.h"
@@ -52,6 +53,8 @@ private:
Control *w_edit;
TextureRect *sample;
TextureRect *preset;
+ HBoxContainer *preset_container;
+ HSeparator *preset_separator;
Button *bt_add_preset;
List<Color> presets;
ToolButton *btn_pick;
@@ -70,6 +73,8 @@ private:
bool deferred_mode_enabled;
bool updating;
bool changing_color;
+ bool presets_enabled;
+ bool presets_visible;
float h, s, v;
Color last_hsv;
@@ -114,6 +119,12 @@ public:
void set_deferred_mode(bool p_enabled);
bool is_deferred_mode() const;
+ void set_presets_enabled(bool p_enabled);
+ bool are_presets_enabled() const;
+
+ void set_presets_visible(bool p_visible);
+ bool are_presets_visible() const;
+
void set_focus_on_line_edit();
ColorPicker();
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 30ad81bb2e..dabff08fea 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -1053,7 +1053,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) {
- if (ABS(E->get().activity - p_activity) < CMP_EPSILON) {
+ if (Math::is_equal_approx(E->get().activity, p_activity)) {
//update only if changed
top_layer->update();
connections_layer->update();
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 026374ded1..f5e979e9e6 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -369,6 +369,7 @@ void ItemList::clear() {
update();
shape_changed = true;
defer_select_single = -1;
+ scroll_bar->set_value(0);
}
void ItemList::set_fixed_column_width(int p_size) {
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 1e8d73b6a4..d889c8d8b8 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -56,6 +56,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
menu->set_position(get_global_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
+ menu->set_scale(get_global_transform().get_scale());
menu->popup();
grab_focus();
return;
@@ -1327,7 +1328,27 @@ void LineEdit::select_all() {
void LineEdit::set_editable(bool p_editable) {
+ if (editable == p_editable)
+ return;
+
editable = p_editable;
+
+ // Reorganize context menu.
+ menu->clear();
+ if (editable)
+ menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
+ menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
+ if (editable)
+ menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
+ menu->add_separator();
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
+ if (editable) {
+ 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);
+ }
+
update();
}
@@ -1623,7 +1644,6 @@ LineEdit::LineEdit() {
deselect();
set_focus_mode(FOCUS_ALL);
- editable = true;
set_default_cursor_shape(CURSOR_IBEAM);
set_mouse_filter(MOUSE_FILTER_STOP);
@@ -1638,15 +1658,7 @@ LineEdit::LineEdit() {
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
- menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
- menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
- menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
- menu->add_separator();
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
- 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);
+ set_editable(true);
menu->connect("id_pressed", this, "menu_option");
expand_to_text_length = false;
}
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index a011b793de..e12cd55e6f 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -55,8 +55,9 @@ void MenuButton::pressed() {
Size2 size = get_size();
Point2 gp = get_global_position();
- popup->set_global_position(gp + Size2(0, size.height));
+ popup->set_global_position(gp + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
+ popup->set_scale(get_global_transform().get_scale());
popup->set_parent_rect(Rect2(Point2(gp - popup->get_global_position()), get_size()));
popup->popup();
}
@@ -91,6 +92,16 @@ bool MenuButton::is_switch_on_hover() {
return switch_on_hover;
}
+void MenuButton::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (!is_visible_in_tree()) {
+ popup->hide();
+ }
+ }
+}
+
void MenuButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_popup"), &MenuButton::get_popup);
@@ -125,7 +136,6 @@ MenuButton::MenuButton() {
popup = memnew(PopupMenu);
popup->hide();
add_child(popup);
- popup->set_as_toplevel(true);
popup->set_pass_on_modal_close_click(false);
popup->connect("about_to_show", this, "set_pressed", varray(true)); // For when switching from another MenuButton.
popup->connect("popup_hide", this, "set_pressed", varray(false));
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index 794840035e..42e909d991 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -52,6 +52,7 @@ class MenuButton : public Button {
void _gui_input(Ref<InputEvent> p_event);
protected:
+ void _notification(int p_what);
static void _bind_methods();
public:
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index cb5fb0263b..7238543a14 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -72,6 +72,11 @@ void OptionButton::_notification(int p_what) {
Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2)));
arrow->draw(ci, ofs, clr);
+ } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (!is_visible_in_tree()) {
+ popup->hide();
+ }
}
}
@@ -104,9 +109,9 @@ void OptionButton::_selected(int p_which) {
void OptionButton::pressed() {
Size2 size = get_size();
- popup->set_global_position(get_global_position() + Size2(0, size.height));
+ popup->set_global_position(get_global_position() + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
-
+ popup->set_scale(get_global_transform().get_scale());
popup->popup();
}
@@ -347,8 +352,8 @@ OptionButton::OptionButton() {
popup = memnew(PopupMenu);
popup->hide();
add_child(popup);
- popup->set_as_toplevel(true);
popup->set_pass_on_modal_close_click(false);
+ popup->set_notify_transform(true);
popup->connect("id_pressed", this, "_selected");
popup->connect("id_focused", this, "_focused");
popup->connect("popup_hide", this, "set_pressed", varray(false));
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 80ec7049fc..b7601bdd3e 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -65,7 +65,7 @@ void Popup::_notification(int p_what) {
void Popup::_fix_size() {
Point2 pos = get_global_position();
- Size2 size = get_size();
+ Size2 size = get_size() * get_scale();
Point2 window_size = get_viewport_rect().size;
if (pos.x + size.width > window_size.width)
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 23c61f37d6..8825891807 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -54,9 +54,11 @@ Size2 PopupMenu::get_minimum_size() const {
Ref<Font> font = get_font("font");
float max_w = 0;
+ float icon_w = 0;
int font_h = font->get_height();
- int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width());
+ int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation;
int accel_max_w = 0;
+ bool has_check = false;
for (int i = 0; i < items.size(); i++) {
@@ -65,8 +67,7 @@ Size2 PopupMenu::get_minimum_size() const {
Size2 icon_size = items[i].icon->get_size();
size.height = MAX(icon_size.height, font_h);
- size.width += icon_size.width;
- size.width += hseparation;
+ icon_w = MAX(icon_size.width + hseparation, icon_w);
} else {
size.height = font_h;
@@ -74,10 +75,8 @@ Size2 PopupMenu::get_minimum_size() const {
size.width += items[i].h_ofs;
- if (items[i].checkable_type) {
-
- size.width += check_w + hseparation;
- }
+ if (items[i].checkable_type)
+ has_check = true;
String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text;
size.width += font->get_string_size(text).width;
@@ -91,13 +90,14 @@ Size2 PopupMenu::get_minimum_size() const {
accel_max_w = MAX(accel_w, accel_max_w);
}
- if (items[i].submenu != "") {
-
+ if (items[i].submenu != "")
size.width += get_icon("submenu")->get_width();
- }
+
+ if (has_check)
+ size.width += check_w;
+ max_w = MAX(max_w, size.width + icon_w);
minsize.height += size.height;
- max_w = MAX(max_w, size.width);
}
minsize.width += max_w + accel_max_w;
@@ -147,10 +147,10 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
void PopupMenu::_activate_submenu(int over) {
Node *n = get_node(items[over].submenu);
- ERR_EXPLAIN("item subnode does not exist: " + items[over].submenu);
+ ERR_EXPLAIN("Item subnode does not exist: " + items[over].submenu);
ERR_FAIL_COND(!n);
Popup *pm = Object::cast_to<Popup>(n);
- ERR_EXPLAIN("item subnode is not a Popup: " + items[over].submenu);
+ ERR_EXPLAIN("Item subnode is not a Popup: " + items[over].submenu);
ERR_FAIL_COND(!pm);
if (pm->is_visible_in_tree())
return; //already visible!
@@ -159,13 +159,14 @@ void PopupMenu::_activate_submenu(int over) {
Rect2 pr(p, get_size());
Ref<StyleBox> style = get_stylebox("panel");
- Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y);
+ Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y) * get_global_transform().get_scale();
Size2 size = pm->get_size();
// fix pos
if (pos.x + size.width > get_viewport_rect().size.width)
pos.x = p.x - size.width;
pm->set_position(pos);
+ pm->set_scale(get_global_transform().get_scale());
pm->popup();
PopupMenu *pum = Object::cast_to<PopupMenu>(pm);
@@ -196,11 +197,11 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
int vseparation = get_constant("vseparation");
Ref<Font> font = get_font("font");
- float dy = (vseparation + font->get_height()) * 3 * p_factor;
+ float dy = (vseparation + font->get_height()) * 3 * p_factor * get_global_transform().get_scale().y;
if (dy > 0 && global_y < 0)
dy = MIN(dy, -global_y - 1);
- else if (dy < 0 && global_y + get_size().y > get_viewport_rect().size.y)
- dy = -MIN(-dy, global_y + get_size().y - get_viewport_rect().size.y - 1);
+ else if (dy < 0 && global_y + get_size().y * get_global_transform().get_scale().y > get_viewport_rect().size.y)
+ dy = -MIN(-dy, global_y + get_size().y * get_global_transform().get_scale().y - get_viewport_rect().size.y - 1);
set_position(get_position() + Vector2(0, dy));
Ref<InputEventMouseMotion> ie;
@@ -289,7 +290,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
case BUTTON_WHEEL_DOWN: {
- if (get_global_position().y + get_size().y > get_viewport_rect().size.y) {
+ if (get_global_position().y + get_size().y * get_global_transform().get_scale().y > get_viewport_rect().size.y) {
_scroll(-b->get_factor(), b->get_position());
}
} break;
@@ -415,7 +416,6 @@ void PopupMenu::_notification(int p_what) {
minimum_size_changed();
update();
-
} break;
case NOTIFICATION_DRAW: {
@@ -443,15 +443,31 @@ void PopupMenu::_notification(int p_what) {
Color font_color_hover = get_color("font_color_hover");
float font_h = font->get_height();
+ // Add the check and the wider icon to the offset of all items.
+ float icon_ofs = 0.0;
+ bool has_check = false;
+ for (int i = 0; i < items.size(); i++) {
+
+ if (!items[i].icon.is_null())
+ icon_ofs = MAX(items[i].icon->get_size().height, icon_ofs);
+
+ if (items[i].checkable_type)
+ has_check = true;
+ }
+ if (icon_ofs > 0.0)
+ icon_ofs += hseparation;
+
+ float check_ofs = 0.0;
+ if (has_check)
+ check_ofs = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation;
+
for (int i = 0; i < items.size(); i++) {
if (i > 0)
ofs.y += vseparation;
Point2 item_ofs = ofs;
- float h;
Size2 icon_size;
-
- Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+ float h;
if (!items[i].icon.is_null()) {
@@ -489,16 +505,15 @@ void PopupMenu::_notification(int p_what) {
}
}
+ Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+
if (items[i].checkable_type) {
Texture *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color);
- item_ofs.x += icon->get_width() + hseparation;
}
if (!items[i].icon.is_null()) {
- items[i].icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
- item_ofs.x += items[i].icon->get_width();
- item_ofs.x += hseparation;
+ items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
}
if (items[i].submenu != "") {
@@ -514,6 +529,7 @@ void PopupMenu::_notification(int p_what) {
}
} else {
+ item_ofs.x += icon_ofs + check_ofs;
font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color));
}
@@ -528,7 +544,6 @@ void PopupMenu::_notification(int p_what) {
ofs.y += h;
}
-
} break;
case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index d6b5c0b82d..101eb2ac88 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -753,6 +753,8 @@ void RichTextLabel::_scroll_changed(double) {
else
scroll_following = false;
+ scroll_updated = true;
+
update();
}
@@ -778,7 +780,6 @@ void RichTextLabel::_update_scroll() {
main->first_invalid_line = 0; //invalidate ALL
_validate_line_caches(main);
}
- scroll_updated = true;
}
void RichTextLabel::_notification(int p_what) {
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index ad41cc4167..6997c2809c 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -86,8 +86,8 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
emit_signal("pre_popup_pressed");
Vector2 popup_pos = get_global_position();
- popup_pos.x += size.width - popup->get_size().width;
- popup_pos.y += menu->get_height();
+ popup_pos.x += size.width * get_global_transform().get_scale().x - popup->get_size().width * popup->get_global_transform().get_scale().x;
+ popup_pos.y += menu->get_height() * get_global_transform().get_scale().y;
popup->set_global_position(popup_pos);
popup->popup();
@@ -350,6 +350,7 @@ void TabContainer::_notification(int p_what) {
}
} break;
case NOTIFICATION_THEME_CHANGED: {
+
minimum_size_changed();
call_deferred("_on_theme_changed"); //wait until all changed theme
} break;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 1f498ea16e..fbf6550362 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -988,6 +988,24 @@ void TextEdit::_notification(int p_what) {
draw_texture_rect(info_icon, Rect2(icon_pos, icon_size));
}
+ // draw execution marker
+ if (executing_line == line) {
+ if (draw_breakpoint_gutter) {
+ int icon_extra_size = 4;
+ int vertical_gap = (get_row_height() * 40) / 100;
+ int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100;
+ int marker_height = get_row_height() - (vertical_gap * 2) + icon_extra_size;
+ int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2) + icon_extra_size;
+ cache.executing_icon->draw_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 - icon_extra_size / 2, ofs_y + vertical_gap - icon_extra_size / 2, marker_width, marker_height), false, Color(cache.executing_line_color.r, cache.executing_line_color.g, cache.executing_line_color.b));
+ } else {
+#ifdef TOOLS_ENABLED
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.executing_line_color);
+#else
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.executing_line_color);
+#endif
+ }
+ }
+
// draw fold markers
if (draw_fold_gutter) {
int horizontal_gap = (cache.fold_gutter_width * 30) / 100;
@@ -2009,6 +2027,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
menu->set_position(get_global_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
+ menu->set_scale(get_global_transform().get_scale());
menu->popup();
grab_focus();
}
@@ -4344,7 +4363,27 @@ void TextEdit::clear() {
void TextEdit::set_readonly(bool p_readonly) {
+ if (readonly == p_readonly)
+ return;
+
readonly = p_readonly;
+
+ // Reorganize context menu.
+ menu->clear();
+ if (!readonly)
+ menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
+ menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
+ if (!readonly)
+ menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
+ menu->add_separator();
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
+ if (!readonly) {
+ 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);
+ }
+
update();
}
@@ -4414,6 +4453,7 @@ void TextEdit::_update_caches() {
cache.current_line_color = get_color("current_line_color");
cache.line_length_guideline_color = get_color("line_length_guideline_color");
cache.breakpoint_color = get_color("breakpoint_color");
+ cache.executing_line_color = get_color("executing_line_color");
cache.code_folding_color = get_color("code_folding_color");
cache.brace_mismatch_color = get_color("brace_mismatch_color");
cache.word_highlighted_color = get_color("word_highlighted_color");
@@ -4428,9 +4468,10 @@ void TextEdit::_update_caches() {
#endif
cache.row_height = cache.font->get_height() + cache.line_spacing;
cache.tab_icon = get_icon("tab");
- cache.folded_icon = get_icon("GuiTreeArrowRight", "EditorIcons");
- cache.can_fold_icon = get_icon("GuiTreeArrowDown", "EditorIcons");
+ cache.folded_icon = get_icon("folded");
+ cache.can_fold_icon = get_icon("fold");
cache.folded_eol_icon = get_icon("GuiEllipsis", "EditorIcons");
+ cache.executing_icon = get_icon("MainPlay", "EditorIcons");
text.set_font(cache.font);
if (syntax_highlighter) {
@@ -4996,6 +5037,17 @@ bool TextEdit::is_line_set_as_safe(int p_line) const {
return text.is_safe(p_line);
}
+void TextEdit::set_executing_line(int p_line) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ executing_line = p_line;
+ update();
+}
+
+void TextEdit::clear_executing_line() {
+ executing_line = -1;
+ update();
+}
+
bool TextEdit::is_line_set_as_breakpoint(int p_line) const {
ERR_FAIL_INDEX_V(p_line, text.size(), false);
@@ -5415,6 +5467,9 @@ void TextEdit::undo() {
TextOperation op = undo_stack_pos->get();
_do_text_op(op, true);
+ if (op.from_line != op.to_line || op.to_column != op.from_column + 1)
+ select(op.from_line, op.from_column, op.to_line, op.to_column);
+
current_op.version = op.prev_version;
if (undo_stack_pos->get().chain_backward) {
while (true) {
@@ -5541,6 +5596,7 @@ int TextEdit::get_indent_size() {
void TextEdit::set_draw_tabs(bool p_draw) {
draw_tabs = p_draw;
+ update();
}
bool TextEdit::is_drawing_tabs() const {
@@ -5727,19 +5783,29 @@ void TextEdit::_confirm_completion() {
cursor_set_column(cursor.column - completion_base.length(), false);
insert_text_at_cursor(completion_current);
- // When inserted into the middle of an existing string, don't add an unnecessary quote
+ // When inserted into the middle of an existing string/method, don't add an unnecessary quote/bracket.
String line = text[cursor.line];
CharType next_char = line[cursor.column];
CharType last_completion_char = completion_current[completion_current.length() - 1];
- if ((last_completion_char == '"' || last_completion_char == '\'') &&
- last_completion_char == next_char) {
+ if ((last_completion_char == '"' || last_completion_char == '\'') && last_completion_char == next_char) {
_base_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
}
- if (last_completion_char == '(' && auto_brace_completion_enabled) {
- insert_text_at_cursor(")");
- cursor.column--;
+ if (last_completion_char == '(') {
+
+ if (next_char == last_completion_char) {
+ _base_remove_text(cursor.line, cursor.column - 1, cursor.line, cursor.column);
+ } else if (auto_brace_completion_enabled) {
+ insert_text_at_cursor(")");
+ cursor.column--;
+ }
+ } else if (last_completion_char == ')' && next_char == '(') {
+
+ _base_remove_text(cursor.line, cursor.column - 2, cursor.line, cursor.column);
+ if (line[cursor.column + 1] != ')') {
+ cursor.column--;
+ }
}
end_complex_operation();
@@ -5783,6 +5849,7 @@ void TextEdit::_update_completion_candidates() {
bool inquote = false;
int first_quote = -1;
+ int restore_quotes = -1;
int c = cofs - 1;
while (c >= 0) {
@@ -5790,6 +5857,11 @@ void TextEdit::_update_completion_candidates() {
inquote = !inquote;
if (first_quote == -1)
first_quote = c;
+ restore_quotes = 0;
+ } else if (restore_quotes == 0 && l[c] == '$') {
+ restore_quotes = 1;
+ } else if (restore_quotes == 0 && !_is_whitespace(l[c])) {
+ restore_quotes = -1;
}
c--;
}
@@ -5857,6 +5929,11 @@ void TextEdit::_update_completion_candidates() {
completion_strings.write[i] = completion_strings[i].unquote().quote("'");
}
+ if (inquote && restore_quotes == 1 && !completion_strings[i].is_quoted()) {
+ String quote = single_quote ? "'" : "\"";
+ completion_strings.write[i] = completion_strings[i].quote(quote);
+ }
+
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())) {
@@ -5934,7 +6011,6 @@ void TextEdit::code_complete(const Vector<String> &p_strings, bool p_forced) {
completion_current = "";
completion_index = 0;
_update_completion_candidates();
- //
}
String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
@@ -6259,8 +6335,12 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_show_line_numbers", "enable"), &TextEdit::set_show_line_numbers);
ClassDB::bind_method(D_METHOD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled);
+ ClassDB::bind_method(D_METHOD("set_draw_tabs"), &TextEdit::set_draw_tabs);
+ ClassDB::bind_method(D_METHOD("is_drawing_tabs"), &TextEdit::is_drawing_tabs);
ClassDB::bind_method(D_METHOD("set_breakpoint_gutter_enabled", "enable"), &TextEdit::set_breakpoint_gutter_enabled);
ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled);
+ ClassDB::bind_method(D_METHOD("set_draw_fold_gutter"), &TextEdit::set_draw_fold_gutter);
+ ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &TextEdit::is_drawing_fold_gutter);
ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled);
ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled);
@@ -6307,7 +6387,9 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_tabs"), "set_draw_tabs", "is_drawing_tabs");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "breakpoint_gutter"), "set_breakpoint_gutter_enabled", "is_breakpoint_gutter_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
@@ -6345,7 +6427,6 @@ void TextEdit::_bind_methods() {
TextEdit::TextEdit() {
- readonly = false;
setting_row = false;
draw_tabs = false;
override_selected_font_color = false;
@@ -6460,17 +6541,11 @@ TextEdit::TextEdit() {
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
- menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
- menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
- menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
- menu->add_separator();
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
- 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);
+ set_readonly(false);
menu->connect("id_pressed", this, "menu_option");
first_draw = true;
+
+ executing_line = -1;
}
TextEdit::~TextEdit() {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index e854032159..4badd85e07 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -166,6 +166,7 @@ private:
Ref<Texture> can_fold_icon;
Ref<Texture> folded_icon;
Ref<Texture> folded_eol_icon;
+ Ref<Texture> executing_icon;
Ref<StyleBox> style_normal;
Ref<StyleBox> style_focus;
Ref<StyleBox> style_readonly;
@@ -187,6 +188,7 @@ private:
Color selection_color;
Color mark_color;
Color breakpoint_color;
+ Color executing_line_color;
Color code_folding_color;
Color current_line_color;
Color line_length_guideline_color;
@@ -345,6 +347,8 @@ private:
bool context_menu_enabled;
+ int executing_line;
+
int get_visible_rows() const;
int get_total_visible_rows() const;
@@ -486,6 +490,8 @@ public:
void set_line_as_marked(int p_line, bool p_marked);
void set_line_as_breakpoint(int p_line, bool p_breakpoint);
bool is_line_set_as_breakpoint(int p_line) const;
+ void set_executing_line(int p_line);
+ void clear_executing_line();
void set_line_as_safe(int p_line, bool p_safe);
bool is_line_set_as_safe(int p_line) const;
void get_breakpoints(List<int> *p_breakpoints) const;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index 795b25cce0..b5f949aeb7 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -64,7 +64,7 @@ bool TextureButton::has_point(const Point2 &p_point) const {
Rect2 rect = Rect2();
Size2 mask_size = click_mask->get_size();
- if (_position_rect.no_area()) {
+ if (_position_rect.has_no_area()) {
rect.size = mask_size;
} else if (_tile) {
// if the stretch mode is tile we offset the point to keep it inside the mask size
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index 2195de9694..423794d8ba 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -96,7 +96,7 @@ void TextureRect::_notification(int p_what) {
size.width *= hflip ? -1.0f : 1.0f;
size.height *= vflip ? -1.0f : 1.0f;
- if (region.no_area()) {
+ if (region.has_no_area()) {
draw_texture_rect(texture, Rect2(offset, size), tile);
} else {
draw_texture_rect_region(texture, Rect2(offset, size), region);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 81c38cec89..b81364e2f0 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -369,8 +369,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
}
void SceneTree::call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) {
-
- call_group_flags(0, p_group, VARIANT_ARG_PASS);
+ call_group_flags(0, p_group, p_function, VARIANT_ARG_PASS);
}
void SceneTree::notify_group(const StringName &p_group, int p_notification) {
@@ -1160,7 +1159,7 @@ void SceneTree::_update_root_rect() {
WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'.");
}
- if (stretch_aspect == STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect) < CMP_EPSILON) {
+ if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) {
//same aspect or ignore aspect
viewport_size = desired_res;
screen_size = video_mode;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 52f63ddc1d..ae2c571201 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2482,11 +2482,7 @@ void Viewport::_gui_hid_control(Control *p_control) {
if (gui.mouse_over == p_control)
gui.mouse_over = NULL;
if (gui.tooltip == p_control)
- gui.tooltip = NULL;
- if (gui.tooltip == p_control) {
- gui.tooltip = NULL;
_gui_cancel_tooltip();
- }
}
void Viewport::_gui_remove_control(Control *p_control) {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 9face3e476..47f5b152f0 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -782,7 +782,11 @@ void unregister_scene_types() {
ResourceLoader::remove_resource_format_loader(resource_loader_bmfont);
resource_loader_bmfont.unref();
+ //SpatialMaterial is not initialised when 3D is disabled, so it shouldn't be cleaned up either
+#ifndef _3D_DISABLED
SpatialMaterial::finish_shaders();
+#endif // _3D_DISABLED
+
ParticlesMaterial::finish_shaders();
CanvasItemMaterial::finish_shaders();
SceneStringNames::free();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index e58ec9d71e..9c79b2ba3b 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1477,7 +1477,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const {
middle = (low + high) / 2;
- if (Math::abs(p_time - keys[middle].time) < CMP_EPSILON) { //match
+ if (Math::is_equal_approx(p_time, keys[middle].time)) { //match
return middle;
} else if (p_time < keys[middle].time)
high = middle - 1; //search low end of array
@@ -1680,10 +1680,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol
float delta = p_keys[next].time - p_keys[idx].time;
float from = p_time - p_keys[idx].time;
- if (Math::absf(delta) > CMP_EPSILON)
- c = from / delta;
- else
+ if (Math::is_zero_approx(delta))
c = 0;
+ else
+ c = from / delta;
} else {
@@ -1691,10 +1691,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol
float delta = (length - p_keys[idx].time) + p_keys[next].time;
float from = p_time - p_keys[idx].time;
- if (Math::absf(delta) > CMP_EPSILON)
- c = from / delta;
- else
+ if (Math::is_zero_approx(delta))
c = 0;
+ else
+ c = from / delta;
}
} else {
@@ -1707,10 +1707,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol
float delta = endtime + p_keys[next].time;
float from = endtime + p_time;
- if (Math::absf(delta) > CMP_EPSILON)
- c = from / delta;
- else
+ if (Math::is_zero_approx(delta))
c = 0;
+ else
+ c = from / delta;
}
} else { // no loop
@@ -1723,10 +1723,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol
float delta = p_keys[next].time - p_keys[idx].time;
float from = p_time - p_keys[idx].time;
- if (Math::absf(delta) > CMP_EPSILON)
- c = from / delta;
- else
+ if (Math::is_zero_approx(delta))
c = 0;
+ else
+ c = from / delta;
} else {
@@ -2774,9 +2774,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
const Vector3 &v1 = t1.value.loc;
const Vector3 &v2 = t2.value.loc;
- if (v0.distance_to(v2) < CMP_EPSILON) {
+ if (Math::is_zero_approx(v0.distance_to(v2))) {
//0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1) > CMP_EPSILON) {
+ if (!Math::is_zero_approx(v0.distance_to(v1))) {
//not close, not optimizable
return false;
}
@@ -2813,9 +2813,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
//localize both to rotation from q0
- if ((q0 - q2).length() < CMP_EPSILON) {
+ if (Math::is_zero_approx((q0 - q2).length())) {
- if ((q0 - q1).length() > CMP_EPSILON)
+ if (!Math::is_zero_approx((q0 - q1).length()))
return false;
} else {
@@ -2863,9 +2863,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
const Vector3 &v1 = t1.value.scale;
const Vector3 &v2 = t2.value.scale;
- if (v0.distance_to(v2) < CMP_EPSILON) {
+ if (Math::is_zero_approx(v0.distance_to(v2))) {
//0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1) > CMP_EPSILON) {
+ if (!Math::is_zero_approx(v0.distance_to(v1))) {
//not close, not optimizable
return false;
}
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index f425972183..79d93113b3 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -423,6 +423,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_icon("tab", "TextEdit", make_icon(tab_png));
+ theme->set_icon("folded", "TextEdit", make_icon(arrow_right_png));
+ theme->set_icon("fold", "TextEdit", make_icon(arrow_down_png));
theme->set_font("font", "TextEdit", default_font);
@@ -437,6 +439,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("selection_color", "TextEdit", font_color_selection);
theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4));
theme->set_color("breakpoint_color", "TextEdit", Color(0.8, 0.8, 0.4, 0.2));
+ theme->set_color("executing_line_color", "TextEdit", Color(0.2, 0.8, 0.2, 0.4));
theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8));
theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8));
theme->set_color("caret_color", "TextEdit", control_font_color);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 626ed9f5b4..2c6f30f429 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -535,7 +535,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
float a = value;
float b = original;
- if (Math::abs(a - b) < CMP_EPSILON)
+ if (Math::is_equal_approx(a, b))
continue;
} else if (bool(Variant::evaluate(Variant::OP_EQUAL, value, original))) {
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 21b2893502..5b5968c10f 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -600,6 +600,8 @@ Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask,
}
List<Vector2> coords;
+ List<uint32_t> priorities;
+ uint32_t priority_sum = 0;
uint32_t mask;
uint16_t mask_;
uint16_t mask_ignore;
@@ -613,16 +615,34 @@ Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask,
mask_ignore = mask >> 16;
if (((mask_ & (~mask_ignore)) == (p_bitmask & (~mask_ignore))) && (((~mask_) | mask_ignore) == ((~p_bitmask) | mask_ignore))) {
- for (int i = 0; i < autotile_get_subtile_priority(p_id, E->key()); i++) {
- coords.push_back(E->key());
- }
+ uint32_t priority = autotile_get_subtile_priority(p_id, E->key());
+ priority_sum += priority;
+ priorities.push_back(priority);
+ coords.push_back(E->key());
}
}
if (coords.size() == 0) {
return autotile_get_icon_coordinate(p_id);
} else {
- return coords[Math::rand() % coords.size()];
+ uint32_t picked_value = Math::rand() % priority_sum;
+ uint32_t upper_bound;
+ uint32_t lower_bound = 0;
+ Vector2 result = coords.front()->get();
+ List<Vector2>::Element *coords_E = coords.front();
+ List<uint32_t>::Element *priorities_E = priorities.front();
+ while (priorities_E) {
+ upper_bound = lower_bound + priorities_E->get();
+ if (lower_bound <= picked_value && picked_value < upper_bound) {
+ result = coords_E->get();
+ break;
+ }
+ lower_bound = upper_bound;
+ priorities_E = priorities_E->next();
+ coords_E = coords_E->next();
+ }
+
+ return result;
}
}
diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h
index 8459a82388..9ea59a3961 100644
--- a/servers/arvr/arvr_interface.h
+++ b/servers/arvr/arvr_interface.h
@@ -112,6 +112,7 @@ public:
virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */
virtual void process() = 0;
+ virtual void notification(int p_what) = 0;
ARVRInterface();
~ARVRInterface();
diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp
index 01a52aa01f..46d92336f3 100644
--- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp
+++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp
@@ -130,7 +130,7 @@ Vector2 AudioEffectSpectrumAnalyzerInstance::get_magnitude_for_frequency_range(f
}
uint64_t time = OS::get_singleton()->get_ticks_usec();
float diff = double(time - last_fft_time) / 1000000.0 + base->get_tap_back_pos();
- diff -= AudioServer::get_singleton()->get_output_delay();
+ diff -= AudioServer::get_singleton()->get_output_latency();
float fft_time_size = float(fft_size) / mix_rate;
int fft_index = fft_pos;
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index c83c3029f3..fc3ecedd03 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -68,16 +68,21 @@ void AudioDriver::audio_server_process(int p_frames, int32_t *p_buffer, bool p_u
void AudioDriver::update_mix_time(int p_frames) {
- _mix_amount += p_frames;
+ _last_mix_frames = p_frames;
if (OS::get_singleton())
_last_mix_time = OS::get_singleton()->get_ticks_usec();
}
-double AudioDriver::get_mix_time() const {
+double AudioDriver::get_time_since_last_mix() const {
+
+ return (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0;
+}
+
+double AudioDriver::get_time_to_next_mix() const {
double total = (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0;
- total += _mix_amount / (double)get_mix_rate();
- return total;
+ double mix_buffer = _last_mix_frames / (double)get_mix_rate();
+ return mix_buffer - total;
}
void AudioDriver::input_buffer_init(int driver_buffer_frames) {
@@ -148,7 +153,7 @@ Array AudioDriver::capture_get_device_list() {
AudioDriver::AudioDriver() {
_last_mix_time = 0;
- _mix_amount = 0;
+ _last_mix_frames = 0;
input_position = 0;
input_size = 0;
@@ -281,13 +286,6 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) {
to_mix -= to_copy;
}
- // Calculate latency for Performance.AUDIO_OUTPUT_LATENCY
- if (OS::get_singleton()) {
- uint64_t ticks = OS::get_singleton()->get_ticks_usec();
- output_latency = (ticks - output_latency_ticks) / 1000000.f;
- output_latency_ticks = ticks;
- }
-
#ifdef DEBUG_ENABLED
prof_time += OS::get_singleton()->get_ticks_usec() - prof_ticks;
#endif
@@ -1107,13 +1105,19 @@ AudioServer *AudioServer::get_singleton() {
return singleton;
}
-double AudioServer::get_mix_time() const {
+double AudioServer::get_output_latency() const {
- return 0;
+ return AudioDriver::get_singleton()->get_latency();
}
-double AudioServer::get_output_delay() const {
- return 0;
+double AudioServer::get_time_to_next_mix() const {
+
+ return AudioDriver::get_singleton()->get_time_to_next_mix();
+}
+
+double AudioServer::get_time_since_last_mix() const {
+
+ return AudioDriver::get_singleton()->get_time_since_last_mix();
}
AudioServer *AudioServer::singleton = NULL;
@@ -1357,6 +1361,10 @@ void AudioServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_device"), &AudioServer::get_device);
ClassDB::bind_method(D_METHOD("set_device", "device"), &AudioServer::set_device);
+ ClassDB::bind_method(D_METHOD("get_time_to_next_mix"), &AudioServer::get_time_to_next_mix);
+ ClassDB::bind_method(D_METHOD("get_time_since_last_mix"), &AudioServer::get_time_since_last_mix);
+ ClassDB::bind_method(D_METHOD("get_output_latency"), &AudioServer::get_output_latency);
+
ClassDB::bind_method(D_METHOD("capture_get_device_list"), &AudioServer::capture_get_device_list);
ClassDB::bind_method(D_METHOD("capture_get_device"), &AudioServer::capture_get_device);
ClassDB::bind_method(D_METHOD("capture_set_device", "name"), &AudioServer::capture_set_device);
@@ -1386,6 +1394,8 @@ AudioServer::AudioServer() {
#ifdef DEBUG_ENABLED
prof_time = 0;
#endif
+ mix_time = 0;
+ mix_size = 0;
}
AudioServer::~AudioServer() {
diff --git a/servers/audio_server.h b/servers/audio_server.h
index 3b69cb1b88..e56d87ce84 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -45,7 +45,7 @@ class AudioDriver {
static AudioDriver *singleton;
uint64_t _last_mix_time;
- uint64_t _mix_amount;
+ uint64_t _last_mix_frames;
#ifdef DEBUG_ENABLED
uint64_t prof_ticks;
@@ -71,7 +71,8 @@ protected:
#endif
public:
- double get_mix_time() const; //useful for video -> audio sync
+ double get_time_since_last_mix() const; //useful for video -> audio sync
+ double get_time_to_next_mix() const;
enum SpeakerMode {
SPEAKER_MODE_STEREO,
@@ -163,6 +164,9 @@ public:
typedef void (*AudioCallback)(void *p_userdata);
private:
+ uint64_t mix_time;
+ int mix_size;
+
uint32_t buffer_size;
uint64_t mix_count;
uint64_t mix_frames;
@@ -351,8 +355,9 @@ public:
static AudioServer *get_singleton();
- virtual double get_mix_time() const; //useful for video -> audio sync
- virtual double get_output_delay() const;
+ virtual double get_output_latency() const;
+ virtual double get_time_to_next_mix() const;
+ virtual double get_time_since_last_mix() const;
void *audio_data_alloc(uint32_t p_data_len, const uint8_t *p_from_data = NULL);
void audio_data_free(void *p_data);
@@ -377,7 +382,6 @@ public:
String capture_get_device();
void capture_set_device(const String &p_name);
- float get_output_latency() { return output_latency; }
AudioServer();
virtual ~AudioServer();
};
diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp
index 085ad4f9ea..b1c21290ab 100644
--- a/servers/physics/collision_object_sw.cpp
+++ b/servers/physics/collision_object_sw.cpp
@@ -32,13 +32,14 @@
#include "servers/physics/physics_server_sw.h"
#include "space_sw.h"
-void CollisionObjectSW::add_shape(ShapeSW *p_shape, const Transform &p_transform) {
+void CollisionObjectSW::add_shape(ShapeSW *p_shape, const Transform &p_transform, bool p_disabled) {
Shape s;
s.shape = p_shape;
s.xform = p_transform;
s.xform_inv = s.xform.affine_inverse();
s.bpid = 0; //needs update
+ s.disabled = p_disabled;
shapes.push_back(s);
p_shape->add_owner(this);
diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h
index 5c14d5aaf9..c2c3fe0e5a 100644
--- a/servers/physics/collision_object_sw.h
+++ b/servers/physics/collision_object_sw.h
@@ -118,7 +118,7 @@ public:
void _shape_changed();
_FORCE_INLINE_ Type get_type() const { return type; }
- void add_shape(ShapeSW *p_shape, const Transform &p_transform = Transform());
+ void add_shape(ShapeSW *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
void set_shape(int p_index, ShapeSW *p_shape);
void set_shape_transform(int p_index, const Transform &p_transform);
_FORCE_INLINE_ int get_shape_count() const { return shapes.size(); }
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
index baf7431e28..3073cc8b11 100644
--- a/servers/physics/collision_solver_sat.cpp
+++ b/servers/physics/collision_solver_sat.cpp
@@ -98,7 +98,7 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
Vector3 c = rel_A.cross(rel_B).cross(rel_B);
- if (Math::abs(rel_A.dot(c)) < CMP_EPSILON) {
+ if (Math::is_zero_approx(rel_A.dot(c))) {
// should handle somehow..
//ERR_PRINT("TODO FIX");
@@ -678,7 +678,7 @@ static void _collision_box_box(const ShapeSW *p_a, const Transform &p_transform_
Vector3 axis = p_transform_a.basis.get_axis(i).cross(p_transform_b.basis.get_axis(j));
- if (axis.length_squared() < CMP_EPSILON)
+ if (Math::is_zero_approx(axis.length_squared()))
continue;
axis.normalize();
@@ -767,7 +767,7 @@ static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transf
// cylinder
Vector3 box_axis = p_transform_a.basis.get_axis(i);
Vector3 axis = box_axis.cross(cyl_axis);
- if (axis.length_squared() < CMP_EPSILON)
+ if (Math::is_zero_approx(axis.length_squared()))
continue;
if (!separator.test_axis(axis.normalized()))
diff --git a/servers/physics/joints/cone_twist_joint_sw.cpp b/servers/physics/joints/cone_twist_joint_sw.cpp
index 268b9eefeb..1b3de3e913 100644
--- a/servers/physics/joints/cone_twist_joint_sw.cpp
+++ b/servers/physics/joints/cone_twist_joint_sw.cpp
@@ -127,10 +127,10 @@ bool ConeTwistJointSW::setup(real_t p_timestep) {
Vector3 relPos = pivotBInW - pivotAInW;
Vector3 normal[3];
- if (relPos.length_squared() > CMP_EPSILON) {
- normal[0] = relPos.normalized();
- } else {
+ if (Math::is_zero_approx(relPos.length_squared())) {
normal[0] = Vector3(real_t(1.0), 0, 0);
+ } else {
+ normal[0] = relPos.normalized();
}
plane_space(normal[0], normal[1], normal[2]);
diff --git a/servers/physics/joints/generic_6dof_joint_sw.cpp b/servers/physics/joints/generic_6dof_joint_sw.cpp
index 756348f448..813d9b7704 100644
--- a/servers/physics/joints/generic_6dof_joint_sw.cpp
+++ b/servers/physics/joints/generic_6dof_joint_sw.cpp
@@ -107,7 +107,7 @@ real_t G6DOFRotationalLimitMotorSW::solveAngularLimits(
// correction velocity
real_t motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel);
- if (motor_relvel < CMP_EPSILON && motor_relvel > -CMP_EPSILON) {
+ if (Math::is_zero_approx(motor_relvel)) {
return 0.0f; //no need for applying force
}
diff --git a/servers/physics/joints/hinge_joint_sw.cpp b/servers/physics/joints/hinge_joint_sw.cpp
index e972496b2b..1d1b30286e 100644
--- a/servers/physics/joints/hinge_joint_sw.cpp
+++ b/servers/physics/joints/hinge_joint_sw.cpp
@@ -167,10 +167,10 @@ bool HingeJointSW::setup(real_t p_step) {
Vector3 relPos = pivotBInW - pivotAInW;
Vector3 normal[3];
- if (relPos.length_squared() > CMP_EPSILON) {
- normal[0] = relPos.normalized();
- } else {
+ if (Math::is_zero_approx(relPos.length_squared())) {
normal[0] = Vector3(real_t(1.0), 0, 0);
+ } else {
+ normal[0] = relPos.normalized();
}
plane_space(normal[0], normal[1], normal[2]);
diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp
index 36d18e8901..66170f5a2e 100644
--- a/servers/physics/physics_server_sw.cpp
+++ b/servers/physics/physics_server_sw.cpp
@@ -283,7 +283,7 @@ PhysicsServer::AreaSpaceOverrideMode PhysicsServerSW::area_get_space_override_mo
return area->get_space_override_mode();
}
-void PhysicsServerSW::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform) {
+void PhysicsServerSW::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) {
AreaSW *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
@@ -291,7 +291,7 @@ void PhysicsServerSW::area_add_shape(RID p_area, RID p_shape, const Transform &p
ShapeSW *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- area->add_shape(shape, p_transform);
+ area->add_shape(shape, p_transform, p_disabled);
}
void PhysicsServerSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
@@ -540,7 +540,7 @@ PhysicsServer::BodyMode PhysicsServerSW::body_get_mode(RID p_body) const {
return body->get_mode();
};
-void PhysicsServerSW::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform) {
+void PhysicsServerSW::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) {
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
@@ -548,7 +548,7 @@ void PhysicsServerSW::body_add_shape(RID p_body, RID p_shape, const Transform &p
ShapeSW *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- body->add_shape(shape, p_transform);
+ body->add_shape(shape, p_transform, p_disabled);
}
void PhysicsServerSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h
index 5d0ba3628e..dc1cbca94d 100644
--- a/servers/physics/physics_server_sw.h
+++ b/servers/physics/physics_server_sw.h
@@ -119,7 +119,7 @@ public:
virtual void area_set_space(RID p_area, RID p_space);
virtual RID area_get_space(RID p_area) const;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform());
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform);
@@ -163,7 +163,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode);
virtual BodyMode body_get_mode(RID p_body) const;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform());
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform);
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp
index 4ec92497e7..445a2e0613 100644
--- a/servers/physics_2d/collision_object_2d_sw.cpp
+++ b/servers/physics_2d/collision_object_2d_sw.cpp
@@ -31,14 +31,14 @@
#include "collision_object_2d_sw.h"
#include "space_2d_sw.h"
-void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_transform) {
+void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_transform, bool p_disabled) {
Shape s;
s.shape = p_shape;
s.xform = p_transform;
s.xform_inv = s.xform.affine_inverse();
s.bpid = 0; //needs update
- s.disabled = false;
+ s.disabled = p_disabled;
s.one_way_collision = false;
s.one_way_collision_margin = 0;
shapes.push_back(s);
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h
index d5e815ff45..fa18e61262 100644
--- a/servers/physics_2d/collision_object_2d_sw.h
+++ b/servers/physics_2d/collision_object_2d_sw.h
@@ -111,7 +111,7 @@ public:
void _shape_changed();
_FORCE_INLINE_ Type get_type() const { return type; }
- void add_shape(Shape2DSW *p_shape, const Transform2D &p_transform = Transform2D());
+ void add_shape(Shape2DSW *p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
void set_shape(int p_index, Shape2DSW *p_shape);
void set_shape_transform(int p_index, const Transform2D &p_transform);
void set_shape_metadata(int p_index, const Variant &p_metadata);
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp
index d6c3fff421..f4bff66389 100644
--- a/servers/physics_2d/collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/collision_solver_2d_sat.cpp
@@ -237,8 +237,8 @@ public:
Vector2 axis = p_axis;
- if (Math::abs(axis.x) < CMP_EPSILON &&
- Math::abs(axis.y) < CMP_EPSILON) {
+ if (Math::is_zero_approx(axis.x) &&
+ Math::is_zero_approx(axis.y)) {
// strange case, try an upwards separator
axis = Vector2(0.0, 1.0);
}
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index 283d20876d..1d02227052 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -378,7 +378,7 @@ Physics2DServer::AreaSpaceOverrideMode Physics2DServerSW::area_get_space_overrid
return area->get_space_override_mode();
}
-void Physics2DServerSW::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform) {
+void Physics2DServerSW::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
Area2DSW *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
@@ -386,7 +386,7 @@ void Physics2DServerSW::area_add_shape(RID p_area, RID p_shape, const Transform2
Shape2DSW *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- area->add_shape(shape, p_transform);
+ area->add_shape(shape, p_transform, p_disabled);
}
void Physics2DServerSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
@@ -643,7 +643,7 @@ Physics2DServer::BodyMode Physics2DServerSW::body_get_mode(RID p_body) const {
return body->get_mode();
};
-void Physics2DServerSW::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform) {
+void Physics2DServerSW::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
@@ -651,7 +651,7 @@ void Physics2DServerSW::body_add_shape(RID p_body, RID p_shape, const Transform2
Shape2DSW *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- body->add_shape(shape, p_transform);
+ body->add_shape(shape, p_transform, p_disabled);
}
void Physics2DServerSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index 4beec41442..6fda74b877 100644
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ b/servers/physics_2d/physics_2d_server_sw.h
@@ -131,7 +131,7 @@ public:
virtual void area_set_space(RID p_area, RID p_space);
virtual RID area_get_space(RID p_area) const;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D());
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform);
@@ -175,7 +175,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode);
virtual BodyMode body_get_mode(RID p_body) const;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D());
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform);
virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata);
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
index 5b9a102a1b..b61e1faad2 100644
--- a/servers/physics_2d/physics_2d_server_wrap_mt.h
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.h
@@ -140,7 +140,7 @@ public:
FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode);
FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID);
- FUNC3(area_add_shape, RID, RID, const Transform2D &);
+ FUNC4(area_add_shape, RID, RID, const Transform2D &, bool);
FUNC3(area_set_shape, RID, int, RID);
FUNC3(area_set_shape_transform, RID, int, const Transform2D &);
FUNC3(area_set_shape_disabled, RID, int, bool);
@@ -183,7 +183,7 @@ public:
FUNC2(body_set_mode, RID, BodyMode);
FUNC1RC(BodyMode, body_get_mode, RID);
- FUNC3(body_add_shape, RID, RID, const Transform2D &);
+ FUNC4(body_add_shape, RID, RID, const Transform2D &, bool);
FUNC3(body_set_shape, RID, int, RID);
FUNC3(body_set_shape_transform, RID, int, const Transform2D &);
FUNC3(body_set_shape_metadata, RID, int, const Variant &);
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index 0ba8a6605d..a9b95fbdf8 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -335,7 +335,7 @@ public:
virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0;
virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D()) = 0;
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0;
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0;
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) = 0;
@@ -388,7 +388,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0;
virtual BodyMode body_get_mode(RID p_body) const = 0;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D()) = 0;
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0;
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0;
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) = 0;
virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) = 0;
diff --git a/servers/physics_server.h b/servers/physics_server.h
index 9895ef2455..bc196c11fb 100644
--- a/servers/physics_server.h
+++ b/servers/physics_server.h
@@ -320,7 +320,7 @@ public:
virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0;
virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform()) = 0;
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0;
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0;
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) = 0;
@@ -372,7 +372,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0;
virtual BodyMode body_get_mode(RID p_body) const = 0;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform()) = 0;
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0;
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0;
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) = 0;
diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h
index 4e99bb3676..26424f927e 100644
--- a/servers/visual/visual_server_canvas.h
+++ b/servers/visual/visual_server_canvas.h
@@ -82,7 +82,7 @@ public:
_FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
- if (Math::abs(p_left->ysort_pos.y - p_right->ysort_pos.y) < CMP_EPSILON)
+ if (Math::is_equal_approx(p_left->ysort_pos.y, p_right->ysort_pos.y))
return p_left->ysort_pos.x < p_right->ysort_pos.x;
else
return p_left->ysort_pos.y < p_right->ysort_pos.y;
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index c1dc94daa2..af580d6794 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -2654,7 +2654,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
for (int i = 0; i < 3; i++) {
- if (ABS(light_axis[i]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[i]))
continue;
clip[clip_planes].normal[i] = 1.0;
@@ -2789,7 +2789,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
for (int c = 0; c < 3; c++) {
- if (ABS(light_axis[c]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index c98f593920..b4a9b83331 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -170,7 +170,7 @@ Files extracted from upstream source:
## libpng
- Upstream: http://libpng.org/pub/png/libpng.html
-- Version: 1.6.35
+- Version: 1.6.37
- License: libpng/zlib
Files extracted from upstream source:
@@ -185,18 +185,21 @@ Files extracted from upstream source:
## libsimplewebm
- Upstream: https://github.com/zaps166/libsimplewebm
-- Version: git (05cfdc2, 2016)
-- License: MIT, BSD-3-Clause
+- Version: git (fe57fd3, 2019)
+- License: MIT (main), BSD-3-Clause (libwebm)
+
+This contains libwebm, but the version in use is updated from the one used by libsimplewebm,
+and may have *unmarked* alterations from that.
Files extracted from upstream source:
-TODO.
+- all the .cpp, .hpp files in the main folder except `example.cpp`
+- LICENSE
Important: Some files have Godot-made changes.
They are marked with `// -- GODOT start --` and `// -- GODOT end --`
comments.
-
## libtheora
- Upstream: https://www.theora.org
diff --git a/thirdparty/libpng/LICENSE b/thirdparty/libpng/LICENSE
index 62ab8e48dc..e0c5b531cf 100644
--- a/thirdparty/libpng/LICENSE
+++ b/thirdparty/libpng/LICENSE
@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
PNG Reference Library License version 2
---------------------------------------
- * Copyright (c) 1995-2018 The PNG Reference Library Authors.
- * Copyright (c) 2018 Cosmin Truta.
+ * Copyright (c) 1995-2019 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2019 Cosmin Truta.
* Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* Copyright (c) 1996-1997 Andreas Dilger.
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -13,7 +13,7 @@ PNG Reference Library License version 2
The software is supplied "as is", without warranty of any kind,
express or implied, including, without limitation, the warranties
of merchantability, fitness for a particular purpose, title, and
-non-infringement. In no even shall the Copyright owners, or
+non-infringement. In no event shall the Copyright owners, or
anyone distributing the software, be liable for any damages or
other liability, whether in contract, tort or otherwise, arising
from, out of, or in connection with the software, or the use or
@@ -39,7 +39,7 @@ subject to the following restrictions:
PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)
-----------------------------------------------------------------------
-libpng versions 1.0.7, July 1, 2000 through 1.6.35, July 15, 2018 are
+libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are
Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are
derived from libpng-1.0.6, and are distributed according to the same
disclaimer and license as libpng-1.0.6 with the following individuals
diff --git a/thirdparty/libpng/arm/palette_neon_intrinsics.c b/thirdparty/libpng/arm/palette_neon_intrinsics.c
index fa02d6a8b3..b4d1fd2abf 100644
--- a/thirdparty/libpng/arm/palette_neon_intrinsics.c
+++ b/thirdparty/libpng/arm/palette_neon_intrinsics.c
@@ -1,7 +1,7 @@
/* palette_neon_intrinsics.c - NEON optimised palette expansion functions
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 2017-2018 Arm Holdings. All rights reserved.
* Written by Richard Townsend <Richard.Townsend@arm.com>, February 2017.
*
@@ -20,9 +20,9 @@
# include <arm_neon.h>
#endif
-/* Build an RGBA palette from the RGB and separate alpha palettes. */
+/* Build an RGBA8 palette from the separate RGB and alpha palettes. */
void
-png_riffle_palette_rgba(png_structrp png_ptr, png_row_infop row_info)
+png_riffle_palette_neon(png_structrp png_ptr)
{
png_const_colorp palette = png_ptr->palette;
png_bytep riffled_palette = png_ptr->riffled_palette;
@@ -30,6 +30,8 @@ png_riffle_palette_rgba(png_structrp png_ptr, png_row_infop row_info)
int num_trans = png_ptr->num_trans;
int i;
+ png_debug(1, "in png_riffle_palette_neon");
+
/* Initially black, opaque. */
uint8x16x4_t w = {{
vdupq_n_u8(0x00),
@@ -38,16 +40,10 @@ png_riffle_palette_rgba(png_structrp png_ptr, png_row_infop row_info)
vdupq_n_u8(0xff),
}};
- if (row_info->bit_depth != 8)
- {
- png_error(png_ptr, "bit_depth must be 8 for png_riffle_palette_rgba");
- return;
- }
-
- /* First, riffle the RGB colours into a RGBA palette, the A value is
- * set to opaque for now.
+ /* First, riffle the RGB colours into an RGBA8 palette.
+ * The alpha component is set to opaque for now.
*/
- for (i = 0; i < (1 << row_info->bit_depth); i += 16)
+ for (i = 0; i < 256; i += 16)
{
uint8x16x3_t v = vld3q_u8((png_const_bytep)(palette + i));
w.val[0] = v.val[0];
@@ -61,9 +57,9 @@ png_riffle_palette_rgba(png_structrp png_ptr, png_row_infop row_info)
riffled_palette[(i << 2) + 3] = trans_alpha[i];
}
-/* Expands a palettized row into RGBA. */
+/* Expands a palettized row into RGBA8. */
int
-png_do_expand_palette_neon_rgba(png_structrp png_ptr, png_row_infop row_info,
+png_do_expand_palette_rgba8_neon(png_structrp png_ptr, png_row_infop row_info,
png_const_bytep row, png_bytepp ssp, png_bytepp ddp)
{
png_uint_32 row_width = row_info->width;
@@ -72,6 +68,8 @@ png_do_expand_palette_neon_rgba(png_structrp png_ptr, png_row_infop row_info,
const png_int_32 pixels_per_chunk = 4;
int i;
+ png_debug(1, "in png_do_expand_palette_rgba8_neon");
+
if (row_width < pixels_per_chunk)
return 0;
@@ -103,9 +101,9 @@ png_do_expand_palette_neon_rgba(png_structrp png_ptr, png_row_infop row_info,
return i;
}
-/* Expands a palettized row into RGB format. */
+/* Expands a palettized row into RGB8. */
int
-png_do_expand_palette_neon_rgb(png_structrp png_ptr, png_row_infop row_info,
+png_do_expand_palette_rgb8_neon(png_structrp png_ptr, png_row_infop row_info,
png_const_bytep row, png_bytepp ssp, png_bytepp ddp)
{
png_uint_32 row_width = row_info->width;
@@ -113,6 +111,8 @@ png_do_expand_palette_neon_rgb(png_structrp png_ptr, png_row_infop row_info,
const png_uint_32 pixels_per_chunk = 8;
int i;
+ png_debug(1, "in png_do_expand_palette_rgb8_neon");
+
if (row_width <= pixels_per_chunk)
return 0;
diff --git a/thirdparty/libpng/png.c b/thirdparty/libpng/png.c
index 3dce191d17..757c755f97 100644
--- a/thirdparty/libpng/png.c
+++ b/thirdparty/libpng/png.c
@@ -1,7 +1,7 @@
/* png.c - location for general purpose libpng functions
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -14,7 +14,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_36 Your_png_h_is_not_version_1_6_36;
+typedef png_libpng_version_1_6_37 Your_png_h_is_not_version_1_6_37;
#ifdef __GNUC__
/* The version tests may need to be added to, but the problem warning has
@@ -815,8 +815,8 @@ png_get_copyright(png_const_structrp png_ptr)
return PNG_STRING_COPYRIGHT
#else
return PNG_STRING_NEWLINE \
- "libpng version 1.6.36" PNG_STRING_NEWLINE \
- "Copyright (c) 2018 Cosmin Truta" PNG_STRING_NEWLINE \
+ "libpng version 1.6.37" PNG_STRING_NEWLINE \
+ "Copyright (c) 2018-2019 Cosmin Truta" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
@@ -4588,8 +4588,7 @@ png_image_free(png_imagep image)
if (image != NULL && image->opaque != NULL &&
image->opaque->error_buf == NULL)
{
- /* Ignore errors here: */
- (void)png_safe_execute(image, png_image_free_function, image);
+ png_image_free_function(image);
image->opaque = NULL;
}
}
diff --git a/thirdparty/libpng/png.h b/thirdparty/libpng/png.h
index 8e272a0553..b12174ba35 100644
--- a/thirdparty/libpng/png.h
+++ b/thirdparty/libpng/png.h
@@ -1,9 +1,9 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.36 - December 1, 2018
+ * libpng version 1.6.37 - April 14, 2019
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -14,8 +14,9 @@
* libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
* libpng versions 0.97, January 1998, through 1.6.35, July 2018:
- * Glenn Randers-Pehrson.
- * libpng version 1.6.36, December 1, 2018: Cosmin Truta
+ * Glenn Randers-Pehrson
+ * libpng versions 1.6.36, December 2018, through 1.6.37, April 2019:
+ * Cosmin Truta
* See also "Contributing Authors", below.
*/
@@ -26,8 +27,8 @@
* PNG Reference Library License version 2
* ---------------------------------------
*
- * * Copyright (c) 1995-2018 The PNG Reference Library Authors.
- * * Copyright (c) 2018 Cosmin Truta.
+ * * Copyright (c) 1995-2019 The PNG Reference Library Authors.
+ * * Copyright (c) 2018-2019 Cosmin Truta.
* * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* * Copyright (c) 1996-1997 Andreas Dilger.
* * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -35,7 +36,7 @@
* The software is supplied "as is", without warranty of any kind,
* express or implied, including, without limitation, the warranties
* of merchantability, fitness for a particular purpose, title, and
- * non-infringement. In no even shall the Copyright owners, or
+ * non-infringement. In no event shall the Copyright owners, or
* anyone distributing the software, be liable for any damages or
* other liability, whether in contract, tort or otherwise, arising
* from, out of, or in connection with the software, or the use or
@@ -61,7 +62,7 @@
* PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)
* -----------------------------------------------------------------------
*
- * libpng versions 1.0.7, July 1, 2000 through 1.6.35, July 15, 2018 are
+ * libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are
* Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are
* derived from libpng-1.0.6, and are distributed according to the same
* disclaimer and license as libpng-1.0.6 with the following individuals
@@ -238,7 +239,7 @@
* ...
* 1.5.30 15 10530 15.so.15.30[.0]
* ...
- * 1.6.36 16 10636 16.so.16.36[.0]
+ * 1.6.37 16 10637 16.so.16.37[.0]
*
* Henceforth the source version will match the shared-library major and
* minor numbers; the shared-library major version number will be used for
@@ -277,8 +278,8 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.36"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.36 - December 1, 2018\n"
+#define PNG_LIBPNG_VER_STRING "1.6.37"
+#define PNG_HEADER_VERSION_STRING " libpng version 1.6.37 - April 14, 2019\n"
#define PNG_LIBPNG_VER_SONUM 16
#define PNG_LIBPNG_VER_DLLNUM 16
@@ -286,12 +287,11 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 36
+#define PNG_LIBPNG_VER_RELEASE 37
-/* This should match the numeric part of the final component of
- * PNG_LIBPNG_VER_STRING, omitting any leading zero:
+/* This should be zero for a public release, or non-zero for a
+ * development version. [Deprecated]
*/
-
#define PNG_LIBPNG_VER_BUILD 0
/* Release Status */
@@ -318,7 +318,7 @@
* From version 1.0.1 it is:
* XXYYZZ, where XX=major, YY=minor, ZZ=release
*/
-#define PNG_LIBPNG_VER 10636 /* 1.6.36 */
+#define PNG_LIBPNG_VER 10637 /* 1.6.37 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -330,6 +330,10 @@
# include "pnglibconf.h"
#endif
+#define PNG_APNG_SUPPORTED
+#define PNG_READ_APNG_SUPPORTED
+#define PNG_WRITE_APNG_SUPPORTED
+
#ifndef PNG_VERSION_INFO_ONLY
/* Machine specific configuration. */
# include "pngconf.h"
@@ -425,10 +429,21 @@ extern "C" {
* See pngconf.h for base types that vary by machine/system
*/
+#ifdef PNG_APNG_SUPPORTED
+/* dispose_op flags from inside fcTL */
+#define PNG_DISPOSE_OP_NONE 0x00U
+#define PNG_DISPOSE_OP_BACKGROUND 0x01U
+#define PNG_DISPOSE_OP_PREVIOUS 0x02U
+
+/* blend_op flags from inside fcTL */
+#define PNG_BLEND_OP_SOURCE 0x00U
+#define PNG_BLEND_OP_OVER 0x01U
+#endif /* PNG_APNG_SUPPORTED */
+
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_6_36;
+typedef char* png_libpng_version_1_6_37;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
@@ -746,6 +761,10 @@ typedef png_unknown_chunk * * png_unknown_chunkpp;
#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */
#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */
#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
+#ifdef PNG_APNG_SUPPORTED
+#define PNG_INFO_acTL 0x20000U
+#define PNG_INFO_fcTL 0x40000U
+#endif
/* This is used for the transformation routines, as some of them
* change these values for the row. It also should enable using
@@ -783,6 +802,10 @@ typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
+#ifdef PNG_APNG_SUPPORTED
+typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
+ png_uint_32));
+#endif
/* The following callback receives png_uint_32 row_number, int pass for the
* png_bytep data of the row. When transforming an interlaced image the
@@ -3226,6 +3249,74 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
/*******************************************************************************
* END OF HARDWARE AND SOFTWARE OPTIONS
******************************************************************************/
+#ifdef PNG_APNG_SUPPORTED
+PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
+
+PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
+
+PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr,
+ png_infop info_ptr));
+
+PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr,
+ png_infop info_ptr));
+
+PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL,
+ (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
+ png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
+ png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
+ png_byte *blend_op));
+
+PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL,
+ (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
+ png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
+ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
+ png_byte blend_op));
+
+PNG_EXPORT(256, png_uint_32, png_get_next_frame_width,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(257, png_uint_32, png_get_next_frame_height,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden,
+ (png_structp png_ptr, png_infop info_ptr));
+PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden,
+ (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
+
+#ifdef PNG_READ_APNG_SUPPORTED
+PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr,
+ png_infop info_ptr));
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr,
+ png_progressive_frame_ptr frame_info_fn,
+ png_progressive_frame_ptr frame_end_fn));
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+#endif /* PNG_READ_APNG_SUPPORTED */
+
+#ifdef PNG_WRITE_APNG_SUPPORTED
+PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr,
+ png_infop info_ptr, png_bytepp row_pointers,
+ png_uint_32 width, png_uint_32 height,
+ png_uint_32 x_offset, png_uint_32 y_offset,
+ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
+ png_byte blend_op));
+
+PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
+ png_infop info_ptr));
+#endif /* PNG_WRITE_APNG_SUPPORTED */
+#endif /* PNG_APNG_SUPPORTED */
/* Maintainer: Put new public prototypes here ^, in libpng.3, in project
* defs, and in scripts/symbols.def.
@@ -3235,7 +3326,11 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
* one to use is one more than this.)
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
+#ifdef PNG_APNG_SUPPORTED
+ PNG_EXPORT_LAST_ORDINAL(269);
+#else
PNG_EXPORT_LAST_ORDINAL(249);
+#endif /* PNG_APNG_SUPPORTED */
#endif
#ifdef __cplusplus
diff --git a/thirdparty/libpng/pngconf.h b/thirdparty/libpng/pngconf.h
index 5e641b2509..927a769dbe 100644
--- a/thirdparty/libpng/pngconf.h
+++ b/thirdparty/libpng/pngconf.h
@@ -1,9 +1,9 @@
-/* pngconf.h - machine configurable file for libpng
+/* pngconf.h - machine-configurable file for libpng
*
- * libpng version 1.6.36
+ * libpng version 1.6.37
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/thirdparty/libpng/pngget.c b/thirdparty/libpng/pngget.c
index 5abf1efd9f..9ed101aedc 100644
--- a/thirdparty/libpng/pngget.c
+++ b/thirdparty/libpng/pngget.c
@@ -1246,4 +1246,166 @@ png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)
# endif
#endif
+#ifdef PNG_APNG_SUPPORTED
+png_uint_32 PNGAPI
+png_get_acTL(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *num_frames, png_uint_32 *num_plays)
+{
+ png_debug1(1, "in %s retrieval function", "acTL");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_acTL) &&
+ num_frames != NULL && num_plays != NULL)
+ {
+ *num_frames = info_ptr->num_frames;
+ *num_plays = info_ptr->num_plays;
+ return (1);
+ }
+
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_num_frames()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->num_frames);
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_num_plays()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->num_plays);
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *width, png_uint_32 *height,
+ png_uint_32 *x_offset, png_uint_32 *y_offset,
+ png_uint_16 *delay_num, png_uint_16 *delay_den,
+ png_byte *dispose_op, png_byte *blend_op)
+{
+ png_debug1(1, "in %s retrieval function", "fcTL");
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_fcTL) &&
+ width != NULL && height != NULL &&
+ x_offset != NULL && y_offset != NULL &&
+ delay_num != NULL && delay_den != NULL &&
+ dispose_op != NULL && blend_op != NULL)
+ {
+ *width = info_ptr->next_frame_width;
+ *height = info_ptr->next_frame_height;
+ *x_offset = info_ptr->next_frame_x_offset;
+ *y_offset = info_ptr->next_frame_y_offset;
+ *delay_num = info_ptr->next_frame_delay_num;
+ *delay_den = info_ptr->next_frame_delay_den;
+ *dispose_op = info_ptr->next_frame_dispose_op;
+ *blend_op = info_ptr->next_frame_blend_op;
+ return (1);
+ }
+
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_next_frame_width()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->next_frame_width);
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_next_frame_height()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->next_frame_height);
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_next_frame_x_offset()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->next_frame_x_offset);
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_next_frame_y_offset()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->next_frame_y_offset);
+ return (0);
+}
+
+png_uint_16 PNGAPI
+png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_next_frame_delay_num()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->next_frame_delay_num);
+ return (0);
+}
+
+png_uint_16 PNGAPI
+png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_next_frame_delay_den()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->next_frame_delay_den);
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_next_frame_dispose_op()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->next_frame_dispose_op);
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_get_next_frame_blend_op()");
+
+ if (png_ptr != NULL && info_ptr != NULL)
+ return (info_ptr->next_frame_blend_op);
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_first_frame_is_hidden()");
+
+ if (png_ptr != NULL)
+ return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
+
+ PNG_UNUSED(info_ptr)
+
+ return 0;
+}
+#endif /* PNG_APNG_SUPPORTED */
#endif /* READ || WRITE */
diff --git a/thirdparty/libpng/pnginfo.h b/thirdparty/libpng/pnginfo.h
index 1f98dedc42..ac7b269132 100644
--- a/thirdparty/libpng/pnginfo.h
+++ b/thirdparty/libpng/pnginfo.h
@@ -263,5 +263,18 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
png_bytepp row_pointers; /* the image bits */
#endif
+#ifdef PNG_APNG_SUPPORTED
+ png_uint_32 num_frames; /* including default image */
+ png_uint_32 num_plays;
+ png_uint_32 next_frame_width;
+ png_uint_32 next_frame_height;
+ png_uint_32 next_frame_x_offset;
+ png_uint_32 next_frame_y_offset;
+ png_uint_16 next_frame_delay_num;
+ png_uint_16 next_frame_delay_den;
+ png_byte next_frame_dispose_op;
+ png_byte next_frame_blend_op;
+#endif
+
};
#endif /* PNGINFO_H */
diff --git a/thirdparty/libpng/pnglibconf.h b/thirdparty/libpng/pnglibconf.h
index 00340c678b..e1e27e957e 100644
--- a/thirdparty/libpng/pnglibconf.h
+++ b/thirdparty/libpng/pnglibconf.h
@@ -1,8 +1,8 @@
/* pnglibconf.h - library build configuration */
-/* libpng version 1.6.36 */
+/* libpng version 1.6.37 */
-/* Copyright (c) 2018 Cosmin Truta */
+/* Copyright (c) 2018-2019 Cosmin Truta */
/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
/* This code is released under the libpng license. */
diff --git a/thirdparty/libpng/pngpread.c b/thirdparty/libpng/pngpread.c
index e283627b77..2eaeca08f7 100644
--- a/thirdparty/libpng/pngpread.c
+++ b/thirdparty/libpng/pngpread.c
@@ -195,6 +195,106 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
chunk_name = png_ptr->chunk_name;
+#ifdef PNG_READ_APNG_SUPPORTED
+ if (png_ptr->num_frames_read > 0 &&
+ png_ptr->num_frames_read < info_ptr->num_frames)
+ {
+ if (chunk_name == png_IDAT)
+ {
+ /* Discard trailing IDATs for the first frame */
+ if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
+ png_error(png_ptr, "out of place IDAT");
+
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+ return;
+ }
+ else if (chunk_name == png_fdAT)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_ensure_sequence_number(png_ptr, 4);
+
+ if (!(png_ptr->mode & PNG_HAVE_fcTL))
+ {
+ /* Discard trailing fdATs for frames other than the first */
+ if (png_ptr->num_frames_read < 2)
+ png_error(png_ptr, "out of place fdAT");
+
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+ return;
+ }
+
+ else
+ {
+ /* frame data follows */
+ png_ptr->idat_size = png_ptr->push_length - 4;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+
+ return;
+ }
+ }
+
+ else if (chunk_name == png_fcTL)
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_read_reset(png_ptr);
+ png_ptr->mode &= ~PNG_HAVE_fcTL;
+
+ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
+
+ if (!(png_ptr->mode & PNG_HAVE_fcTL))
+ png_error(png_ptr, "missing required fcTL chunk");
+
+ png_read_reinit(png_ptr, info_ptr);
+ png_progressive_read_reset(png_ptr);
+
+ if (png_ptr->frame_info_fn != NULL)
+ (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
+
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+
+ return;
+ }
+
+ else
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_warning(png_ptr, "Skipped (ignored) a chunk "
+ "between APNG chunks");
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+ return;
+ }
+
+ return;
+ }
+#endif /* PNG_READ_APNG_SUPPORTED */
+
if (chunk_name == png_IDAT)
{
if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
@@ -261,6 +361,9 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
else if (chunk_name == png_IDAT)
{
+#ifdef PNG_READ_APNG_SUPPORTED
+ png_have_info(png_ptr, info_ptr);
+#endif
png_ptr->idat_size = png_ptr->push_length;
png_ptr->process_mode = PNG_READ_IDAT_MODE;
png_push_have_info(png_ptr, info_ptr);
@@ -406,6 +509,30 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
+#ifdef PNG_READ_APNG_SUPPORTED
+ else if (chunk_name == png_acTL)
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
+ }
+
+ else if (chunk_name == png_fcTL)
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
+ }
+
+#endif /* PNG_READ_APNG_SUPPORTED */
else
{
@@ -539,7 +666,11 @@ png_push_read_IDAT(png_structrp png_ptr)
png_byte chunk_tag[4];
/* TODO: this code can be commoned up with the same code in push_read */
+#ifdef PNG_READ_APNG_SUPPORTED
+ PNG_PUSH_SAVE_BUFFER_IF_LT(12)
+#else
PNG_PUSH_SAVE_BUFFER_IF_LT(8)
+#endif
png_push_fill_buffer(png_ptr, chunk_length, 4);
png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
png_reset_crc(png_ptr);
@@ -547,17 +678,64 @@ png_push_read_IDAT(png_structrp png_ptr)
png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+#ifdef PNG_READ_APNG_SUPPORTED
+ if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
+ {
+ if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ if (png_ptr->frame_end_fn != NULL)
+ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
+ png_ptr->num_frames_read++;
+ return;
+ }
+ else
+ {
+ if (png_ptr->chunk_name == png_IEND)
+ png_error(png_ptr, "Not enough image data");
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_warning(png_ptr, "Skipping (ignoring) a chunk between "
+ "APNG chunks");
+ png_crc_finish(png_ptr, png_ptr->push_length);
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+ return;
+ }
+ }
+ else
+#endif
+#ifdef PNG_READ_APNG_SUPPORTED
+ if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
+#else
if (png_ptr->chunk_name != png_IDAT)
+#endif
{
png_ptr->process_mode = PNG_READ_CHUNK_MODE;
if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
png_error(png_ptr, "Not enough compressed data");
+#ifdef PNG_READ_APNG_SUPPORTED
+ if (png_ptr->frame_end_fn != NULL)
+ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
+ png_ptr->num_frames_read++;
+#endif
+
return;
}
png_ptr->idat_size = png_ptr->push_length;
+
+#ifdef PNG_READ_APNG_SUPPORTED
+ if (png_ptr->num_frames_read > 0)
+ {
+ png_ensure_sequence_number(png_ptr, 4);
+ png_ptr->idat_size -= 4;
+ }
+#endif
}
if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
@@ -631,6 +809,15 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
if (!(buffer_length > 0) || buffer == NULL)
png_error(png_ptr, "No IDAT data (internal error)");
+#ifdef PNG_READ_APNG_SUPPORTED
+ /* If the app is not APNG-aware, decode only the first frame */
+ if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
+ {
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+ return;
+ }
+#endif
+
/* This routine must process all the data it has been given
* before returning, calling the row callback as required to
* handle the uncompressed results.
@@ -1085,6 +1272,18 @@ png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr,
png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
}
+#ifdef PNG_READ_APNG_SUPPORTED
+void PNGAPI
+png_set_progressive_frame_fn(png_structp png_ptr,
+ png_progressive_frame_ptr frame_info_fn,
+ png_progressive_frame_ptr frame_end_fn)
+{
+ png_ptr->frame_info_fn = frame_info_fn;
+ png_ptr->frame_end_fn = frame_end_fn;
+ png_ptr->apng_flags |= PNG_APNG_APP;
+}
+#endif
+
png_voidp PNGAPI
png_get_progressive_ptr(png_const_structrp png_ptr)
{
diff --git a/thirdparty/libpng/pngpriv.h b/thirdparty/libpng/pngpriv.h
index 973c3eac1f..57e1bf989b 100644
--- a/thirdparty/libpng/pngpriv.h
+++ b/thirdparty/libpng/pngpriv.h
@@ -1,7 +1,7 @@
/* pngpriv.h - private declarations for use inside libpng
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -637,6 +637,10 @@
#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
/* 0x4000U (unused) */
#define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */
+#ifdef PNG_APNG_SUPPORTED
+#define PNG_HAVE_acTL 0x10000U
+#define PNG_HAVE_fcTL 0x20000U
+#endif
/* Flags for the transformations the PNG library does on the image data */
#define PNG_BGR 0x0001U
@@ -873,6 +877,16 @@
#define png_tRNS PNG_U32(116, 82, 78, 83)
#define png_zTXt PNG_U32(122, 84, 88, 116)
+#ifdef PNG_APNG_SUPPORTED
+#define png_acTL PNG_U32( 97, 99, 84, 76)
+#define png_fcTL PNG_U32(102, 99, 84, 76)
+#define png_fdAT PNG_U32(102, 100, 65, 84)
+
+/* For png_struct.apng_flags: */
+#define PNG_FIRST_FRAME_HIDDEN 0x0001U
+#define PNG_APNG_APP 0x0002U
+#endif
+
/* The following will work on (signed char*) strings, whereas the get_uint_32
* macro will fail on top-bit-set values because of the sign extension.
*/
@@ -1644,6 +1658,47 @@ PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr,
*/
#endif
+#ifdef PNG_APNG_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
+ png_uint_32 width, png_uint_32 height,
+ png_uint_32 x_offset, png_uint_32 y_offset,
+ png_uint_16 delay_num, png_uint_16 delay_den,
+ png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
+
+#ifdef PNG_READ_APNG_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
+ png_uint_32 length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
+ png_infop info_ptr),PNG_EMPTY);
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+#endif /* PNG_READ_APNG_SUPPORTED */
+
+#ifdef PNG_WRITE_APNG_SUPPORTED
+PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
+ png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
+ png_uint_32 width, png_uint_32 height,
+ png_uint_32 x_offset, png_uint_32 y_offset,
+ png_uint_16 delay_num, png_uint_16 delay_den,
+ png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
+ png_const_bytep data, png_size_t length),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
+#endif /* PNG_WRITE_APNG_SUPPORTED */
+#endif /* PNG_APNG_SUPPORTED */
+
/* Added at libpng version 1.4.0 */
#ifdef PNG_COLORSPACE_SUPPORTED
/* These internal functions are for maintaining the colorspace structure within
@@ -2119,11 +2174,11 @@ PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
#if PNG_ARM_NEON_IMPLEMENTATION == 1
PNG_INTERNAL_FUNCTION(void,
- png_riffle_palette_rgba,
- (png_structrp, png_row_infop),
+ png_riffle_palette_neon,
+ (png_structrp),
PNG_EMPTY);
PNG_INTERNAL_FUNCTION(int,
- png_do_expand_palette_neon_rgba,
+ png_do_expand_palette_rgba8_neon,
(png_structrp,
png_row_infop,
png_const_bytep,
@@ -2131,7 +2186,7 @@ PNG_INTERNAL_FUNCTION(int,
const png_bytepp),
PNG_EMPTY);
PNG_INTERNAL_FUNCTION(int,
- png_do_expand_palette_neon_rgb,
+ png_do_expand_palette_rgb8_neon,
(png_structrp,
png_row_infop,
png_const_bytep,
diff --git a/thirdparty/libpng/pngread.c b/thirdparty/libpng/pngread.c
index f8e762196e..fa44d5a8e4 100644
--- a/thirdparty/libpng/pngread.c
+++ b/thirdparty/libpng/pngread.c
@@ -1,7 +1,7 @@
/* pngread.c - read a PNG file
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -161,6 +161,9 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
else if (chunk_name == png_IDAT)
{
+#ifdef PNG_READ_APNG_SUPPORTED
+ png_have_info(png_ptr, info_ptr);
+#endif
png_ptr->idat_size = length;
break;
}
@@ -255,6 +258,17 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
png_handle_iTXt(png_ptr, info_ptr, length);
#endif
+#ifdef PNG_READ_APNG_SUPPORTED
+ else if (chunk_name == png_acTL)
+ png_handle_acTL(png_ptr, info_ptr, length);
+
+ else if (chunk_name == png_fcTL)
+ png_handle_fcTL(png_ptr, info_ptr, length);
+
+ else if (chunk_name == png_fdAT)
+ png_handle_fdAT(png_ptr, info_ptr, length);
+#endif
+
else
png_handle_unknown(png_ptr, info_ptr, length,
PNG_HANDLE_CHUNK_AS_DEFAULT);
@@ -262,6 +276,72 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
}
#endif /* SEQUENTIAL_READ */
+#ifdef PNG_READ_APNG_SUPPORTED
+void PNGAPI
+png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
+{
+ png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
+
+ png_debug(0, "Reading frame head");
+
+ if (!(png_ptr->mode & PNG_HAVE_acTL))
+ png_error(png_ptr, "attempt to png_read_frame_head() but "
+ "no acTL present");
+
+ /* do nothing for the main IDAT */
+ if (png_ptr->num_frames_read == 0)
+ return;
+
+ png_read_reset(png_ptr);
+ png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
+ png_ptr->mode &= ~PNG_HAVE_fcTL;
+
+ have_chunk_after_DAT = 0;
+ for (;;)
+ {
+ png_uint_32 length = png_read_chunk_header(png_ptr);
+
+ if (png_ptr->chunk_name == png_IDAT)
+ {
+ /* discard trailing IDATs for the first frame */
+ if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
+ png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
+ png_crc_finish(png_ptr, length);
+ }
+
+ else if (png_ptr->chunk_name == png_fcTL)
+ {
+ png_handle_fcTL(png_ptr, info_ptr, length);
+ have_chunk_after_DAT = 1;
+ }
+
+ else if (png_ptr->chunk_name == png_fdAT)
+ {
+ png_ensure_sequence_number(png_ptr, length);
+
+ /* discard trailing fdATs for frames other than the first */
+ if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
+ png_crc_finish(png_ptr, length - 4);
+ else if(png_ptr->mode & PNG_HAVE_fcTL)
+ {
+ png_ptr->idat_size = length - 4;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+
+ break;
+ }
+ else
+ png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
+ }
+ else
+ {
+ png_warning(png_ptr, "Skipped (ignored) a chunk "
+ "between APNG chunks");
+ png_crc_finish(png_ptr, length);
+ }
+ }
+}
+#endif /* PNG_READ_APNG_SUPPORTED */
+
/* Optional call to update the users info_ptr structure */
void PNGAPI
png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
@@ -994,6 +1074,12 @@ png_read_destroy(png_structrp png_ptr)
png_ptr->chunk_list = NULL;
#endif
+#if defined(PNG_READ_EXPAND_SUPPORTED) && \
+ defined(PNG_ARM_NEON_IMPLEMENTATION)
+ png_free(png_ptr, png_ptr->riffled_palette);
+ png_ptr->riffled_palette = NULL;
+#endif
+
/* NOTE: the 'setjmp' buffer may still be allocated and the memory and error
* callbacks are still set at this point. They are required to complete the
* destruction of the png_struct itself.
diff --git a/thirdparty/libpng/pngrtran.c b/thirdparty/libpng/pngrtran.c
index ccc58ce6f1..9a8fad9f4a 100644
--- a/thirdparty/libpng/pngrtran.c
+++ b/thirdparty/libpng/pngrtran.c
@@ -1,7 +1,7 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -1182,20 +1182,20 @@ png_init_palette_transformations(png_structrp png_ptr)
png_ptr->palette[png_ptr->background.index].blue;
#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
- if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
- {
- if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)
- {
- /* Invert the alpha channel (in tRNS) unless the pixels are
- * going to be expanded, in which case leave it for later
- */
- int i, istop = png_ptr->num_trans;
-
- for (i=0; i<istop; i++)
- png_ptr->trans_alpha[i] = (png_byte)(255 -
- png_ptr->trans_alpha[i]);
- }
- }
+ if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
+ {
+ if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)
+ {
+ /* Invert the alpha channel (in tRNS) unless the pixels are
+ * going to be expanded, in which case leave it for later
+ */
+ int i, istop = png_ptr->num_trans;
+
+ for (i = 0; i < istop; i++)
+ png_ptr->trans_alpha[i] =
+ (png_byte)(255 - png_ptr->trans_alpha[i]);
+ }
+ }
#endif /* READ_INVERT_ALPHA */
}
} /* background expand and (therefore) no alpha association. */
@@ -4320,9 +4320,11 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
* but sometimes row_info->bit_depth has been changed to 8.
* In these cases, the palette hasn't been riffled.
*/
- i = png_do_expand_palette_neon_rgba(png_ptr, row_info, row,
+ i = png_do_expand_palette_rgba8_neon(png_ptr, row_info, row,
&sp, &dp);
}
+#else
+ PNG_UNUSED(png_ptr)
#endif
for (; i < row_width; i++)
@@ -4349,8 +4351,10 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
dp = row + (size_t)(row_width * 3) - 1;
i = 0;
#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
- i = png_do_expand_palette_neon_rgb(png_ptr, row_info, row,
+ i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row,
&sp, &dp);
+#else
+ PNG_UNUSED(png_ptr)
#endif
for (; i < row_width; i++)
@@ -4770,19 +4774,17 @@ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
if ((png_ptr->num_trans > 0) && (png_ptr->bit_depth == 8))
{
- /* Allocate space for the decompressed full palette. */
if (png_ptr->riffled_palette == NULL)
{
- png_ptr->riffled_palette = png_malloc(png_ptr, 256*4);
- if (png_ptr->riffled_palette == NULL)
- png_error(png_ptr, "NULL row buffer");
- /* Build the RGBA palette. */
- png_riffle_palette_rgba(png_ptr, row_info);
+ /* Initialize the accelerated palette expansion. */
+ png_ptr->riffled_palette =
+ (png_bytep)png_malloc(png_ptr, 256 * 4);
+ png_riffle_palette_neon(png_ptr);
}
}
#endif
png_do_expand_palette(png_ptr, row_info, png_ptr->row_buf + 1,
- png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);
+ png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);
}
else
diff --git a/thirdparty/libpng/pngrutil.c b/thirdparty/libpng/pngrutil.c
index d5fa08c397..ae66a48a83 100644
--- a/thirdparty/libpng/pngrutil.c
+++ b/thirdparty/libpng/pngrutil.c
@@ -865,6 +865,11 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
filter_type = buf[11];
interlace_type = buf[12];
+#ifdef PNG_READ_APNG_SUPPORTED
+ png_ptr->first_frame_width = width;
+ png_ptr->first_frame_height = height;
+#endif
+
/* Set internal variables */
png_ptr->width = width;
png_ptr->height = height;
@@ -2857,6 +2862,179 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
}
#endif
+#ifdef PNG_READ_APNG_SUPPORTED
+void /* PRIVATE */
+png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte data[8];
+ png_uint_32 num_frames;
+ png_uint_32 num_plays;
+ png_uint_32 didSet;
+
+ png_debug(1, "in png_handle_acTL");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ {
+ png_error(png_ptr, "Missing IHDR before acTL");
+ }
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid acTL after IDAT skipped");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_acTL)
+ {
+ png_warning(png_ptr, "Duplicate acTL skipped");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (length != 8)
+ {
+ png_warning(png_ptr, "acTL with invalid length skipped");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, data, 8);
+ png_crc_finish(png_ptr, 0);
+
+ num_frames = png_get_uint_31(png_ptr, data);
+ num_plays = png_get_uint_31(png_ptr, data + 4);
+
+ /* the set function will do error checking on num_frames */
+ didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
+ if(didSet)
+ png_ptr->mode |= PNG_HAVE_acTL;
+}
+
+void /* PRIVATE */
+png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte data[22];
+ png_uint_32 width;
+ png_uint_32 height;
+ png_uint_32 x_offset;
+ png_uint_32 y_offset;
+ png_uint_16 delay_num;
+ png_uint_16 delay_den;
+ png_byte dispose_op;
+ png_byte blend_op;
+
+ png_debug(1, "in png_handle_fcTL");
+
+ png_ensure_sequence_number(png_ptr, length);
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ {
+ png_error(png_ptr, "Missing IHDR before fcTL");
+ }
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ /* for any frames other then the first this message may be misleading,
+ * but correct. PNG_HAVE_IDAT is unset before the frame head is read
+ * i can't think of a better message */
+ png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
+ png_crc_finish(png_ptr, length-4);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_fcTL)
+ {
+ png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
+ png_crc_finish(png_ptr, length-4);
+ return;
+ }
+ else if (length != 26)
+ {
+ png_warning(png_ptr, "fcTL with invalid length skipped");
+ png_crc_finish(png_ptr, length-4);
+ return;
+ }
+
+ png_crc_read(png_ptr, data, 22);
+ png_crc_finish(png_ptr, 0);
+
+ width = png_get_uint_31(png_ptr, data);
+ height = png_get_uint_31(png_ptr, data + 4);
+ x_offset = png_get_uint_31(png_ptr, data + 8);
+ y_offset = png_get_uint_31(png_ptr, data + 12);
+ delay_num = png_get_uint_16(data + 16);
+ delay_den = png_get_uint_16(data + 18);
+ dispose_op = data[20];
+ blend_op = data[21];
+
+ if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
+ {
+ png_warning(png_ptr, "fcTL for the first frame must have zero offset");
+ return;
+ }
+
+ if (info_ptr != NULL)
+ {
+ if (png_ptr->num_frames_read == 0 &&
+ (width != info_ptr->width || height != info_ptr->height))
+ {
+ png_warning(png_ptr, "size in first frame's fcTL must match "
+ "the size in IHDR");
+ return;
+ }
+
+ /* The set function will do more error checking */
+ png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
+ x_offset, y_offset, delay_num, delay_den,
+ dispose_op, blend_op);
+
+ png_read_reinit(png_ptr, info_ptr);
+
+ png_ptr->mode |= PNG_HAVE_fcTL;
+ }
+}
+
+void /* PRIVATE */
+png_have_info(png_structp png_ptr, png_infop info_ptr)
+{
+ if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
+ {
+ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
+ info_ptr->num_frames++;
+ }
+}
+
+void /* PRIVATE */
+png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_ensure_sequence_number(png_ptr, length);
+
+ /* This function is only called from png_read_end(), png_read_info(),
+ * and png_push_read_chunk() which means that:
+ * - the user doesn't want to read this frame
+ * - or this is an out-of-place fdAT
+ * in either case it is safe to ignore the chunk with a warning */
+ png_warning(png_ptr, "ignoring fdAT chunk");
+ png_crc_finish(png_ptr, length - 4);
+ PNG_UNUSED(info_ptr)
+}
+
+void /* PRIVATE */
+png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
+{
+ png_byte data[4];
+ png_uint_32 sequence_number;
+
+ if (length < 4)
+ png_error(png_ptr, "invalid fcTL or fdAT chunk found");
+
+ png_crc_read(png_ptr, data, 4);
+ sequence_number = png_get_uint_31(png_ptr, data);
+
+ if (sequence_number != png_ptr->next_seq_num)
+ png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
+ "number found");
+
+ png_ptr->next_seq_num++;
+}
+#endif /* PNG_READ_APNG_SUPPORTED */
+
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
static int
@@ -4165,7 +4343,38 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
{
uInt avail_in;
png_bytep buffer;
+#ifdef PNG_READ_APNG_SUPPORTED
+ png_uint_32 bytes_to_skip = 0;
+
+ while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
+ {
+ png_crc_finish(png_ptr, bytes_to_skip);
+ bytes_to_skip = 0;
+
+ png_ptr->idat_size = png_read_chunk_header(png_ptr);
+ if (png_ptr->num_frames_read == 0)
+ {
+ if (png_ptr->chunk_name != png_IDAT)
+ png_error(png_ptr, "Not enough image data");
+ }
+ else
+ {
+ if (png_ptr->chunk_name == png_IEND)
+ png_error(png_ptr, "Not enough image data");
+ if (png_ptr->chunk_name != png_fdAT)
+ {
+ png_warning(png_ptr, "Skipped (ignored) a chunk "
+ "between APNG chunks");
+ bytes_to_skip = png_ptr->idat_size;
+ continue;
+ }
+
+ png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
+ png_ptr->idat_size -= 4;
+ }
+ }
+#else
while (png_ptr->idat_size == 0)
{
png_crc_finish(png_ptr, 0);
@@ -4177,7 +4386,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
if (png_ptr->chunk_name != png_IDAT)
png_error(png_ptr, "Not enough image data");
}
-
+#endif /* PNG_READ_APNG_SUPPORTED */
avail_in = png_ptr->IDAT_read_size;
if (avail_in > png_ptr->idat_size)
@@ -4240,6 +4449,9 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+#ifdef PNG_READ_APNG_SUPPORTED
+ png_ptr->num_frames_read++;
+#endif
if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
png_chunk_benign_error(png_ptr, "Extra compressed data");
@@ -4678,4 +4890,80 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
png_ptr->flags |= PNG_FLAG_ROW_INIT;
}
+
+#ifdef PNG_READ_APNG_SUPPORTED
+/* This function is to be called after the main IDAT set has been read and
+ * before a new IDAT is read. It resets some parts of png_ptr
+ * to make them usable by the read functions again */
+void /* PRIVATE */
+png_read_reset(png_structp png_ptr)
+{
+ png_ptr->mode &= ~PNG_HAVE_IDAT;
+ png_ptr->mode &= ~PNG_AFTER_IDAT;
+ png_ptr->row_number = 0;
+ png_ptr->pass = 0;
+}
+
+void /* PRIVATE */
+png_read_reinit(png_structp png_ptr, png_infop info_ptr)
+{
+ png_ptr->width = info_ptr->next_frame_width;
+ png_ptr->height = info_ptr->next_frame_height;
+ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
+ png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
+ png_ptr->width);
+ if (png_ptr->prev_row)
+ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+}
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+/* same as png_read_reset() but for the progressive reader */
+void /* PRIVATE */
+png_progressive_read_reset(png_structp png_ptr)
+{
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* Start of interlace block */
+ const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* Offset to next interlace block */
+ const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* Start of interlace block in the y direction */
+ const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* Offset to next interlace block in the y direction */
+ const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ else
+ png_ptr->num_rows = png_ptr->height;
+
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ }
+ else
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->iwidth = png_ptr->width;
+ }
+ png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
+ if (inflateReset(&(png_ptr->zstream)) != Z_OK)
+ png_error(png_ptr, "inflateReset failed");
+ png_ptr->zstream.avail_in = 0;
+ png_ptr->zstream.next_in = 0;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
+ png_ptr->iwidth) + 1;
+}
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+#endif /* PNG_READ_APNG_SUPPORTED */
#endif /* READ */
diff --git a/thirdparty/libpng/pngset.c b/thirdparty/libpng/pngset.c
index ec75dbe369..a281db58ae 100644
--- a/thirdparty/libpng/pngset.c
+++ b/thirdparty/libpng/pngset.c
@@ -288,6 +288,11 @@ png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
+
+#ifdef PNG_APNG_SUPPORTED
+ /* for non-animated png. this may be overwritten from an acTL chunk later */
+ info_ptr->num_frames = 1;
+#endif
}
#ifdef PNG_oFFs_SUPPORTED
@@ -1158,6 +1163,147 @@ png_set_sPLT(png_const_structrp png_ptr,
}
#endif /* sPLT */
+#ifdef PNG_APNG_SUPPORTED
+png_uint_32 PNGAPI
+png_set_acTL(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 num_frames, png_uint_32 num_plays)
+{
+ png_debug1(1, "in %s storage function", "acTL");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ {
+ png_warning(png_ptr,
+ "Call to png_set_acTL() with NULL png_ptr "
+ "or info_ptr ignored");
+ return (0);
+ }
+ if (num_frames == 0)
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to set acTL with num_frames zero");
+ return (0);
+ }
+ if (num_frames > PNG_UINT_31_MAX)
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to set acTL with num_frames > 2^31-1");
+ return (0);
+ }
+ if (num_plays > PNG_UINT_31_MAX)
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to set acTL with num_plays "
+ "> 2^31-1");
+ return (0);
+ }
+
+ info_ptr->num_frames = num_frames;
+ info_ptr->num_plays = num_plays;
+
+ info_ptr->valid |= PNG_INFO_acTL;
+
+ return (1);
+}
+
+/* delay_num and delay_den can hold any 16-bit values including zero */
+png_uint_32 PNGAPI
+png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 width, png_uint_32 height,
+ png_uint_32 x_offset, png_uint_32 y_offset,
+ png_uint_16 delay_num, png_uint_16 delay_den,
+ png_byte dispose_op, png_byte blend_op)
+{
+ png_debug1(1, "in %s storage function", "fcTL");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ {
+ png_warning(png_ptr,
+ "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
+ "ignored");
+ return (0);
+ }
+
+ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
+ delay_num, delay_den, dispose_op, blend_op);
+
+ if (blend_op == PNG_BLEND_OP_OVER)
+ {
+ if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
+ !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
+ {
+ png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
+ "and wasteful for opaque images, ignored");
+ blend_op = PNG_BLEND_OP_SOURCE;
+ }
+ }
+
+ info_ptr->next_frame_width = width;
+ info_ptr->next_frame_height = height;
+ info_ptr->next_frame_x_offset = x_offset;
+ info_ptr->next_frame_y_offset = y_offset;
+ info_ptr->next_frame_delay_num = delay_num;
+ info_ptr->next_frame_delay_den = delay_den;
+ info_ptr->next_frame_dispose_op = dispose_op;
+ info_ptr->next_frame_blend_op = blend_op;
+
+ info_ptr->valid |= PNG_INFO_fcTL;
+
+ return (1);
+}
+
+void /* PRIVATE */
+png_ensure_fcTL_is_valid(png_structp png_ptr,
+ png_uint_32 width, png_uint_32 height,
+ png_uint_32 x_offset, png_uint_32 y_offset,
+ png_uint_16 delay_num, png_uint_16 delay_den,
+ png_byte dispose_op, png_byte blend_op)
+{
+ if (width == 0 || width > PNG_UINT_31_MAX)
+ png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
+ if (height == 0 || height > PNG_UINT_31_MAX)
+ png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
+ if (x_offset > PNG_UINT_31_MAX)
+ png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
+ if (y_offset > PNG_UINT_31_MAX)
+ png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
+ if (width + x_offset > png_ptr->first_frame_width ||
+ height + y_offset > png_ptr->first_frame_height)
+ png_error(png_ptr, "dimensions of a frame are greater than"
+ "the ones in IHDR");
+
+ if (dispose_op != PNG_DISPOSE_OP_NONE &&
+ dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
+ dispose_op != PNG_DISPOSE_OP_PREVIOUS)
+ png_error(png_ptr, "invalid dispose_op in fcTL");
+
+ if (blend_op != PNG_BLEND_OP_SOURCE &&
+ blend_op != PNG_BLEND_OP_OVER)
+ png_error(png_ptr, "invalid blend_op in fcTL");
+
+ PNG_UNUSED(delay_num)
+ PNG_UNUSED(delay_den)
+}
+
+png_uint_32 PNGAPI
+png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
+ png_byte is_hidden)
+{
+ png_debug(1, "in png_first_frame_is_hidden()");
+
+ if (png_ptr == NULL)
+ return 0;
+
+ if (is_hidden)
+ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
+ else
+ png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
+
+ PNG_UNUSED(info_ptr)
+
+ return 1;
+}
+#endif /* PNG_APNG_SUPPORTED */
+
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
static png_byte
check_location(png_const_structrp png_ptr, int location)
diff --git a/thirdparty/libpng/pngstruct.h b/thirdparty/libpng/pngstruct.h
index 94a6d041ff..2a2236f92e 100644
--- a/thirdparty/libpng/pngstruct.h
+++ b/thirdparty/libpng/pngstruct.h
@@ -1,7 +1,7 @@
/* pngstruct.h - header file for PNG reference library
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -228,10 +228,6 @@ struct png_struct_def
* big_row_buf; while writing it is separately
* allocated.
*/
-#ifdef PNG_READ_EXPAND_SUPPORTED
- /* Buffer to accelerate palette transformations. */
- png_bytep riffled_palette;
-#endif
#ifdef PNG_WRITE_FILTER_SUPPORTED
png_bytep try_row; /* buffer to save trial row when filtering */
png_bytep tst_row; /* buffer to save best trial row when filtering */
@@ -396,6 +392,12 @@ struct png_struct_def
/* deleted in 1.5.5: rgb_to_gray_blue_coeff; */
#endif
+/* New member added in libpng-1.6.36 */
+#if defined(PNG_READ_EXPAND_SUPPORTED) && \
+ defined(PNG_ARM_NEON_IMPLEMENTATION)
+ png_bytep riffled_palette; /* buffer for accelerated palette expansion */
+#endif
+
/* New member added in libpng-1.0.4 (renamed in 1.0.9) */
#if defined(PNG_MNG_FEATURES_SUPPORTED)
/* Changed from png_byte to png_uint_32 at version 1.2.0 */
@@ -407,6 +409,27 @@ struct png_struct_def
png_byte filter_type;
#endif
+#ifdef PNG_APNG_SUPPORTED
+ png_uint_32 apng_flags;
+ png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */
+ png_uint_32 first_frame_width;
+ png_uint_32 first_frame_height;
+
+#ifdef PNG_READ_APNG_SUPPORTED
+ png_uint_32 num_frames_read; /* incremented after all image data of */
+ /* a frame is read */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
+ png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
+#endif
+#endif
+
+#ifdef PNG_WRITE_APNG_SUPPORTED
+ png_uint_32 num_frames_to_write;
+ png_uint_32 num_frames_written;
+#endif
+#endif /* PNG_APNG_SUPPORTED */
+
/* New members added in libpng-1.2.0 */
/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
diff --git a/thirdparty/libpng/pngwrite.c b/thirdparty/libpng/pngwrite.c
index 160c877d38..5e68032378 100644
--- a/thirdparty/libpng/pngwrite.c
+++ b/thirdparty/libpng/pngwrite.c
@@ -1,7 +1,7 @@
/* pngwrite.c - general routines to write a PNG file
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -128,6 +128,10 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
* the application continues writing the PNG. So check the 'invalid'
* flag here too.
*/
+#ifdef PNG_WRITE_APNG_SUPPORTED
+ if (info_ptr->valid & PNG_INFO_acTL)
+ png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
+#endif
#ifdef PNG_GAMMA_SUPPORTED
# ifdef PNG_WRITE_gAMA_SUPPORTED
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
@@ -370,6 +374,11 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
#endif
+#ifdef PNG_WRITE_APNG_SUPPORTED
+ if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
+ png_error(png_ptr, "Not enough frames written");
+#endif
+
/* See if user wants us to write information chunks */
if (info_ptr != NULL)
{
@@ -948,10 +957,6 @@ png_write_destroy(png_structrp png_ptr)
png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
png_free(png_ptr, png_ptr->row_buf);
png_ptr->row_buf = NULL;
-#ifdef PNG_READ_EXPANDED_SUPPORTED
- png_free(png_ptr, png_ptr->riffled_palette);
- png_ptr->riffled_palette = NULL;
-#endif
#ifdef PNG_WRITE_FILTER_SUPPORTED
png_free(png_ptr, png_ptr->prev_row);
png_free(png_ptr, png_ptr->try_row);
@@ -1465,6 +1470,43 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr,
}
#endif
+#ifdef PNG_WRITE_APNG_SUPPORTED
+void PNGAPI
+png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
+ png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
+ png_uint_32 x_offset, png_uint_32 y_offset,
+ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
+ png_byte blend_op)
+{
+ png_debug(1, "in png_write_frame_head");
+
+ /* there is a chance this has been set after png_write_info was called,
+ * so it would be set but not written. is there a way to be sure? */
+ if (!(info_ptr->valid & PNG_INFO_acTL))
+ png_error(png_ptr, "png_write_frame_head(): acTL not set");
+
+ png_write_reset(png_ptr);
+
+ png_write_reinit(png_ptr, info_ptr, width, height);
+
+ if ( !(png_ptr->num_frames_written == 0 &&
+ (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
+ png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
+ delay_num, delay_den, dispose_op, blend_op);
+
+ PNG_UNUSED(row_pointers)
+}
+
+void PNGAPI
+png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_write_frame_tail");
+
+ png_ptr->num_frames_written++;
+
+ PNG_UNUSED(info_ptr)
+}
+#endif /* PNG_WRITE_APNG_SUPPORTED */
#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
/* Initialize the write structure - general purpose utility. */
diff --git a/thirdparty/libpng/pngwutil.c b/thirdparty/libpng/pngwutil.c
index 16345e4c0b..b4809cda6b 100644
--- a/thirdparty/libpng/pngwutil.c
+++ b/thirdparty/libpng/pngwutil.c
@@ -821,6 +821,11 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
/* Write the chunk */
png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
+#ifdef PNG_WRITE_APNG_SUPPORTED
+ png_ptr->first_frame_width = width;
+ png_ptr->first_frame_height = height;
+#endif
+
if ((png_ptr->do_filter) == PNG_NO_FILTERS)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
@@ -1002,8 +1007,17 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
optimize_cmf(data, png_image_size(png_ptr));
#endif
- if (size > 0)
- png_write_complete_chunk(png_ptr, png_IDAT, data, size);
+ if (size > 0)
+#ifdef PNG_WRITE_APNG_SUPPORTED
+ {
+ if (png_ptr->num_frames_written == 0)
+#endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
+#ifdef PNG_WRITE_APNG_SUPPORTED
+ else
+ png_write_fdAT(png_ptr, data, size);
+ }
+#endif /* PNG_WRITE_APNG_SUPPORTED */
png_ptr->mode |= PNG_HAVE_IDAT;
png_ptr->zstream.next_out = data;
@@ -1050,7 +1064,17 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
#endif
if (size > 0)
+#ifdef PNG_WRITE_APNG_SUPPORTED
+ {
+ if (png_ptr->num_frames_written == 0)
+#endif
png_write_complete_chunk(png_ptr, png_IDAT, data, size);
+#ifdef PNG_WRITE_APNG_SUPPORTED
+ else
+ png_write_fdAT(png_ptr, data, size);
+ }
+#endif /* PNG_WRITE_APNG_SUPPORTED */
+
png_ptr->zstream.avail_out = 0;
png_ptr->zstream.next_out = NULL;
png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
@@ -1885,6 +1909,82 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
}
#endif
+#ifdef PNG_WRITE_APNG_SUPPORTED
+void /* PRIVATE */
+png_write_acTL(png_structp png_ptr,
+ png_uint_32 num_frames, png_uint_32 num_plays)
+{
+ png_byte buf[8];
+
+ png_debug(1, "in png_write_acTL");
+
+ png_ptr->num_frames_to_write = num_frames;
+
+ if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
+ num_frames--;
+
+ png_save_uint_32(buf, num_frames);
+ png_save_uint_32(buf + 4, num_plays);
+
+ png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
+}
+
+void /* PRIVATE */
+png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
+ png_uint_32 x_offset, png_uint_32 y_offset,
+ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
+ png_byte blend_op)
+{
+ png_byte buf[26];
+
+ png_debug(1, "in png_write_fcTL");
+
+ if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
+ png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
+ if (png_ptr->num_frames_written == 0 &&
+ (width != png_ptr->first_frame_width ||
+ height != png_ptr->first_frame_height))
+ png_error(png_ptr, "width and/or height in the first frame's fcTL "
+ "don't match the ones in IHDR");
+
+ /* more error checking */
+ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
+ delay_num, delay_den, dispose_op, blend_op);
+
+ png_save_uint_32(buf, png_ptr->next_seq_num);
+ png_save_uint_32(buf + 4, width);
+ png_save_uint_32(buf + 8, height);
+ png_save_uint_32(buf + 12, x_offset);
+ png_save_uint_32(buf + 16, y_offset);
+ png_save_uint_16(buf + 20, delay_num);
+ png_save_uint_16(buf + 22, delay_den);
+ buf[24] = dispose_op;
+ buf[25] = blend_op;
+
+ png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
+
+ png_ptr->next_seq_num++;
+}
+
+void /* PRIVATE */
+png_write_fdAT(png_structp png_ptr,
+ png_const_bytep data, png_size_t length)
+{
+ png_byte buf[4];
+
+ png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
+
+ png_save_uint_32(buf, png_ptr->next_seq_num);
+ png_write_chunk_data(png_ptr, buf, 4);
+
+ png_write_chunk_data(png_ptr, data, length);
+
+ png_write_chunk_end(png_ptr);
+
+ png_ptr->next_seq_num++;
+}
+#endif /* PNG_WRITE_APNG_SUPPORTED */
+
/* Initializes the row writing capability of libpng */
void /* PRIVATE */
png_write_start_row(png_structrp png_ptr)
@@ -2778,4 +2878,39 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
}
#endif /* WRITE_FLUSH */
}
+
+#ifdef PNG_WRITE_APNG_SUPPORTED
+void /* PRIVATE */
+png_write_reset(png_structp png_ptr)
+{
+ png_ptr->row_number = 0;
+ png_ptr->pass = 0;
+ png_ptr->mode &= ~PNG_HAVE_IDAT;
+}
+
+void /* PRIVATE */
+png_write_reinit(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 width, png_uint_32 height)
+{
+ if (png_ptr->num_frames_written == 0 &&
+ (width != png_ptr->first_frame_width ||
+ height != png_ptr->first_frame_height))
+ png_error(png_ptr, "width and/or height in the first frame's fcTL "
+ "don't match the ones in IHDR");
+ if (width > png_ptr->first_frame_width ||
+ height > png_ptr->first_frame_height)
+ png_error(png_ptr, "width and/or height for a frame greater than"
+ "the ones in IHDR");
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ info_ptr->bit_depth, info_ptr->color_type,
+ info_ptr->interlace_type, info_ptr->compression_type,
+ info_ptr->filter_type);
+
+ png_ptr->width = width;
+ png_ptr->height = height;
+ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
+ png_ptr->usr_width = png_ptr->width;
+}
+#endif /* PNG_WRITE_APNG_SUPPORTED */
#endif /* WRITE */
diff --git a/thirdparty/libsimplewebm/OpusVorbisDecoder.cpp b/thirdparty/libsimplewebm/OpusVorbisDecoder.cpp
index c9e71eb733..b5824b17be 100644
--- a/thirdparty/libsimplewebm/OpusVorbisDecoder.cpp
+++ b/thirdparty/libsimplewebm/OpusVorbisDecoder.cpp
@@ -122,6 +122,7 @@ bool OpusVorbisDecoder::getPCMS16(WebMFrame &frame, short *buffer, int &numOutSa
return false;
}
+// -- GODOT begin --
bool OpusVorbisDecoder::getPCMF(WebMFrame &frame, float *buffer, int &numOutSamples) {
if (m_vorbis) {
m_vorbis->op.packet = frame.buffer;
@@ -158,6 +159,7 @@ bool OpusVorbisDecoder::getPCMF(WebMFrame &frame, float *buffer, int &numOutSamp
}
return false;
}
+// -- GODOT end --
bool OpusVorbisDecoder::openVorbis(const WebMDemuxer &demuxer)
{
diff --git a/thirdparty/libsimplewebm/OpusVorbisDecoder.hpp b/thirdparty/libsimplewebm/OpusVorbisDecoder.hpp
index b7619d6a25..f285b3fbd6 100644
--- a/thirdparty/libsimplewebm/OpusVorbisDecoder.hpp
+++ b/thirdparty/libsimplewebm/OpusVorbisDecoder.hpp
@@ -44,8 +44,10 @@ public:
{
return m_numSamples;
}
- bool getPCMF(WebMFrame &frame, float *buffer, int &numOutSamples);
bool getPCMS16(WebMFrame &frame, short *buffer, int &numOutSamples);
+// -- GODOT begin --
+ bool getPCMF(WebMFrame &frame, float *buffer, int &numOutSamples);
+// -- GODOT end --
private:
bool openVorbis(const WebMDemuxer &demuxer);
diff --git a/thirdparty/libsimplewebm/VPXDecoder.cpp b/thirdparty/libsimplewebm/VPXDecoder.cpp
index 3f77b8f5cd..e2606f83ba 100644
--- a/thirdparty/libsimplewebm/VPXDecoder.cpp
+++ b/thirdparty/libsimplewebm/VPXDecoder.cpp
@@ -33,7 +33,8 @@
VPXDecoder::VPXDecoder(const WebMDemuxer &demuxer, unsigned threads) :
m_ctx(NULL),
m_iter(NULL),
- m_delay(0)
+ m_delay(0),
+ m_last_space(VPX_CS_UNKNOWN)
{
if (threads > 8)
threads = 8;
@@ -86,6 +87,11 @@ VPXDecoder::IMAGE_ERROR VPXDecoder::getImage(Image &image)
IMAGE_ERROR err = NO_FRAME;
if (vpx_image_t *img = vpx_codec_get_frame(m_ctx, &m_iter))
{
+ // It seems to be a common problem that UNKNOWN comes up a lot, yet FFMPEG is somehow getting accurate colour-space information.
+ // After checking FFMPEG code, *they're* getting colour-space information, so I'm assuming something like this is going on.
+ // It appears to work, at least.
+ if (img->cs != VPX_CS_UNKNOWN)
+ m_last_space = img->cs;
if ((img->fmt & VPX_IMG_FMT_PLANAR) && !(img->fmt & (VPX_IMG_FMT_HAS_ALPHA | VPX_IMG_FMT_HIGHBITDEPTH)))
{
if (img->stride[0] && img->stride[1] && img->stride[2])
@@ -95,6 +101,7 @@ VPXDecoder::IMAGE_ERROR VPXDecoder::getImage(Image &image)
image.w = img->d_w;
image.h = img->d_h;
+ image.cs = m_last_space;
image.chromaShiftW = img->x_chroma_shift;
image.chromaShiftH = img->y_chroma_shift;
@@ -119,7 +126,9 @@ VPXDecoder::IMAGE_ERROR VPXDecoder::getImage(Image &image)
/**/
+// -- GODOT begin --
#if 0
+// -- GODOT end --
static inline int ceilRshift(int val, int shift)
{
@@ -139,4 +148,7 @@ int VPXDecoder::Image::getHeight(int plane) const
return ceilRshift(h, chromaShiftH);
}
+// -- GODOT begin --
#endif
+// -- GODOT end --
+
diff --git a/thirdparty/libsimplewebm/VPXDecoder.hpp b/thirdparty/libsimplewebm/VPXDecoder.hpp
index 6108395871..5071b069cb 100644
--- a/thirdparty/libsimplewebm/VPXDecoder.hpp
+++ b/thirdparty/libsimplewebm/VPXDecoder.hpp
@@ -37,12 +37,17 @@ public:
class Image
{
public:
+// -- GODOT begin --
#if 0
+// -- GODOT end --
int getWidth(int plane) const;
int getHeight(int plane) const;
+// -- GODOT begin --
#endif
+// -- GODOT end --
int w, h;
+ int cs;
int chromaShiftW, chromaShiftH;
unsigned char *planes[3];
int linesize[3];
@@ -75,6 +80,7 @@ private:
vpx_codec_ctx *m_ctx;
const void *m_iter;
int m_delay;
+ int m_last_space;
};
#endif // VPXDECODER_HPP
diff --git a/thirdparty/misc/yuv2rgb.h b/thirdparty/misc/yuv2rgb.h
index 3ec8388246..d8f7fd6de2 100644
--- a/thirdparty/misc/yuv2rgb.h
+++ b/thirdparty/misc/yuv2rgb.h
@@ -24,6 +24,14 @@ does not infringe any patents that apply in your area before you
ship it.
*/
+/*
+ * Please note that this version has been modified for various reasons:
+ * 1. Using the Godot core typedefs
+ * 2. At some point or another the code relied on the byte order of a uint32_t, this has been fixed
+ * 3. Output has been reordered to struct { uint8_t r, g, b, a; } precisely in accordance with the function names
+ * 4. Removing unused 'dither' parameter
+ */
+
#ifndef YUV2RGB_H
#define YUV2RGB_H
@@ -803,6 +811,8 @@ static const uint32_t tables[256*3] = {
0xE6365800U
};
+/* -- Common -- */
+
#define FLAGS 0x40080100
#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
#define READY(Y) tables[Y]
@@ -820,12 +830,14 @@ do { \
#define STORE(Y,DSTPTR) \
do { \
- *(DSTPTR)++ = (Y); \
- *(DSTPTR)++ = (Y)>>22; \
*(DSTPTR)++ = (Y)>>11; \
- *(DSTPTR)++ = 255; \
+ *(DSTPTR)++ = (Y)>>22; \
+ *(DSTPTR)++ = (Y); \
+ *(DSTPTR)++ = 255; \
} while (0 == 1)
+/* -- End Common -- */
+
static void yuv422_2_rgb8888(uint8_t *dst_ptr,
const uint8_t *y_ptr,
const uint8_t *u_ptr,
@@ -834,8 +846,7 @@ static void yuv422_2_rgb8888(uint8_t *dst_ptr,
int32_t height,
int32_t y_span,
int32_t uv_span,
- int32_t dst_span,
- int32_t dither)
+ int32_t dst_span)
{
height -= 1;
while (height > 0)
@@ -909,35 +920,7 @@ static void yuv422_2_rgb8888(uint8_t *dst_ptr,
}
}
-
-#undef FLAGS
-#undef READUV
-#undef READY
-#undef FIXUP
-#undef STORE
-
-
-#define FLAGS 0x40080100
-#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
-#define READY(Y) tables[Y]
-#define FIXUP(Y) \
-do { \
- int tmp = (Y) & FLAGS; \
- if (tmp != 0) \
- { \
- tmp -= tmp>>8; \
- (Y) |= tmp; \
- tmp = FLAGS & ~(Y>>1); \
- (Y) += tmp>>8; \
- } \
-} while (0 == 1)
-
-#define STORE(Y,DSTPTR) \
-do { \
- (DSTPTR) = 0xFF000000 | (Y & 0xFF) | (0xFF00 & (Y>>14)) | (0xFF0000 & (Y<<5));\
-} while (0 == 1)
-
-static void yuv420_2_rgb8888(uint8_t *dst_ptr_,
+static void yuv420_2_rgb8888(uint8_t *dst_ptr,
const uint8_t *y_ptr,
const uint8_t *u_ptr,
const uint8_t *v_ptr,
@@ -945,12 +928,9 @@ static void yuv420_2_rgb8888(uint8_t *dst_ptr_,
int32_t height,
int32_t y_span,
int32_t uv_span,
- int32_t dst_span,
- int32_t dither)
+ int32_t dst_span)
{
- uint32_t *dst_ptr = (uint32_t *)(void *)dst_ptr_;
- dst_span >>= 2;
-
+ /* The 'dst_ptr as uint32_t' thing is not endianness-aware, so that's been removed. */
height -= 1;
while (height > 0)
{
@@ -960,36 +940,38 @@ static void yuv420_2_rgb8888(uint8_t *dst_ptr_,
{
/* Do 2 column pairs */
uint32_t uv, y0, y1;
+ uint8_t * dst_ptr_1span = dst_ptr + dst_span;
uv = READUV(*u_ptr++,*v_ptr++);
y1 = uv + READY(y_ptr[y_span]);
y0 = uv + READY(*y_ptr++);
FIXUP(y1);
FIXUP(y0);
- STORE(y1, dst_ptr[dst_span]);
- STORE(y0, *dst_ptr++);
+ STORE(y1, dst_ptr_1span);
+ STORE(y0, dst_ptr);
y1 = uv + READY(y_ptr[y_span]);
y0 = uv + READY(*y_ptr++);
FIXUP(y1);
FIXUP(y0);
- STORE(y1, dst_ptr[dst_span]);
- STORE(y0, *dst_ptr++);
+ STORE(y1, dst_ptr_1span);
+ STORE(y0, dst_ptr);
height += (2<<16);
}
if ((height>>16) == 0)
{
/* Trailing column pair */
uint32_t uv, y0, y1;
+ uint8_t * dst_ptr_1span = dst_ptr + dst_span;
uv = READUV(*u_ptr,*v_ptr);
y1 = uv + READY(y_ptr[y_span]);
y0 = uv + READY(*y_ptr++);
FIXUP(y1);
FIXUP(y0);
- STORE(y0, dst_ptr[dst_span]);
- STORE(y1, *dst_ptr++);
+ STORE(y0, dst_ptr_1span);
+ STORE(y1, dst_ptr);
}
- dst_ptr += dst_span*2-width;
+ dst_ptr += (dst_span * 2) - (width * 4);
y_ptr += y_span*2-width;
u_ptr += uv_span-(width>>1);
v_ptr += uv_span-(width>>1);
@@ -1011,8 +993,8 @@ static void yuv420_2_rgb8888(uint8_t *dst_ptr_,
y0 = uv + READY(*y_ptr++);
FIXUP(y1);
FIXUP(y0);
- STORE(y1, *dst_ptr++);
- STORE(y0, *dst_ptr++);
+ STORE(y1, dst_ptr);
+ STORE(y0, dst_ptr);
height += (2<<16);
}
if ((height>>16) == 0)
@@ -1023,42 +1005,11 @@ static void yuv420_2_rgb8888(uint8_t *dst_ptr_,
uv = READUV(*u_ptr++,*v_ptr++);
y0 = uv + READY(*y_ptr++);
FIXUP(y0);
- STORE(y0, *dst_ptr++);
+ STORE(y0, dst_ptr);
}
}
}
-
-
-#undef FLAGS
-#undef READUV
-#undef READY
-#undef FIXUP
-#undef STORE
-
-#define FLAGS 0x40080100
-#define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
-#define READY(Y) tables[Y]
-#define FIXUP(Y) \
-do { \
- int tmp = (Y) & FLAGS; \
- if (tmp != 0) \
- { \
- tmp -= tmp>>8; \
- (Y) |= tmp; \
- tmp = FLAGS & ~(Y>>1); \
- (Y) += tmp>>8; \
- } \
-} while (0 == 1)
-
-#define STORE(Y,DSTPTR) \
-do { \
- *(DSTPTR)++ = (Y); \
- *(DSTPTR)++ = (Y)>>22; \
- *(DSTPTR)++ = (Y)>>11; \
- *(DSTPTR)++ = 255; \
-} while (0 == 1)
-
static void yuv444_2_rgb8888(uint8_t *dst_ptr,
const uint8_t *y_ptr,
const uint8_t *u_ptr,
@@ -1067,8 +1018,7 @@ static void yuv444_2_rgb8888(uint8_t *dst_ptr,
int32_t height,
int32_t y_span,
int32_t uv_span,
- int32_t dst_span,
- int32_t dither)
+ int32_t dst_span)
{
height -= 1;
while (height > 0)
@@ -1143,4 +1093,11 @@ static void yuv444_2_rgb8888(uint8_t *dst_ptr,
height -= 1;
}
}
+
+#undef FLAGS
+#undef READUV
+#undef READY
+#undef FIXUP
+#undef STORE
+
#endif // YUV2RGB_H