summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ISSUE_TEMPLATE.md5
-rw-r--r--SConstruct5
-rw-r--r--core/global_constants.cpp37
-rw-r--r--core/math/a_star.cpp2
-rw-r--r--core/math/math_2d.cpp63
-rw-r--r--core/math/math_2d.h88
-rw-r--r--core/math/matrix3.cpp9
-rw-r--r--core/math/matrix3.h3
-rw-r--r--core/os/file_access.cpp31
-rw-r--r--core/os/file_access.h1
-rw-r--r--core/os/input_event.cpp18
-rw-r--r--core/os/input_event.h4
-rw-r--r--core/os/threaded_array_processor.cpp2
-rw-r--r--core/os/threaded_array_processor.h80
-rw-r--r--core/string_buffer.cpp2
-rw-r--r--core/string_db.h17
-rw-r--r--core/ustring.cpp95
-rw-r--r--core/ustring.h26
-rw-r--r--doc/classes/ARVRController.xml5
-rw-r--r--doc/classes/ARVRServer.xml11
-rw-r--r--doc/classes/AnimationPlayer.xml1
-rw-r--r--doc/classes/ColorPickerButton.xml4
-rw-r--r--doc/classes/MenuButton.xml2
-rw-r--r--doc/classes/Mutex.xml6
-rw-r--r--doc/classes/OptionButton.xml7
-rw-r--r--doc/classes/Physics2DDirectSpaceState.xml67
-rw-r--r--doc/classes/PhysicsDirectSpaceState.xml28
-rw-r--r--doc/classes/Semaphore.xml6
-rw-r--r--doc/classes/TextEdit.xml17
-rw-r--r--doc/classes/TileMap.xml3
-rw-r--r--doc/classes/Timer.xml10
-rw-r--r--doc/classes/Transform2D.xml30
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp17
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp14
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp8
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h1
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp3
-rw-r--r--drivers/gles3/shaders/scene.glsl96
-rw-r--r--editor/create_dialog.cpp27
-rw-r--r--editor/editor_about.cpp2
-rw-r--r--editor/editor_data.cpp9
-rw-r--r--editor/editor_data.h1
-rw-r--r--editor/editor_file_dialog.cpp63
-rw-r--r--editor/editor_file_dialog.h1
-rw-r--r--editor/editor_file_system.cpp46
-rw-r--r--editor/editor_fonts.cpp15
-rw-r--r--editor/editor_help.cpp98
-rw-r--r--editor/editor_settings.cpp38
-rw-r--r--editor/editor_themes.cpp101
-rw-r--r--editor/filesystem_dock.cpp68
-rw-r--r--editor/filesystem_dock.h1
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp282
-rw-r--r--editor/import/editor_scene_importer_gltf.h39
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp110
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp4
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp52
-rw-r--r--editor/plugins/script_text_editor.cpp176
-rw-r--r--editor/plugins/shader_editor_plugin.cpp125
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp246
-rw-r--r--editor/plugins/spatial_editor_plugin.h7
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp2
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_plugin.cpp2
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp295
-rw-r--r--editor/plugins/tile_set_editor_plugin.h26
-rw-r--r--editor/project_manager.cpp6
-rw-r--r--editor/project_settings_editor.cpp2
-rw-r--r--editor/property_editor.cpp52
-rw-r--r--editor/scene_tree_dock.cpp4
-rw-r--r--editor/settings_config_dialog.cpp2
-rw-r--r--editor/spatial_editor_gizmos.cpp845
-rw-r--r--editor/spatial_editor_gizmos.h51
-rw-r--r--main/main.cpp6
-rw-r--r--modules/bullet/bullet_physics_server.cpp2
-rw-r--r--modules/bullet/godot_result_callbacks.cpp5
-rw-r--r--modules/bullet/rigid_body_bullet.cpp39
-rw-r--r--modules/bullet/rigid_body_bullet.h1
-rw-r--r--modules/mono/csharp_script.cpp94
-rw-r--r--modules/mono/csharp_script.h15
-rw-r--r--modules/mono/editor/bindings_generator.cpp840
-rw-r--r--modules/mono/editor/bindings_generator.h171
-rw-r--r--modules/mono/editor/csharp_project.cpp6
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp8
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp18
-rw-r--r--modules/mono/editor/mono_bottom_panel.cpp6
-rw-r--r--modules/mono/glue/cs_files/Error.cs47
-rw-r--r--modules/mono/glue/cs_files/ExportAttribute.cs8
-rw-r--r--modules/mono/glue/cs_files/GD.cs4
-rw-r--r--modules/mono/glue/cs_files/Rect2.cs12
-rw-r--r--modules/mono/glue/glue_header.h8
-rw-r--r--modules/mono/mono_gc_handle.cpp5
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp9
-rw-r--r--modules/mono/mono_gd/gd_mono.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp5
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h9
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h2
-rw-r--r--modules/opus/register_types.cpp15
-rw-r--r--platform/osx/detect.py3
-rw-r--r--platform/uwp/export/export.cpp70
-rw-r--r--platform/windows/detect.py11
-rw-r--r--platform/x11/detect.py4
-rw-r--r--platform/x11/os_x11.cpp4
-rw-r--r--scene/2d/particles_2d.cpp7
-rw-r--r--scene/2d/particles_2d.h1
-rw-r--r--scene/2d/tile_map.cpp2
-rw-r--r--scene/3d/arvr_nodes.cpp10
-rw-r--r--scene/3d/baked_lightmap.cpp4
-rw-r--r--scene/3d/camera.cpp17
-rw-r--r--scene/3d/camera.h2
-rw-r--r--scene/3d/particles.cpp7
-rw-r--r--scene/3d/particles.h1
-rw-r--r--scene/3d/skeleton.cpp25
-rw-r--r--scene/3d/skeleton.h2
-rw-r--r--scene/3d/spatial.cpp8
-rw-r--r--scene/3d/voxel_light_baker.cpp74
-rw-r--r--scene/3d/voxel_light_baker.h5
-rw-r--r--scene/animation/animation_tree_player.cpp23
-rw-r--r--scene/animation/animation_tree_player.h1
-rw-r--r--scene/gui/base_button.cpp8
-rw-r--r--scene/gui/button.h3
-rw-r--r--scene/gui/color_picker.cpp18
-rw-r--r--scene/gui/color_picker.h4
-rw-r--r--scene/gui/menu_button.cpp28
-rw-r--r--scene/gui/menu_button.h5
-rw-r--r--scene/gui/option_button.cpp77
-rw-r--r--scene/gui/option_button.h2
-rw-r--r--scene/gui/rich_text_label.cpp28
-rw-r--r--scene/gui/split_container.cpp66
-rw-r--r--scene/gui/split_container.h4
-rw-r--r--scene/gui/text_edit.cpp148
-rw-r--r--scene/gui/text_edit.h4
-rw-r--r--scene/gui/tree.cpp56
-rw-r--r--scene/gui/tree.h8
-rw-r--r--scene/main/node.cpp3
-rw-r--r--scene/main/scene_tree.cpp15
-rw-r--r--scene/main/scene_tree.h9
-rw-r--r--scene/main/viewport.cpp10
-rw-r--r--scene/main/viewport.h1
-rw-r--r--scene/register_scene_types.cpp16
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/shader.cpp77
-rw-r--r--scene/resources/shader.h17
-rw-r--r--scene/resources/texture.cpp2
-rw-r--r--scene/resources/tile_set.cpp4
-rw-r--r--servers/arvr/arvr_positional_tracker.cpp23
-rw-r--r--servers/arvr_server.cpp21
-rw-r--r--servers/arvr_server.h14
-rw-r--r--servers/audio_server.cpp8
-rw-r--r--servers/physics_2d_server.cpp4
-rw-r--r--servers/visual/rasterizer.h2
-rw-r--r--servers/visual/shader_language.cpp1
-rw-r--r--servers/visual/shader_types.cpp1
-rw-r--r--servers/visual/visual_server_raster.h1
-rw-r--r--servers/visual/visual_server_wrap_mt.h1
-rw-r--r--servers/visual_server.h1
159 files changed, 3810 insertions, 2134 deletions
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index dbfb2bdeab..ddddc3a1a9 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -1,5 +1,5 @@
**Godot version:**
-<!-- If thirdparty of self-compiled, specify the build date or commit hash. -->
+<!-- If thirdparty or self-compiled, specify the build date or commit hash. -->
**OS/device including version:**
@@ -15,3 +15,6 @@
**Minimal reproduction project:**
<!-- Optional but greatly speeds up debugging. You can drag and drop a zip archive to upload it. -->
+
+
+- [ ] I searched the existing [GitHub issues](https://github.com/godotengine/godot/issues?utf8=%E2%9C%93&q=is%3Aissue+) for potential duplicates.
diff --git a/SConstruct b/SConstruct
index 88cd1494f1..88b29695cb 100644
--- a/SConstruct
+++ b/SConstruct
@@ -168,7 +168,6 @@ opts.Add(BoolVariable('vsproj', "Generate Visual Studio Project.", False))
opts.Add(EnumVariable('warnings', "Set the level of warnings emitted during compilation", 'no', ('extra', 'all', 'moderate', 'no')))
opts.Add(BoolVariable('progress', "Show a progress indicator during build", True))
opts.Add(BoolVariable('dev', "If yes, alias for verbose=yes warnings=all", False))
-opts.Add(BoolVariable('openmp', "If yes, enable OpenMP", True))
opts.Add(EnumVariable('macports_clang', "Build using clang from MacPorts", 'no', ('no', '5.0', 'devel')))
# Thirdparty libraries
@@ -411,9 +410,7 @@ if selected_platform in platform_list:
methods.update_version(env.module_version_string)
- suffix += env.module_version_string
-
- env["PROGSUFFIX"] = suffix + env["PROGSUFFIX"]
+ env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"]
env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index a8f6e4da6c..b390590cf2 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -98,6 +98,11 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(MARGIN_RIGHT);
BIND_GLOBAL_ENUM_CONSTANT(MARGIN_BOTTOM);
+ BIND_GLOBAL_ENUM_CONSTANT(CORNER_TOP_LEFT);
+ BIND_GLOBAL_ENUM_CONSTANT(CORNER_TOP_RIGHT);
+ BIND_GLOBAL_ENUM_CONSTANT(CORNER_BOTTOM_RIGHT);
+ BIND_GLOBAL_ENUM_CONSTANT(CORNER_BOTTOM_LEFT);
+
BIND_GLOBAL_ENUM_CONSTANT(VERTICAL);
BIND_GLOBAL_ENUM_CONSTANT(HORIZONTAL);
@@ -573,6 +578,38 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3_ARRAY", Variant::POOL_VECTOR3_ARRAY);
BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_COLOR_ARRAY", Variant::POOL_COLOR_ARRAY);
BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_MAX", Variant::VARIANT_MAX);
+
+ //comparation
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_EQUAL", Variant::OP_EQUAL);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NOT_EQUAL", Variant::OP_NOT_EQUAL);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_LESS", Variant::OP_LESS);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_LESS_EQUAL", Variant::OP_LESS_EQUAL);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_GREATER", Variant::OP_GREATER);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_GREATER_EQUAL", Variant::OP_GREATER_EQUAL);
+ //mathematic
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_ADD", Variant::OP_ADD);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SUBTRACT", Variant::OP_SUBTRACT);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MULTIPLY", Variant::OP_MULTIPLY);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_DIVIDE", Variant::OP_DIVIDE);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_STRING_CONCAT", Variant::OP_STRING_CONCAT);
+ //bitwise
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_AND", Variant::OP_BIT_AND);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_OR", Variant::OP_BIT_OR);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_XOR", Variant::OP_BIT_XOR);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_NEGATE", Variant::OP_BIT_NEGATE);
+ //logic
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_AND", Variant::OP_AND);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_OR", Variant::OP_OR);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_XOR", Variant::OP_XOR);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NOT", Variant::OP_NOT);
+ //containment
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_IN", Variant::OP_IN);
+ BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MAX", Variant::OP_MAX);
}
void unregister_global_constants() {
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 4498efeb41..7c5dbc895a 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -459,7 +459,7 @@ void AStar::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar::has_point);
ClassDB::bind_method(D_METHOD("get_points"), &AStar::get_points);
- ClassDB::bind_method(D_METHOD("get_point_connections"), &AStar::get_point_connections);
+ ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar::get_point_connections);
ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true));
ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar::disconnect_points);
diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp
index 11003c1cd5..8ad164d4dc 100644
--- a/core/math/math_2d.cpp
+++ b/core/math/math_2d.cpp
@@ -102,69 +102,6 @@ Vector2 Vector2::cross(real_t p_other) const {
return Vector2(p_other * y, -p_other * x);
}
-Vector2 Vector2::operator+(const Vector2 &p_v) const {
-
- return Vector2(x + p_v.x, y + p_v.y);
-}
-void Vector2::operator+=(const Vector2 &p_v) {
-
- x += p_v.x;
- y += p_v.y;
-}
-Vector2 Vector2::operator-(const Vector2 &p_v) const {
-
- return Vector2(x - p_v.x, y - p_v.y);
-}
-void Vector2::operator-=(const Vector2 &p_v) {
-
- x -= p_v.x;
- y -= p_v.y;
-}
-
-Vector2 Vector2::operator*(const Vector2 &p_v1) const {
-
- return Vector2(x * p_v1.x, y * p_v1.y);
-};
-
-Vector2 Vector2::operator*(const real_t &rvalue) const {
-
- return Vector2(x * rvalue, y * rvalue);
-};
-void Vector2::operator*=(const real_t &rvalue) {
-
- x *= rvalue;
- y *= rvalue;
-};
-
-Vector2 Vector2::operator/(const Vector2 &p_v1) const {
-
- return Vector2(x / p_v1.x, y / p_v1.y);
-};
-
-Vector2 Vector2::operator/(const real_t &rvalue) const {
-
- return Vector2(x / rvalue, y / rvalue);
-};
-
-void Vector2::operator/=(const real_t &rvalue) {
-
- x /= rvalue;
- y /= rvalue;
-};
-
-Vector2 Vector2::operator-() const {
-
- return Vector2(-x, -y);
-}
-
-bool Vector2::operator==(const Vector2 &p_vec2) const {
-
- return x == p_vec2.x && y == p_vec2.y;
-}
-bool Vector2::operator!=(const Vector2 &p_vec2) const {
-
- return x != p_vec2.x || y != p_vec2.y;
-}
Vector2 Vector2::floor() const {
return Vector2(Math::floor(x), Math::floor(y));
diff --git a/core/math/math_2d.h b/core/math/math_2d.h
index 60351445c0..4939e7ae99 100644
--- a/core/math/math_2d.h
+++ b/core/math/math_2d.h
@@ -187,6 +187,70 @@ _FORCE_INLINE_ Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) {
return p_vec * p_scalar;
}
+_FORCE_INLINE_ Vector2 Vector2::operator+(const Vector2 &p_v) const {
+
+ return Vector2(x + p_v.x, y + p_v.y);
+}
+_FORCE_INLINE_ void Vector2::operator+=(const Vector2 &p_v) {
+
+ x += p_v.x;
+ y += p_v.y;
+}
+_FORCE_INLINE_ Vector2 Vector2::operator-(const Vector2 &p_v) const {
+
+ return Vector2(x - p_v.x, y - p_v.y);
+}
+_FORCE_INLINE_ void Vector2::operator-=(const Vector2 &p_v) {
+
+ x -= p_v.x;
+ y -= p_v.y;
+}
+
+_FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const {
+
+ return Vector2(x * p_v1.x, y * p_v1.y);
+};
+
+_FORCE_INLINE_ Vector2 Vector2::operator*(const real_t &rvalue) const {
+
+ return Vector2(x * rvalue, y * rvalue);
+};
+_FORCE_INLINE_ void Vector2::operator*=(const real_t &rvalue) {
+
+ x *= rvalue;
+ y *= rvalue;
+};
+
+_FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const {
+
+ return Vector2(x / p_v1.x, y / p_v1.y);
+};
+
+_FORCE_INLINE_ Vector2 Vector2::operator/(const real_t &rvalue) const {
+
+ return Vector2(x / rvalue, y / rvalue);
+};
+
+_FORCE_INLINE_ void Vector2::operator/=(const real_t &rvalue) {
+
+ x /= rvalue;
+ y /= rvalue;
+};
+
+_FORCE_INLINE_ Vector2 Vector2::operator-() const {
+
+ return Vector2(-x, -y);
+}
+
+_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const {
+
+ return x == p_vec2.x && y == p_vec2.y;
+}
+_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
+
+ return x != p_vec2.x || y != p_vec2.y;
+}
+
Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const {
Vector2 res = *this;
@@ -239,22 +303,31 @@ struct Rect2 {
inline real_t distance_to(const Vector2 &p_point) const {
- real_t dist = 1e20;
+ real_t dist;
+ bool inside = true;
if (p_point.x < position.x) {
- dist = MIN(dist, position.x - p_point.x);
+ real_t d = position.x - p_point.x;
+ dist = inside ? d : MIN(dist, d);
+ inside = false;
}
if (p_point.y < position.y) {
- dist = MIN(dist, position.y - p_point.y);
+ real_t d = position.y - p_point.y;
+ dist = inside ? d : MIN(dist, d);
+ inside = false;
}
if (p_point.x >= (position.x + size.x)) {
- dist = MIN(p_point.x - (position.x + size.x), dist);
+ real_t d = p_point.x - (position.x + size.x);
+ dist = inside ? d : MIN(dist, d);
+ inside = false;
}
if (p_point.y >= (position.y + size.y)) {
- dist = MIN(p_point.y - (position.y + size.y), dist);
+ real_t d = p_point.y - (position.y + size.y);
+ dist = inside ? d : MIN(dist, d);
+ inside = false;
}
- if (dist == 1e20)
+ if (inside)
return 0;
else
return dist;
@@ -336,9 +409,10 @@ struct Rect2 {
g.size.height += p_by * 2;
return g;
}
+
inline Rect2 grow_margin(Margin p_margin, real_t p_amount) const {
Rect2 g = *this;
- g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
+ 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);
diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp
index ab3bca79ae..5346141470 100644
--- a/core/math/matrix3.cpp
+++ b/core/math/matrix3.cpp
@@ -311,6 +311,15 @@ void Basis::rotate(const Vector3 &p_axis, real_t p_phi) {
*this = rotated(p_axis, p_phi);
}
+void Basis::rotate_local(const Vector3 &p_axis, real_t p_phi) {
+
+ *this = rotated_local(p_axis, p_phi);
+}
+Basis Basis::rotated_local(const Vector3 &p_axis, real_t p_phi) const {
+
+ return (*this) * Basis(p_axis, p_phi);
+}
+
Basis Basis::rotated(const Vector3 &p_euler) const {
return Basis(p_euler) * (*this);
}
diff --git a/core/math/matrix3.h b/core/math/matrix3.h
index 9a33b8203d..9a75308f08 100644
--- a/core/math/matrix3.h
+++ b/core/math/matrix3.h
@@ -75,6 +75,9 @@ public:
void rotate(const Vector3 &p_axis, real_t p_phi);
Basis rotated(const Vector3 &p_axis, real_t p_phi) const;
+ void rotate_local(const Vector3 &p_axis, real_t p_phi);
+ Basis rotated_local(const Vector3 &p_axis, real_t p_phi) const;
+
void rotate(const Vector3 &p_euler);
Basis rotated(const Vector3 &p_euler) const;
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index 20c1221f2b..133c70b671 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -569,6 +569,37 @@ String FileAccess::get_md5(const String &p_file) {
return ret;
}
+String FileAccess::get_multiple_md5(const Vector<String> &p_file) {
+
+ MD5_CTX md5;
+ MD5Init(&md5);
+
+ for (int i = 0; i < p_file.size(); i++) {
+ FileAccess *f = FileAccess::open(p_file[i], READ);
+ ERR_CONTINUE(!f);
+
+ unsigned char step[32768];
+
+ while (true) {
+
+ int br = f->get_buffer(step, 32768);
+ if (br > 0) {
+
+ MD5Update(&md5, step, br);
+ }
+ if (br < 4096)
+ break;
+ }
+ memdelete(f);
+ }
+
+ MD5Final(&md5);
+
+ String ret = String::md5(md5.digest);
+
+ return ret;
+}
+
String FileAccess::get_sha256(const String &p_file) {
FileAccess *f = FileAccess::open(p_file, READ);
diff --git a/core/os/file_access.h b/core/os/file_access.h
index 6fda3d9668..548d7b71f1 100644
--- a/core/os/file_access.h
+++ b/core/os/file_access.h
@@ -155,6 +155,7 @@ public:
static String get_md5(const String &p_file);
static String get_sha256(const String &p_file);
+ static String get_multiple_md5(const Vector<String> &p_file);
static Vector<uint8_t> get_file_as_array(const String &p_path);
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index 9b2bd30868..0cab8c10ef 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -32,14 +32,6 @@
#include "input_map.h"
#include "os/keyboard.h"
-void InputEvent::set_id(uint32_t p_id) {
- id = p_id;
-}
-
-uint32_t InputEvent::get_id() const {
- return id;
-}
-
void InputEvent::set_device(int p_device) {
device = p_device;
}
@@ -99,9 +91,6 @@ bool InputEvent::is_action_type() const {
void InputEvent::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_id", "id"), &InputEvent::set_id);
- ClassDB::bind_method(D_METHOD("get_id"), &InputEvent::get_id);
-
ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device);
ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device);
@@ -125,7 +114,6 @@ void InputEvent::_bind_methods() {
InputEvent::InputEvent() {
- id = 0;
device = 0;
}
@@ -441,7 +429,6 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co
Ref<InputEventMouseButton> mb;
mb.instance();
- mb->set_id(get_id());
mb->set_device(get_device());
mb->set_modifiers_from_event(this);
@@ -557,7 +544,6 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co
Ref<InputEventMouseMotion> mm;
mm.instance();
- mm->set_id(get_id());
mm->set_device(get_device());
mm->set_modifiers_from_event(this);
@@ -764,7 +750,6 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co
Ref<InputEventScreenTouch> st;
st.instance();
- st->set_id(get_id());
st->set_device(get_device());
st->set_index(index);
st->set_position(p_xform.xform(pos + p_local_ofs));
@@ -845,7 +830,6 @@ Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, con
sd.instance();
- sd->set_id(get_id());
sd->set_device(get_device());
sd->set_index(index);
@@ -968,7 +952,6 @@ Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform,
Ref<InputEventMagnifyGesture> ev;
ev.instance();
- ev->set_id(get_id());
ev->set_device(get_device());
ev->set_modifiers_from_event(this);
@@ -1006,7 +989,6 @@ Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, con
Ref<InputEventPanGesture> ev;
ev.instance();
- ev->set_id(get_id());
ev->set_device(get_device());
ev->set_modifiers_from_event(this);
diff --git a/core/os/input_event.h b/core/os/input_event.h
index 614a3289ba..9b1a2736b1 100644
--- a/core/os/input_event.h
+++ b/core/os/input_event.h
@@ -144,16 +144,12 @@ enum JoystickList {
class InputEvent : public Resource {
GDCLASS(InputEvent, Resource)
- uint32_t id;
int device;
protected:
static void _bind_methods();
public:
- void set_id(uint32_t p_id);
- uint32_t get_id() const;
-
void set_device(int p_device);
int get_device() const;
diff --git a/core/os/threaded_array_processor.cpp b/core/os/threaded_array_processor.cpp
new file mode 100644
index 0000000000..8e92508ea5
--- /dev/null
+++ b/core/os/threaded_array_processor.cpp
@@ -0,0 +1,2 @@
+#include "threaded_array_processor.h"
+
diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h
new file mode 100644
index 0000000000..e584fbb193
--- /dev/null
+++ b/core/os/threaded_array_processor.h
@@ -0,0 +1,80 @@
+#ifndef THREADED_ARRAY_PROCESSOR_H
+#define THREADED_ARRAY_PROCESSOR_H
+
+#include "os/mutex.h"
+#include "os/os.h"
+#include "os/thread.h"
+#include "safe_refcount.h"
+#include "thread_safe.h"
+
+template <class C, class U>
+struct ThreadArrayProcessData {
+ uint32_t elements;
+ uint32_t index;
+ C *instance;
+ U userdata;
+ void (C::*method)(uint32_t, U);
+
+ void process(uint32_t p_index) {
+ (instance->*method)(p_index, userdata);
+ }
+};
+
+#ifndef NO_THREADS
+
+template <class T>
+void process_array_thread(void *ud) {
+
+ T &data = *(T *)ud;
+ while (true) {
+ uint32_t index = atomic_increment(&data.index);
+ if (index >= data.elements)
+ break;
+ data.process(index);
+ }
+}
+
+template <class C, class M, class U>
+void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
+
+ ThreadArrayProcessData<C, U> data;
+ data.method = p_method;
+ data.instance = p_instance;
+ data.userdata = p_userdata;
+ data.index = 0;
+ data.elements = p_elements;
+ data.process(data.index); //process first, let threads increment for next
+
+ Vector<Thread *> threads;
+
+ threads.resize(OS::get_singleton()->get_processor_count());
+
+ for (int i = 0; i < threads.size(); i++) {
+ threads[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U> >, &data);
+ }
+
+ for (int i = 0; i < threads.size(); i++) {
+ Thread::wait_to_finish(threads[i]);
+ memdelete(threads[i]);
+ }
+}
+
+#else
+
+template <class C, class M, class U>
+void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
+
+ ThreadArrayProcessData<C, U> data;
+ data.method = p_method;
+ data.instance = p_instance;
+ data.userdata = p_userdata;
+ data.index = 0;
+ data.elements = p_elements;
+ for (uint32_t i = 0; i < p_elements; i++) {
+ data.process(i);
+ }
+}
+
+#endif
+
+#endif // THREADED_ARRAY_PROCESSOR_H
diff --git a/core/string_buffer.cpp b/core/string_buffer.cpp
index 8489df2599..3b47685fc9 100644
--- a/core/string_buffer.cpp
+++ b/core/string_buffer.cpp
@@ -46,7 +46,7 @@ StringBuffer &StringBuffer::append(const char *p_str) {
reserve(string_length + len + 1);
CharType *buf = current_buffer_ptr();
- for (const char *c_ptr = p_str; c_ptr; ++c_ptr) {
+ for (const char *c_ptr = p_str; *c_ptr; ++c_ptr) {
buf[string_length++] = *c_ptr;
}
return *this;
diff --git a/core/string_db.h b/core/string_db.h
index de91e2abd8..9665198ecd 100644
--- a/core/string_db.h
+++ b/core/string_db.h
@@ -138,7 +138,22 @@ public:
_FORCE_INLINE_ bool operator()(const StringName &l, const StringName &r) const {
- return l.operator String() < r.operator String();
+ const char *l_cname = l._data ? l._data->cname : "";
+ const char *r_cname = r._data ? r._data->cname : "";
+
+ if (l_cname) {
+
+ if (r_cname)
+ return is_str_less(l_cname, r_cname);
+ else
+ return is_str_less(l_cname, r._data->name.ptr());
+ } else {
+
+ if (r_cname)
+ return is_str_less(l._data->name.ptr(), r_cname);
+ else
+ return is_str_less(l._data->name.ptr(), r._data->name.ptr());
+ }
}
};
diff --git a/core/ustring.cpp b/core/ustring.cpp
index ceafe209ea..fc6312355a 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -56,34 +56,49 @@
#define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9')
#define IS_HEX_DIGIT(m_d) (((m_d) >= '0' && (m_d) <= '9') || ((m_d) >= 'a' && (m_d) <= 'f') || ((m_d) >= 'A' && (m_d) <= 'F'))
-/** STRING **/
+bool is_symbol(CharType c) {
+ return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
+}
-bool CharString::operator<(const CharString &p_right) const {
+bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) {
- if (length() == 0) {
- return p_right.length() != 0;
+ const String &s = p_s;
+ int beg = CLAMP(p_col, 0, s.length());
+ int end = beg;
+
+ if (s[beg] > 32 || beg == s.length()) {
+
+ bool symbol = beg < s.length() && is_symbol(s[beg]);
+
+ while (beg > 0 && s[beg - 1] > 32 && (symbol == is_symbol(s[beg - 1]))) {
+ beg--;
+ }
+ while (end < s.length() && s[end + 1] > 32 && (symbol == is_symbol(s[end + 1]))) {
+ end++;
+ }
+
+ if (end < s.length())
+ end += 1;
+
+ r_beg = beg;
+ r_end = end;
+
+ return true;
+ } else {
+
+ return false;
}
+}
- const char *this_str = get_data();
- const char *that_str = p_right.get_data();
- while (true) {
+/** STRING **/
- if (*that_str == 0 && *this_str == 0)
- return false; //this can't be equal, sadly
- else if (*this_str == 0)
- return true; //if this is empty, and the other one is not, then we're less.. I think?
- else if (*that_str == 0)
- return false; //otherwise the other one is smaller..
- else if (*this_str < *that_str) //more than
- return true;
- else if (*this_str > *that_str) //less than
- return false;
+bool CharString::operator<(const CharString &p_right) const {
- this_str++;
- that_str++;
+ if (length() == 0) {
+ return p_right.length() != 0;
}
- return false; //should never reach here anyway
+ return is_str_less(get_data(), p_right.get_data());
}
const char *CharString::get_data() const {
@@ -372,25 +387,7 @@ bool String::operator<(const CharType *p_str) const {
if (empty())
return true;
- const CharType *this_str = c_str();
- while (true) {
-
- if (*p_str == 0 && *this_str == 0)
- return false; //this can't be equal, sadly
- else if (*this_str == 0)
- return true; //if this is empty, and the other one is not, then we're less.. I think?
- else if (*p_str == 0)
- return false; //otherwise the other one is smaller..
- else if (*this_str < *p_str) //more than
- return true;
- else if (*this_str > *p_str) //less than
- return false;
-
- this_str++;
- p_str++;
- }
-
- return false; //should never reach here anyway
+ return is_str_less(c_str(), p_str);
}
bool String::operator<=(const String &p_str) const {
@@ -405,25 +402,7 @@ bool String::operator<(const char *p_str) const {
if (empty())
return true;
- const CharType *this_str = c_str();
- while (true) {
-
- if (*p_str == 0 && *this_str == 0)
- return false; //this can't be equal, sadly
- else if (*this_str == 0)
- return true; //if this is empty, and the other one is not, then we're less.. I think?
- else if (*p_str == 0)
- return false; //otherwise the other one is smaller..
- else if (*this_str < *p_str) //more than
- return true;
- else if (*this_str > *p_str) //less than
- return false;
-
- this_str++;
- p_str++;
- }
-
- return false; //should never reach here anyway
+ return is_str_less(c_str(), p_str);
}
bool String::operator<(const String &p_str) const {
diff --git a/core/ustring.h b/core/ustring.h
index 73537bfd13..3be3161a4a 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -279,6 +279,29 @@ struct NaturalNoCaseComparator {
}
};
+template <typename L, typename R>
+_FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
+
+ while (true) {
+
+ if (*l_ptr == 0 && *r_ptr == 0)
+ return false;
+ else if (*l_ptr == 0)
+ return true;
+ else if (*r_ptr == 0)
+ return false;
+ else if (*l_ptr < *r_ptr)
+ return true;
+ else if (*l_ptr > *r_ptr)
+ return false;
+
+ l_ptr++;
+ r_ptr++;
+ }
+
+ CRASH_COND(true); // unreachable
+}
+
/* end of namespace */
//tool translate
@@ -295,4 +318,7 @@ String TTR(const String &);
//tool or regular translate
String RTR(const String &);
+bool is_symbol(CharType c);
+bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end);
+
#endif
diff --git a/doc/classes/ARVRController.xml b/doc/classes/ARVRController.xml
index 47a9341643..2adc073ebe 100644
--- a/doc/classes/ARVRController.xml
+++ b/doc/classes/ARVRController.xml
@@ -62,7 +62,10 @@
</methods>
<members>
<member name="controller_id" type="int" setter="set_controller_id" getter="get_controller_id">
- The controller's id. The first controller that the [ARVRServer] detects will have id 1, the second id 2, the third id 3, etc. When a controller is turned off, it's slot is freed. This ensures controllers will keep the same id even when controllers with lower ids are turned off.
+ The controller's id.
+ A controller id of 0 is unbound and will always result in an inactive node. Controller id 1 is reserved for the first controller that identifies itself as the left hand controller and id 2 is reserved for the first controller that identifies itself as the right hand controller.
+ For any other controller that the [ARVRServer] detects we continue with controller id 3.
+ When a controller is turned off, its slot is freed. This ensures controllers will keep the same id even when controllers with lower ids are turned off.
</member>
<member name="rumble" type="float" setter="set_rumble" getter="get_rumble">
The degree to which the tracker rumbles. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code]. If changed, updates [member ARVRPositionalTracker.rumble] accordingly.
diff --git a/doc/classes/ARVRServer.xml b/doc/classes/ARVRServer.xml
index 17202c8c2c..ffe6c35240 100644
--- a/doc/classes/ARVRServer.xml
+++ b/doc/classes/ARVRServer.xml
@@ -14,7 +14,7 @@
<method name="center_on_hmd">
<return type="void">
</return>
- <argument index="0" name="ignore_tilt" type="bool">
+ <argument index="0" name="rotation_mode" type="bool">
</argument>
<argument index="1" name="keep_height" type="bool">
</argument>
@@ -154,5 +154,14 @@
<constant name="TRACKER_ANY" value="255" enum="TrackerType">
Used internally to select all trackers.
</constant>
+ <constant name="RESET_FULL_ROTATION" value="0" enum="RotationMode">
+ Fully reset the orientation of the HMD. Regardless of what direction the user is looking to in the real world. The user will look dead ahead in the virtual world.
+ </constant>
+ <constant name="RESET_BUT_KEEP_TILT" value="1" enum="RotationMode">
+ Resets the orientation but keeps the tilt of the device. So if we're looking down, we keep looking down but heading will be reset.
+ </constant>
+ <constant name="DONT_RESET_ROTATION" value="2" enum="RotationMode">
+ Does not reset the orientation of the HMD, only the position of the player gets centered.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index 570f5e9741..a244788020 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -133,6 +133,7 @@
<return type="float">
</return>
<description>
+ Returns the speed scaling ratio of the current animation channel. For instance, if this value is 1 then the animation plays at normal speed. If it's 0.5 then it plays at half speed. If it's 2 then it plays at double speed.
</description>
</method>
<method name="has_animation" qualifiers="const">
diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml
index 185460eef2..87d00b7600 100644
--- a/doc/classes/ColorPickerButton.xml
+++ b/doc/classes/ColorPickerButton.xml
@@ -11,14 +11,14 @@
<demos>
</demos>
<methods>
- <method name="get_picker">
+ <method name="get_picker" qualifiers="const">
<return type="ColorPicker">
</return>
<description>
Returns the [code]ColorPicker[/code] that this [code]ColorPickerButton[/code] toggles.
</description>
</method>
- <method name="get_popup">
+ <method name="get_popup" qualifiers="const">
<return type="PopupPanel">
</return>
<description>
diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml
index c41c86d693..22231cfdf3 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -11,7 +11,7 @@
<demos>
</demos>
<methods>
- <method name="get_popup">
+ <method name="get_popup" qualifiers="const">
<return type="PopupMenu">
</return>
<description>
diff --git a/doc/classes/Mutex.xml b/doc/classes/Mutex.xml
index 4b845c05ad..74d59b2dd3 100644
--- a/doc/classes/Mutex.xml
+++ b/doc/classes/Mutex.xml
@@ -4,7 +4,7 @@
A synchronization Mutex.
</brief_description>
<description>
- A synchronization Mutex. Element used in multi-threadding. Basically a binary [Semaphore]. Guarantees that only one thread has this lock, can be used to protect a critical section.
+ A synchronization Mutex. Element used to synchronize multiple [Thread]s. Basically a binary [Semaphore]. Guarantees that only one thread can ever acquire this lock at a time. Can be used to protect a critical section. Be careful to avoid deadlocks.
</description>
<tutorials>
</tutorials>
@@ -22,14 +22,14 @@
<return type="int" enum="Error">
</return>
<description>
- Try locking this [code]Mutex[/code], does not block. Returns [OK] on success else [ERR_BUSY].
+ Try locking this [code]Mutex[/code], does not block. Returns [OK] on success, [ERR_BUSY] otherwise.
</description>
</method>
<method name="unlock">
<return type="void">
</return>
<description>
- Unlock this [code]Mutex[/code], leaving it to others threads.
+ Unlock this [code]Mutex[/code], leaving it to other threads.
</description>
</method>
</methods>
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index 76265e700a..ff3e513c79 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -91,6 +91,13 @@
Return the text of the item at index "idx".
</description>
</method>
+ <method name="get_popup" qualifiers="const">
+ <return type="PopupMenu">
+ </return>
+ <description>
+ Return the [PopupMenu] contained in this button.
+ </description>
+ </method>
<method name="get_selected_id" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/Physics2DDirectSpaceState.xml b/doc/classes/Physics2DDirectSpaceState.xml
index f63b8f17bc..2e2d8e95f9 100644
--- a/doc/classes/Physics2DDirectSpaceState.xml
+++ b/doc/classes/Physics2DDirectSpaceState.xml
@@ -17,8 +17,8 @@
<argument index="0" name="shape" type="Physics2DShapeQueryParameters">
</argument>
<description>
- Check whether the shape can travel to a point. If it can, the method will return an array with two floats: The first is the distance the shape can move in that direction without colliding, and the second is the distance at which it will collide.
- If the shape can not move, the array will be empty.
+ Checks how far the shape can travel toward a point. Note that both the shape and the motion are supplied through a [Physics2DShapeQueryParameters] object. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [1, 1].
+ If the shape can not move, the array will be empty ([code]dir.empty()==true[/code]).
</description>
</method>
<method name="collide_shape">
@@ -29,7 +29,7 @@
<argument index="1" name="max_results" type="int" default="32">
</argument>
<description>
- Check the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
+ Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
</description>
</method>
<method name="get_rest_info">
@@ -38,16 +38,15 @@
<argument index="0" name="shape" type="Physics2DShapeQueryParameters">
</argument>
<description>
- Check the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. If it collides with more than a shape, the nearest one is selected. The returned object is a dictionary containing the following fields:
- pointo: Place where the shapes intersect.
- normal: Normal of the object at the point where the shapes intersect.
- shape: Shape index within the object against which the shape intersected.
- metadata: Metadata of the shape against which the shape intersected. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- collider_id: Id of the object against which the shape intersected.
- collider: Object against which the shape intersected.
- rid: [RID] of the object against which the shape intersected.
- linear_velocity: The movement vector of the object the shape intersected, if it was a body. If it was an area, it is (0,0).
- If the shape did not intersect anything, then an empty dictionary (dir.empty()==true) is returned instead.
+ Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. If it collides with more than one shape, the nearest one is selected. Note that this method does not take into account the [code]motion[/code] property of the object. The returned object is a dictionary containing the following fields:
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]linear_velocity[/code]: The colliding object's velocity [Vector2]. If the object is an [Area2D], the result is [code](0, 0)[/code].
+ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
+ [code]normal[/code]: The object's surface normal at the intersection point.
+ [code]point[/code]: The intersection point.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ If the shape did not intersect anything, then an empty dictionary ([code]dir.empty()==true[/code]) is returned instead.
</description>
</method>
<method name="intersect_point">
@@ -62,12 +61,12 @@
<argument index="3" name="collision_layer" type="int" default="2147483647">
</argument>
<description>
- Check whether a point is inside any shape. The shapes the point is inside of are returned in an array containing dictionaries with the following fields:
- shape: Shape index within the object the point is in.
- metadata: Metadata of the shape the point is in. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- collider_id: Id of the object the point is in.
- collider: Object the point is inside of.
- rid: [RID] of the object the point is in.
+ Checks whether a point is inside any shape. The shapes the point is inside of are returned in an array containing dictionaries with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
Additionally, the method can take an array of objects or [RID]s that are to be excluded from collisions, or a bitmask representing the physics layers to check in.
</description>
</method>
@@ -83,15 +82,15 @@
<argument index="3" name="collision_layer" type="int" default="2147483647">
</argument>
<description>
- Intersect a ray in a given space. The returned object is a dictionary with the following fields:
- position: Place where ray is stopped.
- normal: Normal of the object at the point where the ray was stopped.
- shape: Shape index within the object against which the ray was stopped.
- metadata: Metadata of the shape against which the ray was stopped. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- collider_id: Id of the object against which the ray was stopped.
- collider: Object against which the ray was stopped.
- rid: [RID] of the object against which the ray was stopped.
- If the ray did not intersect anything, then an empty dictionary (dir.empty()==true) is returned instead.
+ Intersects a ray in a given space. The returned object is a dictionary with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
+ [code]normal[/code]: The object's surface normal at the intersection point.
+ [code]position[/code]: The intersection point.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ If the ray did not intersect anything, then an empty dictionary ([code]dir.empty()==true[/code]) is returned instead.
Additionally, the method can take an array of objects or [RID]s that are to be excluded from collisions, or a bitmask representing the physics layers to check in.
</description>
</method>
@@ -103,12 +102,12 @@
<argument index="1" name="max_results" type="int" default="32">
</argument>
<description>
- Check the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. The intersected shapes are returned in an array containing dictionaries with the following fields:
- shape: Shape index within the object the shape intersected.
- metadata: Metadata of the shape intersected by the shape given through the [Physics2DShapeQueryParameters]. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- collider_id: Id of the object the shape intersected.
- collider: Object the shape intersected.
- rid: [RID] of the object the shape intersected.
+ Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. Note that this method does not take into account the [code]motion[/code] property of the object. The intersected shapes are returned in an array containing dictionaries with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
The number of intersections can be limited with the second parameter, to reduce the processing time.
</description>
</method>
diff --git a/doc/classes/PhysicsDirectSpaceState.xml b/doc/classes/PhysicsDirectSpaceState.xml
index 21576646f9..d93550eb47 100644
--- a/doc/classes/PhysicsDirectSpaceState.xml
+++ b/doc/classes/PhysicsDirectSpaceState.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicsDirectSpaceState" inherits="Object" category="Core" version="3.0-beta">
<brief_description>
+ Direct access object to a space in the [PhysicsServer].
</brief_description>
<description>
+ Direct access object to a space in the [PhysicsServer]. It's used mainly to do queries against objects and areas residing in a given space.
</description>
<tutorials>
</tutorials>
@@ -17,6 +19,8 @@
<argument index="1" name="motion" type="Vector3">
</argument>
<description>
+ Checks whether the shape can travel to a point. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [1, 1].
+ If the shape can not move, the array will be empty ([code]dir.empty()==true[/code]).
</description>
</method>
<method name="collide_shape">
@@ -27,6 +31,7 @@
<argument index="1" name="max_results" type="int" default="32">
</argument>
<description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
</description>
</method>
<method name="get_rest_info">
@@ -35,6 +40,14 @@
<argument index="0" name="shape" type="PhysicsShapeQueryParameters">
</argument>
<description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. If it collides with more than a shape, the nearest one is selected. The returned object is a dictionary containing the following fields:
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]linear_velocity[/code]: The colliding object's velocity [Vector3]. If the object is an [Area], the result is [code](0, 0, 0)[/code].
+ [code]normal[/code]: The object's surface normal at the intersection point.
+ [code]point[/code]: The intersection point.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ If the shape did not intersect anything, then an empty dictionary ([code]dir.empty()==true[/code]) is returned instead.
</description>
</method>
<method name="intersect_ray">
@@ -49,6 +62,15 @@
<argument index="3" name="collision_layer" type="int" default="2147483647">
</argument>
<description>
+ Intersects a ray in a given space. The returned object is a dictionary with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]normal[/code]: The object's surface normal at the intersection point.
+ [code]position[/code]: The intersection point.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ If the ray did not intersect anything, then an empty dictionary ([code]dir.empty()==true[/code]) is returned instead.
+ Additionally, the method can take an array of objects or [RID]s that are to be excluded from collisions, or a bitmask representing the physics layers to check in.
</description>
</method>
<method name="intersect_shape">
@@ -59,6 +81,12 @@
<argument index="1" name="max_results" type="int" default="32">
</argument>
<description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. The intersected shapes are returned in an array containing dictionaries with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ The number of intersections can be limited with the second parameter, to reduce the processing time.
</description>
</method>
</methods>
diff --git a/doc/classes/Semaphore.xml b/doc/classes/Semaphore.xml
index d8deb9651a..c8206ff2c2 100644
--- a/doc/classes/Semaphore.xml
+++ b/doc/classes/Semaphore.xml
@@ -4,7 +4,7 @@
A synchronization Semaphore.
</brief_description>
<description>
- A synchronization Semaphore. Element used in multi-threadding. Initialized to zero on creation.
+ A synchronization Semaphore. Element used to synchronize multiple [Thread]s. Initialized to zero on creation. Be careful to avoid deadlocks. For a binary version, see [Mutex].
</description>
<tutorials>
</tutorials>
@@ -15,14 +15,14 @@
<return type="int" enum="Error">
</return>
<description>
- Lowers the [code]Semaphore[/code], allowing one more thread in.
+ Lowers the [code]Semaphore[/code], allowing one more thread in. Returns [OK] on success, [ERR_BUSY] otherwise.
</description>
</method>
<method name="wait">
<return type="int" enum="Error">
</return>
<description>
- Tries to wait for the [code]Semaphore[/code], if its value is zero, blocks until non-zero.
+ Tries to wait for the [code]Semaphore[/code], if its value is zero, blocks until non-zero. Returns [OK] on success, [ERR_BUSY] otherwise.
</description>
</method>
</methods>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 85cbeaaa03..ab722a24c3 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -345,18 +345,28 @@
</methods>
<members>
<member name="caret_blink" type="bool" setter="cursor_set_blink_enabled" getter="cursor_get_blink_enabled">
+ If [code]true[/code] the caret (visual cursor) blinks.
</member>
<member name="caret_blink_speed" type="float" setter="cursor_set_blink_speed" getter="cursor_get_blink_speed">
+ Duration (in seconds) of a caret's blinking cycle.
</member>
<member name="caret_block_mode" type="bool" setter="cursor_set_block_mode" getter="cursor_is_block_mode">
+ If [code]true[/code] the caret displays as a rectangle.
+ If [code]false[/code] the caret displays as a bar.
+ </member>
+ <member name="caret_moving_by_right_click" type="bool" setter="set_right_click_moves_caret" getter="is_right_click_moving_caret">
+ If [code]true[/code] a right click moves the cursor at the mouse position before displaying the context menu.
+ If [code]false[/code] the context menu disregards mouse location.
</member>
<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="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">
</member>
<member name="highlight_current_line" type="bool" setter="set_highlight_current_line" getter="is_highlight_current_line_enabled">
+ If [code]true[/code] the line containing the cursor is highlighted.
</member>
<member name="override_selected_font_color" type="bool" setter="set_override_selected_font_color" getter="is_overriding_selected_font_color">
</member>
@@ -364,6 +374,7 @@
If [code]true[/code] read-only mode is enabled. Existing text cannot be modified and new text cannot be added.
</member>
<member name="show_line_numbers" type="bool" setter="set_show_line_numbers" getter="is_show_line_numbers_enabled">
+ If [code]true[/code] line numbers are displayed to the left of the text.
</member>
<member name="smooth_scrolling" type="bool" setter="set_smooth_scroll_enable" getter="is_smooth_scroll_enabled">
</member>
@@ -419,16 +430,22 @@
Search from end to beginning.
</constant>
<constant name="MENU_CUT" value="0" enum="MenuItems">
+ Cuts (Copies and clears) the selected text.
</constant>
<constant name="MENU_COPY" value="1" enum="MenuItems">
+ Copies the selected text.
</constant>
<constant name="MENU_PASTE" value="2" enum="MenuItems">
+ Pastes the clipboard text over the selected text (or at the cursor's position).
</constant>
<constant name="MENU_CLEAR" value="3" enum="MenuItems">
+ Erases the whole [TextEdit] text.
</constant>
<constant name="MENU_SELECT_ALL" value="4" enum="MenuItems">
+ Selects the whole [TextEdit] text.
</constant>
<constant name="MENU_UNDO" value="5" enum="MenuItems">
+ Undoes the previous action.
</constant>
<constant name="MENU_MAX" value="6" enum="MenuItems">
</constant>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 510a215fbc..a09f6b6dc3 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -188,6 +188,7 @@
<argument index="0" name="arg0" type="Vector2">
</argument>
<description>
+ Applies autotiling rules to the cell (and its adjacent cells) referenced by its grid-based X and Y coordinates.
</description>
</method>
<method name="update_bitmask_region">
@@ -198,6 +199,8 @@
<argument index="1" name="end" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
+ Applies autotiling rules to the cells in the given region (specified by grid-based X and Y coordinates).
+ Calling with invalid (or missing) parameters applies autotiling rules for the entire TileMap.
</description>
</method>
<method name="world_to_map" qualifiers="const">
diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml
index 7ea83b0b22..09071b2ad1 100644
--- a/doc/classes/Timer.xml
+++ b/doc/classes/Timer.xml
@@ -15,20 +15,21 @@
<return type="float">
</return>
<description>
- Return the time left for timeout in seconds if the timer is active, 0 otherwise.
+ Returns the timer's remaining time in seconds. Returns 0 if the timer is inactive.
</description>
</method>
<method name="is_paused" qualifiers="const">
<return type="bool">
</return>
<description>
- Return if the timer is paused or not.
+ Returns [code]true[/code] if the timer is paused.
</description>
</method>
<method name="is_stopped" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if the timer is stopped.
</description>
</method>
<method name="set_paused">
@@ -37,14 +38,15 @@
<argument index="0" name="paused" type="bool">
</argument>
<description>
- Set whether the timer is paused or not. A paused timer will be inactive until it is unpaused again.
+ Pauses the timer. If [code]paused[/code] is [code]true[/code], the timer will not process until it is started or unpaused again, even if [method start] is called.
</description>
</method>
<method name="start">
<return type="void">
</return>
<description>
- Start the Timer.
+ Starts the timer. This also resets the remaining time to [code]wait_time[/code].
+ Note: this method will not resume a paused timer. See [method set_paused].
</description>
</method>
<method name="stop">
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 17576f33ed..f4717aa995 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -4,7 +4,7 @@
2D Transformation. 3x2 matrix.
</brief_description>
<description>
- Represents one or many transformations in 3D space such as translation, rotation, or scaling. It consists of a two [Vector2] x, y and [Vector2] "origin". It is similar to a 3x2 matrix.
+ Represents one or many transformations in 2D space such as translation, rotation, or scaling. It consists of a two [Vector2] x, y and [Vector2] "origin". It is similar to a 3x2 matrix.
</description>
<tutorials>
</tutorials>
@@ -17,7 +17,7 @@
<argument index="0" name="from" type="Transform">
</argument>
<description>
- Constructs the [code]Transform2D[/code] from a 3D [Transform].
+ Constructs the transform from a 3D [Transform].
</description>
</method>
<method name="Transform2D">
@@ -30,7 +30,7 @@
<argument index="2" name="origin" type="Vector2">
</argument>
<description>
- Constructs the [code]Transform2D[/code] from 3 [Vector2] consisting of rows x, y and origin.
+ Constructs the transform from 3 [Vector2]s representing x, y, and origin.
</description>
</method>
<method name="Transform2D">
@@ -41,7 +41,7 @@
<argument index="1" name="position" type="Vector2">
</argument>
<description>
- Constructs the [code]Transform2D[/code] from rotation angle in radians and position [Vector2].
+ Constructs the transform from a given angle (in radians) and position.
</description>
</method>
<method name="affine_inverse">
@@ -57,7 +57,7 @@
<argument index="0" name="v" type="var">
</argument>
<description>
- Transforms the given vector "v" by this transform basis (no translation).
+ Transforms the given vector by this transform's basis (no translation).
</description>
</method>
<method name="basis_xform_inv">
@@ -66,21 +66,21 @@
<argument index="0" name="v" type="var">
</argument>
<description>
- Inverse-transforms the given vector "v" by this transform basis (no translation).
+ Inverse-transforms the given vector by this transform's basis (no translation).
</description>
</method>
<method name="get_origin">
<return type="Vector2">
</return>
<description>
- Returns the origin [Vector2] (translation).
+ Returns the transform's origin (translation).
</description>
</method>
<method name="get_rotation">
<return type="float">
</return>
<description>
- Returns the rotation (in radians).
+ Returns the transform's rotation (in radians).
</description>
</method>
<method name="get_scale">
@@ -98,7 +98,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Interpolates the transform to other Transform2D by weight amount (0-1).
+ Returns a transform interpolated between this transform and another by a given weight (0-1).
</description>
</method>
<method name="inverse">
@@ -121,7 +121,7 @@
<argument index="0" name="phi" type="float">
</argument>
<description>
- Rotates the transform by phi.
+ Rotates the transform by the given angle (in radians).
</description>
</method>
<method name="scaled">
@@ -130,7 +130,7 @@
<argument index="0" name="scale" type="Vector2">
</argument>
<description>
- Scales the transform by the specified 2D scaling factors.
+ Scales the transform by the given factor.
</description>
</method>
<method name="translated">
@@ -139,7 +139,7 @@
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
- Translates the transform by the specified offset.
+ Translates the transform by the given offset.
</description>
</method>
<method name="xform">
@@ -163,13 +163,13 @@
</methods>
<members>
<member name="origin" type="Vector2" setter="" getter="">
- The translation offset of the transform.
+ The transform's translation offset.
</member>
<member name="x" type="Vector2" setter="" getter="">
- The X axis of 2x2 basis matrix containing 2 [Vector2] as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object.
+ The X axis of 2x2 basis matrix containing 2 [Vector2]s as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object.
</member>
<member name="y" type="Vector2" setter="" getter="">
- The Y axis of 2x2 basis matrix containing 2 [Vector2] as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object.
+ The Y axis of 2x2 basis matrix containing 2 [Vector2]s as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object.
</member>
</members>
<constants>
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index a4daa77b50..86415ea740 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -1086,19 +1086,22 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons
}
}
- if (shader_ptr && shader_ptr != shader_cache) {
+ if (shader_ptr) {
if (shader_ptr->canvas_item.uses_screen_texture && !state.canvas_texscreen_used) {
//copy if not copied before
_copy_texscreen(Rect2());
}
- if (shader_ptr->canvas_item.uses_time) {
- VisualServerRaster::redraw_request();
- }
+ if (shader_ptr != shader_cache) {
- state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id);
- state.canvas_shader.bind();
+ if (shader_ptr->canvas_item.uses_time) {
+ VisualServerRaster::redraw_request();
+ }
+
+ state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id);
+ state.canvas_shader.bind();
+ }
if (material_ptr->ubo_id) {
glBindBufferBase(GL_UNIFORM_BUFFER, 2, material_ptr->ubo_id);
@@ -1147,7 +1150,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons
glBindTexture(t->target, t->tex_id);
}
- } else if (!shader_ptr) {
+ } else {
state.canvas_shader.set_custom_shader(0);
state.canvas_shader.bind();
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index b777f9343a..1c3361d2de 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1541,7 +1541,19 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) {
- const RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(c.texture);
+ RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(c.texture);
+
+ t = t->get_ptr(); //resolve for proxies
+#ifdef TOOLS_ENABLED
+ if (t->detect_3d) {
+ t->detect_3d(t->detect_3d_ud);
+ }
+#endif
+
+ if (t->render_target) {
+ t->render_target->used_in_frame = true;
+ }
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(t->target, t->tex_id);
restore_tex = true;
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 8ee9e3fdb8..0ed0dbe0c0 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -5334,6 +5334,14 @@ void RasterizerStorageGLES3::particles_set_emitting(RID p_particles, bool p_emit
}
particles->emitting = p_emitting;
}
+
+bool RasterizerStorageGLES3::particles_get_emitting(RID p_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, false);
+
+ return particles->emitting;
+}
+
void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) {
Particles *particles = particles_owner.getornull(p_particles);
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 6647372688..9f04e00360 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -1206,6 +1206,7 @@ public:
virtual RID particles_create();
virtual void particles_set_emitting(RID p_particles, bool p_emitting);
+ virtual bool particles_get_emitting(RID p_particles);
virtual void particles_set_amount(RID p_particles, int p_amount);
virtual void particles_set_lifetime(RID p_particles, float p_lifetime);
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot);
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index 101978548d..ec00c057b2 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/drivers/gles3/shader_compiler_gles3.cpp
@@ -806,7 +806,6 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture";
actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer";
- actions[VS::SHADER_SPATIAL].renames["SIDE"] = "side";
actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor";
//for light
@@ -847,6 +846,8 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 9bc2bc079d..6427e3d967 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -174,7 +174,7 @@ void light_compute(vec3 N, vec3 L,vec3 V, vec3 light_color, float roughness, ino
vec3 H = normalize(V + L);
float dotNH = max(dot(N,H), 0.0 );
- float intensity = pow( dotNH, (1.0-roughness) * 256.0);
+ float intensity = (roughness >= 1.0 ? 1.0 : pow( dotNH, (1.0-roughness) * 256.0));
specular += light_color * intensity;
}
@@ -296,6 +296,48 @@ void main() {
#endif
+
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+
+ vec3 binormal = normalize( cross(normal,tangent) * binormalf );
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+ uv_interp = uv_attrib;
+#endif
+
+#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
+ uv2_interp = uv2_attrib;
+#endif
+
+#if defined(USE_INSTANCING) && defined(ENABLE_INSTANCE_CUSTOM)
+ vec4 instance_custom = instance_custom_data;
+#else
+ vec4 instance_custom = vec4(0.0);
+#endif
+
+ highp mat4 local_projection = projection_matrix;
+
+//using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
+
+ vertex = world_matrix * vertex;
+ normal = normalize((world_matrix * vec4(normal,0.0)).xyz);
+
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+
+ tangent = normalize((world_matrix * vec4(tangent,0.0)).xyz);
+ binormal = normalize((world_matrix * vec4(binormal,0.0)).xyz);
+#endif
+#endif
+
+ float roughness=0.0;
+
+//defines that make writing custom shaders easier
+#define projection_matrix local_projection
+#define world_transform world_matrix
+
+
#ifdef USE_SKELETON
{
//skeleton transform
@@ -333,57 +375,13 @@ void main() {
texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
) * bone_weights.w;
+ mat4 bone_matrix = transpose(mat4(m[0],m[1],m[2],vec4(0.0,0.0,0.0,1.0)));
- vertex.xyz = vertex * m;
-
- normal = vec4(normal,0.0) * m;
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- tangent.xyz = vec4(tangent.xyz,0.0) * m;
-#endif
+ world_matrix = bone_matrix * world_matrix;
}
#endif
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-
- vec3 binormal = normalize( cross(normal,tangent) * binormalf );
-#endif
-
-#if defined(ENABLE_UV_INTERP)
- uv_interp = uv_attrib;
-#endif
-
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
- uv2_interp = uv2_attrib;
-#endif
-
-#if defined(USE_INSTANCING) && defined(ENABLE_INSTANCE_CUSTOM)
- vec4 instance_custom = instance_custom_data;
-#else
- vec4 instance_custom = vec4(0.0);
-#endif
-
- highp mat4 modelview = camera_inverse_matrix * world_matrix;
- highp mat4 local_projection = projection_matrix;
-
-//using world coordinates
-#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
-
- vertex = world_matrix * vertex;
- normal = normalize((world_matrix * vec4(normal,0.0)).xyz);
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-
- tangent = normalize((world_matrix * vec4(tangent,0.0)).xyz);
- binormal = normalize((world_matrix * vec4(binormal,0.0)).xyz);
-#endif
-#endif
-
- float roughness=0.0;
-
-//defines that make writing custom shaders easier
-#define projection_matrix local_projection
-#define world_transform world_matrix
+ mat4 modelview = camera_inverse_matrix * world_matrix;
{
VERTEX_SHADER_CODE
@@ -1617,7 +1615,7 @@ void main() {
float alpha = 1.0;
-#ifdef METERIAL_DOUBLESIDED
+#if defined(DO_SIDE_CHECK)
float side=float(gl_FrontFacing)*2.0-1.0;
#else
float side=1.0;
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 2584d26fc4..e904fd94be 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -267,7 +267,6 @@ void CreateDialog::_update_search() {
if (EditorNode::get_editor_data().get_custom_types().has(type) && ClassDB::is_parent_class(type, base_type)) {
//there are custom types based on this... cool.
- //print_line("there are custom types");
const Vector<EditorData::CustomType> &ct = EditorNode::get_editor_data().get_custom_types()[type];
for (int i = 0; i < ct.size(); i++) {
@@ -630,31 +629,40 @@ CreateDialog::CreateDialog() {
set_resizable(true);
- HSplitContainer *hbc = memnew(HSplitContainer);
+ HSplitContainer *hsc = memnew(HSplitContainer);
+ add_child(hsc);
- add_child(hbc);
+ VSplitContainer *vsc = memnew(VSplitContainer);
+ hsc->add_child(vsc);
- VBoxContainer *lvbc = memnew(VBoxContainer);
- hbc->add_child(lvbc);
- lvbc->set_custom_minimum_size(Size2(150, 0) * EDSCALE);
+ VBoxContainer *fav_vb = memnew(VBoxContainer);
+ vsc->add_child(fav_vb);
+ fav_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
+ fav_vb->set_v_size_flags(SIZE_EXPAND_FILL);
favorites = memnew(Tree);
- lvbc->add_margin_child(TTR("Favorites:"), favorites, true);
+ fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
favorites->set_hide_root(true);
favorites->set_hide_folding(true);
favorites->connect("cell_selected", this, "_favorite_selected");
favorites->connect("item_activated", this, "_favorite_activated");
favorites->set_drag_forwarding(this);
+ VBoxContainer *rec_vb = memnew(VBoxContainer);
+ vsc->add_child(rec_vb);
+ rec_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
+ rec_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+
recent = memnew(Tree);
- lvbc->add_margin_child(TTR("Recent:"), recent, true);
+ rec_vb->add_margin_child(TTR("Recent:"), recent, true);
recent->set_hide_root(true);
recent->set_hide_folding(true);
recent->connect("cell_selected", this, "_history_selected");
recent->connect("item_activated", this, "_history_activated");
VBoxContainer *vbc = memnew(VBoxContainer);
- hbc->add_child(vbc);
+ hsc->add_child(vbc);
+ vbc->set_custom_minimum_size(Size2(300, 0) * EDSCALE);
vbc->set_h_size_flags(SIZE_EXPAND_FILL);
HBoxContainer *search_hb = memnew(HBoxContainer);
search_box = memnew(LineEdit);
@@ -676,7 +684,6 @@ CreateDialog::CreateDialog() {
set_hide_on_ok(false);
search_options->connect("item_activated", this, "_confirmed");
search_options->connect("cell_selected", this, "_item_selected");
- //search_options->set_hide_root(true);
base_type = "Object";
preferred_search_result_type = "";
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 5f026abb6d..6db3c09673 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -145,7 +145,7 @@ EditorAbout::EditorAbout() {
List<String> dev_sections;
dev_sections.push_back(TTR("Project Founders"));
dev_sections.push_back(TTR("Lead Developer"));
- dev_sections.push_back(TTR("Project Manager"));
+ dev_sections.push_back(TTR("Project Manager ")); // " " appended to distinguish between 'project supervisor' and 'project list'
dev_sections.push_back(TTR("Developers"));
const char **dev_src[] = { dev_founders, dev_lead, dev_manager, dev_names };
tc->add_child(_populate_list(TTR("Authors"), dev_sections, dev_src, 1));
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 49d55e6305..214b1cac89 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -701,6 +701,15 @@ String EditorData::get_scene_title(int p_idx) const {
return name;
}
+void EditorData::set_scene_path(int p_idx, const String &p_path) {
+
+ ERR_FAIL_INDEX(p_idx, edited_scene.size());
+
+ if (!edited_scene[p_idx].root)
+ return;
+ edited_scene[p_idx].root->set_filename(p_path);
+}
+
String EditorData::get_scene_path(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String());
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 33a4091a65..f15b7e37f1 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -185,6 +185,7 @@ public:
String get_scene_title(int p_idx) const;
String get_scene_path(int p_idx) const;
String get_scene_type(int p_idx) const;
+ void set_scene_path(int p_idx, const String &p_path);
Ref<Script> get_scene_root_script(int p_idx) const;
void set_edited_scene_version(uint64_t version, int p_scene_idx = -1);
uint64_t get_edited_scene_version() const;
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index deba16a524..4bf138354d 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -54,7 +54,7 @@ void EditorFileDialog::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- //_update_icons
+ // update icons
mode_thumbnails->set_icon(get_icon("FileThumbnail", "EditorIcons"));
mode_list->set_icon(get_icon("FileList", "EditorIcons"));
dir_prev->set_icon(get_icon("Back", "EditorIcons"));
@@ -65,7 +65,6 @@ void EditorFileDialog::_notification(int p_what) {
fav_up->set_icon(get_icon("MoveUp", "EditorIcons"));
fav_down->set_icon(get_icon("MoveDown", "EditorIcons"));
- fav_rm->set_icon(get_icon("Remove", "EditorIcons"));
} else if (p_what == NOTIFICATION_PROCESS) {
@@ -80,10 +79,6 @@ void EditorFileDialog::_notification(int p_what) {
preview_wheel_timeout = 0.1;
}
}
- } else if (p_what == NOTIFICATION_DRAW) {
-
- //RID ci = get_canvas_item();
- //get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
} else if (p_what == NOTIFICATION_POPUP_HIDE) {
set_process_unhandled_input(false);
@@ -95,7 +90,7 @@ void EditorFileDialog::_notification(int p_what) {
set_show_hidden_files(show_hidden);
set_display_mode((DisplayMode)EditorSettings::get_singleton()->get("filesystem/file_dialog/display_mode").operator int());
- //_update_icons
+ // update icons
mode_thumbnails->set_icon(get_icon("FileThumbnail", "EditorIcons"));
mode_list->set_icon(get_icon("FileList", "EditorIcons"));
dir_prev->set_icon(get_icon("Back", "EditorIcons"));
@@ -106,7 +101,6 @@ void EditorFileDialog::_notification(int p_what) {
fav_up->set_icon(get_icon("MoveUp", "EditorIcons"));
fav_down->set_icon(get_icon("MoveDown", "EditorIcons"));
- fav_rm->set_icon(get_icon("Remove", "EditorIcons"));
// DO NOT CALL UPDATE FILE LIST HERE, ALL HUNDREDS OF HIDDEN DIALOGS WILL RESPOND, CALL INVALIDATE INSTEAD
invalidate();
}
@@ -260,7 +254,6 @@ void EditorFileDialog::_post_popup() {
name = name.get_file() + "/";
}
- //print_line("file: "+name);
recent->add_item(name, folder);
recent->set_item_metadata(recent->get_item_count() - 1, recentd[i]);
}
@@ -316,7 +309,7 @@ void EditorFileDialog::_request_single_thumbnail(const String &p_path) {
return;
EditorResourcePreview::get_singleton()->queue_resource_preview(p_path, this, "_thumbnail_done", p_path);
- //print_line("want file "+p_path);
+
set_process(true);
preview_waiting = true;
preview_wheel_timeout = 0;
@@ -376,7 +369,7 @@ void EditorFileDialog::_action_pressed() {
bool valid = false;
if (filter->get_selected() == filter->get_item_count() - 1) {
- valid = true; //match none
+ valid = true; // match none
} else if (filters.size() > 1 && filter->get_selected() == 0) {
// match all filters
for (int i = 0; i < filters.size(); i++) {
@@ -777,14 +770,12 @@ void EditorFileDialog::update_file_list() {
}
if (match) {
- //TreeItem *ti=tree->create_item(root);
- //ti->set_text(0,files.front()->get());
+
item_list->add_item(files.front()->get());
if (get_icon_func) {
Ref<Texture> icon = get_icon_func(cdir.plus_file(files.front()->get()));
- //ti->set_icon(0,icon);
if (display_mode == DISPLAY_THUMBNAILS) {
item_list->set_item_icon(item_list->get_item_count() - 1, file_thumbnail);
@@ -794,11 +785,6 @@ void EditorFileDialog::update_file_list() {
}
}
- if (mode == MODE_OPEN_DIR) {
- //disabled mode?
- //ti->set_custom_color(0,get_color("files_disabled"));
- //ti->set_selectable(0,false);
- }
Dictionary d;
d["name"] = files.front()->get();
d["dir"] = false;
@@ -807,7 +793,6 @@ void EditorFileDialog::update_file_list() {
EditorResourcePreview::get_singleton()->queue_resource_preview(fullpath, this, "_thumbnail_result", fullpath);
}
d["path"] = fullpath;
- //ti->set_metadata(0,d);
item_list->set_item_metadata(item_list->get_item_count() - 1, d);
if (file->get_text() == files.front()->get())
@@ -838,11 +823,6 @@ void EditorFileDialog::update_file_list() {
break;
}
}
- // ??
- /*
- if (tree->get_root() && tree->get_root()->get_children())
- tree->get_root()->get_children()->select(0);
- */
files.clear();
}
@@ -916,7 +896,6 @@ void EditorFileDialog::set_current_dir(const String &p_dir) {
dir_access->change_dir(p_dir);
update_dir();
invalidate();
- //_push_history();
}
void EditorFileDialog::set_current_file(const String &p_file) {
@@ -1191,7 +1170,6 @@ void EditorFileDialog::_update_favorites() {
name = name.get_file() + "/";
}
- //print_line("file: "+name);
favorites->add_item(name, star);
favorites->set_item_metadata(favorites->get_item_count() - 1, favorited[i]);
@@ -1442,6 +1420,8 @@ bool EditorFileDialog::is_overwrite_warning_disabled() const {
EditorFileDialog::EditorFileDialog() {
+ set_resizable(true);
+
show_hidden_files = default_show_hidden_files;
display_mode = default_display_mode;
local_history_pos = 0;
@@ -1499,6 +1479,8 @@ EditorFileDialog::EditorFileDialog() {
Ref<ButtonGroup> view_mode_group;
view_mode_group.instance();
+ pathhb->add_child(memnew(VSeparator));
+
mode_thumbnails = memnew(ToolButton);
mode_thumbnails->connect("pressed", this, "set_display_mode", varray(DISPLAY_THUMBNAILS));
mode_thumbnails->set_toggle_mode(true);
@@ -1528,8 +1510,13 @@ EditorFileDialog::EditorFileDialog() {
vbc->add_child(list_hb);
list_hb->set_v_size_flags(SIZE_EXPAND_FILL);
+ VSplitContainer *vsc = memnew(VSplitContainer);
+ list_hb->add_child(vsc);
+
VBoxContainer *fav_vb = memnew(VBoxContainer);
- list_hb->add_child(fav_vb);
+ vsc->add_child(fav_vb);
+ fav_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
+ fav_vb->set_v_size_flags(SIZE_EXPAND_FILL);
HBoxContainer *fav_hb = memnew(HBoxContainer);
fav_vb->add_child(fav_hb);
fav_hb->add_child(memnew(Label(TTR("Favorites:"))));
@@ -1540,23 +1527,23 @@ EditorFileDialog::EditorFileDialog() {
fav_down = memnew(ToolButton);
fav_hb->add_child(fav_down);
fav_down->connect("pressed", this, "_favorite_move_down");
- fav_rm = memnew(ToolButton);
- fav_hb->add_child(fav_rm);
- fav_rm->hide(); // redundant
- MarginContainer *fav_mv = memnew(MarginContainer);
- fav_vb->add_child(fav_mv);
- fav_mv->set_v_size_flags(SIZE_EXPAND_FILL);
favorites = memnew(ItemList);
- fav_mv->add_child(favorites);
+ fav_vb->add_child(favorites);
+ favorites->set_v_size_flags(SIZE_EXPAND_FILL);
favorites->connect("item_selected", this, "_favorite_selected");
+ VBoxContainer *rec_vb = memnew(VBoxContainer);
+ vsc->add_child(rec_vb);
+ rec_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
+ rec_vb->set_v_size_flags(SIZE_EXPAND_FILL);
recent = memnew(ItemList);
- fav_vb->add_margin_child(TTR("Recent:"), recent, true);
+ rec_vb->add_margin_child(TTR("Recent:"), recent, true);
recent->connect("item_selected", this, "_recent_selected");
VBoxContainer *item_vb = memnew(VBoxContainer);
list_hb->add_child(item_vb);
+ item_vb->set_custom_minimum_size(Size2(320, 0) * EDSCALE);
HBoxContainer *preview_hb = memnew(HBoxContainer);
preview_hb->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -1599,7 +1586,7 @@ EditorFileDialog::EditorFileDialog() {
filter = memnew(OptionButton);
filter->set_stretch_ratio(3);
filter->set_h_size_flags(SIZE_EXPAND_FILL);
- filter->set_clip_text(true); //too many extensions overflow it
+ filter->set_clip_text(true); // too many extensions overflow it
filename_hbc->add_child(filter);
filename_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
item_vb->add_child(filename_hbc);
@@ -1609,7 +1596,6 @@ EditorFileDialog::EditorFileDialog() {
_update_drives();
connect("confirmed", this, "_action_pressed");
- //cancel->connect("pressed", this,"_cancel_pressed");
item_list->connect("item_selected", this, "_item_selected", varray(), CONNECT_DEFERRED);
item_list->connect("item_activated", this, "_item_db_selected", varray());
item_list->connect("nothing_selected", this, "_items_clear_selection");
@@ -1643,7 +1629,6 @@ EditorFileDialog::EditorFileDialog() {
exterr->set_text(TTR("Must use a valid extension."));
add_child(exterr);
- //update_file_list();
update_filters();
update_dir();
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index f4a9a174e7..281ded6889 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -36,6 +36,7 @@
#include "scene/gui/item_list.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
+#include "scene/gui/separator.h"
#include "scene/gui/split_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tool_button.h"
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index d462cce908..27a1248089 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -320,7 +320,10 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
List<String> to_check;
+ String source_file;
String source_md5;
+ Vector<String> dest_files;
+ String dest_md5;
while (true) {
@@ -346,8 +349,16 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
for (int i = 0; i < fa.size(); i++) {
to_check.push_back(fa[i]);
}
- } else if (!p_only_imported_files && assign == "source_md5") {
- source_md5 = value;
+ } else if (!p_only_imported_files) {
+ if (assign == "source_md5") {
+ source_md5 = value;
+ } else if (assign == "source_file") {
+ source_file = value;
+ } else if (assign == "dest_md5") {
+ dest_md5 = value;
+ } else if (assign == "dest_files") {
+ dest_files = value;
+ }
}
} else if (next_tag.name != "remap" && next_tag.name != "deps") {
@@ -366,6 +377,11 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
//check source md5 matching
if (!p_only_imported_files) {
+
+ if (source_file != String() && source_file != p_path) {
+ return true; //file was moved, reimport
+ }
+
if (source_md5 == String()) {
return true; //lacks md5, so just reimport
}
@@ -374,6 +390,13 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
if (md5 != source_md5) {
return true;
}
+
+ if (dest_files.size() && dest_md5 != String()) {
+ md5 = FileAccess::get_multiple_md5(dest_files);
+ if (md5 != dest_md5) {
+ return true;
+ }
+ }
}
return false; //nothing changed
@@ -1388,6 +1411,8 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
f->store_line("type=\"" + importer->get_resource_type() + "\"");
}
+ Vector<String> dest_paths;
+
if (err == OK) {
if (importer->get_save_extension() == "") {
@@ -1399,10 +1424,12 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
String path = base_path.c_escape() + "." + E->get() + "." + importer->get_save_extension();
f->store_line("path." + E->get() + "=\"" + path + "\"");
+ dest_paths.push_back(path);
}
} else {
-
- f->store_line("path=\"" + base_path + "." + importer->get_save_extension() + "\"");
+ String path = base_path + "." + importer->get_save_extension();
+ f->store_line("path=\"" + path + "\"");
+ dest_paths.push_back(path);
}
} else {
@@ -1418,6 +1445,7 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
Array genf;
for (List<String>::Element *E = gen_files.front(); E; E = E->next()) {
genf.push_back(E->get());
+ dest_paths.push_back(E->get());
}
String value;
@@ -1426,8 +1454,18 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
f->store_line("");
}
+ f->store_line("source_file=" + Variant(p_file).get_construct_string());
f->store_line("source_md5=\"" + FileAccess::get_md5(p_file) + "\"\n");
+ if (dest_paths.size()) {
+ Array dp;
+ for (int i = 0; i < dest_paths.size(); i++) {
+ dp.push_back(dest_paths[i]);
+ }
+ f->store_line("dest_files=" + Variant(dp).get_construct_string());
+ f->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n");
+ }
+
f->store_line("[params]");
f->store_line("");
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index 8aca007e6b..a76c419152 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -173,11 +173,12 @@ void editor_register_fonts(Ref<Theme> p_theme) {
p_theme->set_font("output_source", "EditorFonts", df_output_code);
Ref<DynamicFont> df_text_editor_status_code;
- df_output_code.instance();
- df_output_code->set_size(14 * EDSCALE);
- df_output_code->set_spacing(DynamicFont::SPACING_TOP, -EDSCALE);
- df_output_code->set_spacing(DynamicFont::SPACING_BOTTOM, -EDSCALE);
- df_output_code->set_font_data(dfmono);
- MAKE_FALLBACKS(df_output_code);
- p_theme->set_font("status_source", "EditorFonts", df_output_code);
+ df_text_editor_status_code.instance();
+ df_text_editor_status_code->set_size(14 * EDSCALE);
+ df_text_editor_status_code->set_spacing(DynamicFont::SPACING_TOP, -EDSCALE);
+ df_text_editor_status_code->set_spacing(DynamicFont::SPACING_BOTTOM, -EDSCALE);
+ df_text_editor_status_code->set_font_data(dfmono);
+ MAKE_FALLBACKS(df_text_editor_status_code);
+
+ p_theme->set_font("status_source", "EditorFonts", df_text_editor_status_code);
}
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 46badc8c86..b078136f23 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -324,23 +324,14 @@ EditorHelpSearch::EditorHelpSearch() {
set_hide_on_ok(false);
search_options->connect("item_activated", this, "_confirmed");
set_title(TTR("Search Help"));
-
- //search_options->set_hide_root(true);
}
/////////////////////////////////
-////////////////////////////////////
-/// /////////////////////////////////
-
void EditorHelpIndex::add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root) {
if (p_types.has(p_type))
return;
- /*
- if (!ClassDB::is_type(p_type,base) || p_type==base)
- return;
- */
String inherits = EditorHelp::get_doc_data()->class_list[p_type].inherits;
@@ -379,8 +370,6 @@ void EditorHelpIndex::_tree_item_selected() {
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);
emit_signal("open_class", s->get_text(0));
hide();
-
- //_goto_desc(s->get_text(0));
}
void EditorHelpIndex::select_class(const String &p_class) {
@@ -518,8 +507,6 @@ EditorHelpIndex::EditorHelpIndex() {
/////////////////////////////////
-////////////////////////////////////
-/// /////////////////////////////////
DocData *EditorHelp::doc = NULL;
void EditorHelp::_init_colors() {
@@ -572,9 +559,7 @@ void EditorHelp::_class_list_select(const String &p_select) {
void EditorHelp::_class_desc_select(const String &p_select) {
- //print_line("LINK: "+p_select);
if (p_select.begins_with("$")) { //enum
- //_goto_desc(p_select.substr(1,p_select.length()));
String select = p_select.substr(1, p_select.length());
String class_name;
if (select.find(".") != -1) {
@@ -585,7 +570,6 @@ void EditorHelp::_class_desc_select(const String &p_select) {
emit_signal("go_to_help", "class_enum:" + class_name + ":" + select);
return;
} else if (p_select.begins_with("#")) {
- //_goto_desc(p_select.substr(1,p_select.length()));
emit_signal("go_to_help", "class_name:" + p_select.substr(1, p_select.length()));
return;
} else if (p_select.begins_with("@")) {
@@ -612,7 +596,6 @@ void EditorHelp::_class_desc_select(const String &p_select) {
}
if (link.find(".") != -1) {
- //must go somewhere else
emit_signal("go_to_help", topic + ":" + link.get_slice(".", 0) + ":" + link.get_slice(".", 1));
} else {
@@ -630,7 +613,7 @@ void EditorHelp::_class_desc_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseButton> mb = p_input;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == 1) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == 1 && !mb->is_doubleclick()) {
class_desc->set_selection_enabled(false);
class_desc->set_selection_enabled(true);
}
@@ -749,16 +732,13 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
- //ERR_FAIL_COND(!doc->class_list.has(p_class));
if (!doc->class_list.has(p_class))
return ERR_DOES_NOT_EXIST;
- //if (tree_item_map.has(p_class)) {
select_locked = true;
- //}
class_desc->show();
- //tabs->set_current_tab(PAGE_CLASS_DESC);
+
description_line = 0;
if (p_class == edited_class)
@@ -770,7 +750,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
method_line.clear();
section_line.clear();
edited_class = p_class;
- //edited_class->show();
_init_colors();
@@ -866,7 +845,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop();
class_desc->pop();
- //class_desc->add_newline();
class_desc->add_newline();
class_desc->push_color(text_color);
class_desc->push_font(doc_font);
@@ -891,7 +869,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->add_text(TTR("Members:"));
class_desc->pop();
class_desc->pop();
- //class_desc->add_newline();
class_desc->push_indent(1);
class_desc->push_table(2);
@@ -970,9 +947,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop();
class_desc->pop();
- //class_desc->add_newline();
- //class_desc->add_newline();
-
+ class_desc->push_font(doc_code_font);
class_desc->push_indent(1);
class_desc->push_table(2);
class_desc->set_table_column_expand(1, 1);
@@ -1028,6 +1003,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop(); //table
class_desc->pop();
+ class_desc->pop(); // font
class_desc->add_newline();
class_desc->add_newline();
}
@@ -1098,7 +1074,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop();
class_desc->add_newline();
- //class_desc->add_newline();
+ class_desc->add_newline();
class_desc->push_indent(1);
@@ -1106,8 +1082,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
signal_line[cd.signals[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
class_desc->push_font(doc_code_font); // monofont
- //_add_type("void");
- //class_desc->add_text(" ");
class_desc->push_color(headline_color);
_add_text(cd.signals[i].name);
class_desc->pop();
@@ -1141,7 +1115,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->push_font(doc_font);
class_desc->push_color(comment_color);
class_desc->push_indent(1);
- // class_desc->add_text(" ");
_add_text(cd.signals[i].description);
class_desc->pop(); // indent
class_desc->pop();
@@ -1185,7 +1158,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->push_indent(1);
class_desc->add_newline();
- //class_desc->add_newline();
for (Map<String, Vector<DocData::ConstantDoc> >::Element *E = enums.front(); E; E = E->next()) {
@@ -1260,7 +1232,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->push_indent(1);
class_desc->add_newline();
- //class_desc->add_newline();
for (int i = 0; i < constants.size(); i++) {
@@ -1279,7 +1250,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
if (constants[i].description != "") {
class_desc->push_font(doc_font);
class_desc->push_indent(1);
- //class_desc->add_text(" ");
class_desc->push_color(comment_color);
_add_text(constants[i].description);
class_desc->pop();
@@ -1353,8 +1323,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop(); // font
class_desc->pop(); // cell
- //class_desc->add_text(" ");
-
if (cd.properties[i].setter != "") {
class_desc->push_cell();
@@ -1428,7 +1396,9 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
for (int i = 0; i < methods.size(); i++) {
+ class_desc->push_font(doc_code_font);
_add_method(methods[i], false);
+ class_desc->pop();
class_desc->add_newline();
class_desc->push_color(text_color);
@@ -1538,7 +1508,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
}
if (brk_pos == bbcode.length())
- break; //nothing else o add
+ break; //nothing else to add
int brk_end = bbcode.find("]", brk_pos + 1);
@@ -1734,10 +1704,6 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
pos = brk_pos + 1;
}
}
-
- /*p_rt->pop();
- p_rt->pop();
- p_rt->pop();*/
}
void EditorHelp::_add_text(const String &p_bbcode) {
@@ -1762,8 +1728,7 @@ void EditorHelp::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- //forward->set_icon(get_icon("Forward","EditorIcons"));
- //back->set_icon(get_icon("Back","EditorIcons"));
+
_update_doc();
} break;
@@ -1836,7 +1801,6 @@ void EditorHelp::_bind_methods() {
ClassDB::bind_method("_class_list_select", &EditorHelp::_class_list_select);
ClassDB::bind_method("_class_desc_select", &EditorHelp::_class_desc_select);
ClassDB::bind_method("_class_desc_input", &EditorHelp::_class_desc_input);
- //ClassDB::bind_method("_button_pressed",&EditorHelp::_button_pressed);
ClassDB::bind_method("_request_help", &EditorHelp::_request_help);
ClassDB::bind_method("_unhandled_key_input", &EditorHelp::_unhandled_key_input);
ClassDB::bind_method("_search", &EditorHelp::_search);
@@ -1848,21 +1812,16 @@ void EditorHelp::_bind_methods() {
EditorHelp::EditorHelp() {
- VBoxContainer *vbc = this;
+ set_custom_minimum_size(Size2(150 * EDSCALE, 0));
EDITOR_DEF("text_editor/help/sort_functions_alphabetically", true);
- //class_list->connect("meta_clicked",this,"_class_list_select");
- //class_list->set_selection_enabled(true);
-
- {
- class_desc = memnew(RichTextLabel);
- vbc->add_child(class_desc);
- class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
- class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
- class_desc->connect("meta_clicked", this, "_class_desc_select");
- class_desc->connect("gui_input", this, "_class_desc_input");
- }
+ class_desc = memnew(RichTextLabel);
+ add_child(class_desc);
+ class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
+ class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ class_desc->connect("meta_clicked", this, "_class_desc_select");
+ class_desc->connect("gui_input", this, "_class_desc_input");
class_desc->set_selection_enabled(true);
@@ -1882,12 +1841,6 @@ EditorHelp::EditorHelp() {
search_dialog->get_ok()->set_text(TTR("Find"));
search_dialog->connect("confirmed", this, "_search_cbk");
search_dialog->set_hide_on_ok(false);
-
- /*class_search = memnew( EditorHelpSearch(editor) );
- editor->get_gui_base()->add_child(class_search);
- class_search->connect("go_to_help",this,"_help_callback");*/
-
- //prev_search_page=-1;
}
EditorHelp::~EditorHelp() {
@@ -1905,9 +1858,9 @@ void EditorHelpBit::_go_to_help(String p_what) {
void EditorHelpBit::_meta_clicked(String p_select) {
print_line("got meta " + p_select);
- //print_line("LINK: "+p_select);
+
if (p_select.begins_with("$")) { //enum
- //_goto_desc(p_select.substr(1,p_select.length()));
+
String select = p_select.substr(1, p_select.length());
String class_name;
if (select.find(".") != -1) {
@@ -1918,24 +1871,15 @@ void EditorHelpBit::_meta_clicked(String p_select) {
_go_to_help("class_enum:" + class_name + ":" + select);
return;
} else if (p_select.begins_with("#")) {
- //_goto_desc(p_select.substr(1,p_select.length()));
+
_go_to_help("class_name:" + p_select.substr(1, p_select.length()));
return;
} else if (p_select.begins_with("@")) {
String m = p_select.substr(1, p_select.length());
- if (m.find(".") != -1) {
- //must go somewhere else
-
- _go_to_help("class_method:" + m.get_slice(".", 0) + ":" + m.get_slice(".", 0));
- } else {
- /*
- if (!method_line.has(m))
- return;
- class_desc->scroll_to_line(method_line[m]);
- */
- }
+ if (m.find(".") != -1)
+ _go_to_help("class_method:" + m.get_slice(".", 0) + ":" + m.get_slice(".", 0)); //must go somewhere else
}
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index bd85927223..c0932c47b8 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -75,20 +75,33 @@ bool EditorSettings::_set(const StringName &p_name, const Variant &p_value, bool
return true;
}
+ bool changed = false;
+
if (p_value.get_type() == Variant::NIL) {
- props.erase(p_name);
+ if (props.has(p_name)) {
+ props.erase(p_name);
+ changed = true;
+ }
} else {
- if (props.has(p_name))
- props[p_name].variant = p_value;
- else
+ if (props.has(p_name)) {
+ if (p_value != props[p_name].variant) {
+ props[p_name].variant = p_value;
+ changed = true;
+ }
+ } else {
props[p_name] = VariantContainer(p_value, last_order++);
+ changed = true;
+ }
if (save_changed_setting) {
- props[p_name].save = true;
+ if (props[p_name].save != true) {
+ props[p_name].save = true;
+ changed = true;
+ }
}
}
- if (p_emit_signal) {
+ if (changed && p_emit_signal) {
emit_signal("settings_changed");
}
return true;
@@ -310,7 +323,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/scene_tabs/show_script_button", false);
_initial_set("text_editor/theme/color_theme", "Adaptive");
- hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Adaptive,Default");
+ hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Adaptive,Default,Custom");
_initial_set("text_editor/theme/line_spacing", 4);
@@ -351,6 +364,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/cursor/caret_blink", true);
_initial_set("text_editor/cursor/caret_blink_speed", 0.65);
hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.1");
+ _initial_set("text_editor/cursor/right_click_moves_caret", true);
_initial_set("text_editor/theme/font", "");
hints["text_editor/theme/font"] = PropertyInfo(Variant::STRING, "text_editor/theme/font", PROPERTY_HINT_GLOBAL_FILE, "*.font,*.tres,*.res");
@@ -1140,13 +1154,13 @@ void EditorSettings::load_favorites() {
}
void EditorSettings::list_text_editor_themes() {
- String themes = "Adaptive,Default";
+ String themes = "Adaptive,Default,Custom";
DirAccess *d = DirAccess::open(get_text_editor_themes_dir());
if (d) {
d->list_dir_begin();
String file = d->get_next();
while (file != String()) {
- if (file.get_extension() == "tet" && file.get_basename().to_lower() != "default" && file.get_basename().to_lower() != "adaptive") {
+ if (file.get_extension() == "tet" && file.get_basename().to_lower() != "default" && file.get_basename().to_lower() != "adaptive" && file.get_basename().to_lower() != "custom") {
themes += "," + file.get_basename();
}
file = d->get_next();
@@ -1158,7 +1172,7 @@ void EditorSettings::list_text_editor_themes() {
}
void EditorSettings::load_text_editor_theme() {
- if (get("text_editor/theme/color_theme") == "Default" || get("text_editor/theme/color_theme") == "Adaptive") {
+ if (get("text_editor/theme/color_theme") == "Default" || get("text_editor/theme/color_theme") == "Adaptive" || get("text_editor/theme/color_theme") == "Custom") {
_load_default_text_editor_theme(); // sorry for "Settings changed" console spam
return;
}
@@ -1215,7 +1229,7 @@ bool EditorSettings::save_text_editor_theme() {
String p_file = get("text_editor/theme/color_theme");
- if (p_file.get_file().to_lower() == "default" || p_file.get_file().to_lower() == "adaptive") {
+ if (p_file.get_file().to_lower() == "default" || p_file.get_file().to_lower() == "adaptive" || p_file.get_file().to_lower() == "custom") {
return false;
}
String theme_path = get_text_editor_themes_dir().plus_file(p_file + ".tet");
@@ -1227,7 +1241,7 @@ bool EditorSettings::save_text_editor_theme_as(String p_file) {
p_file += ".tet";
}
- if (p_file.get_file().to_lower() == "default.tet" || p_file.get_file().to_lower() == "adaptive.tet") {
+ if (p_file.get_file().to_lower() == "default.tet" || p_file.get_file().to_lower() == "adaptive.tet" || p_file.get_file().to_lower() == "custom.tet") {
return false;
}
if (_save_text_editor_theme(p_file)) {
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index cc0b292cc4..4964c78496 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -972,6 +972,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("commentfocus", "GraphNode", graphsbcommentselected);
theme->set_stylebox("breakpoint", "GraphNode", graphsbbreakpoint);
theme->set_stylebox("position", "GraphNode", graphsbposition);
+
+ Color default_node_color = Color(mv2, mv2, mv2);
+ theme->set_color("title_color", "GraphNode", default_node_color);
+ default_node_color.a = 0.7;
+ theme->set_color("close_color", "GraphNode", default_node_color);
+
theme->set_constant("port_offset", "GraphNode", 14 * EDSCALE);
theme->set_constant("title_h_offset", "GraphNode", -16 * EDSCALE);
theme->set_constant("close_h_offset", "GraphNode", 20 * EDSCALE);
@@ -1050,36 +1056,71 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color search_result_color = alpha1;
const Color search_result_border_color = alpha4;
- theme->set_color("text_editor/theme/symbol_color", "Editor", symbol_color);
- theme->set_color("text_editor/theme/keyword_color", "Editor", keyword_color);
- theme->set_color("text_editor/theme/basetype_color", "Editor", basetype_color);
- theme->set_color("text_editor/theme/type_color", "Editor", type_color);
- theme->set_color("text_editor/theme/comment_color", "Editor", comment_color);
- theme->set_color("text_editor/theme/string_color", "Editor", string_color);
- theme->set_color("text_editor/theme/background_color", "Editor", te_background_color);
- theme->set_color("text_editor/theme/completion_background_color", "Editor", completion_background_color);
- theme->set_color("text_editor/theme/completion_selected_color", "Editor", completion_selected_color);
- theme->set_color("text_editor/theme/completion_existing_color", "Editor", completion_existing_color);
- theme->set_color("text_editor/theme/completion_scroll_color", "Editor", completion_scroll_color);
- theme->set_color("text_editor/theme/completion_font_color", "Editor", completion_font_color);
- theme->set_color("text_editor/theme/text_color", "Editor", text_color);
- theme->set_color("text_editor/theme/line_number_color", "Editor", line_number_color);
- theme->set_color("text_editor/theme/caret_color", "Editor", caret_color);
- theme->set_color("text_editor/theme/caret_background_color", "Editor", caret_background_color);
- theme->set_color("text_editor/theme/text_selected_color", "Editor", text_selected_color);
- theme->set_color("text_editor/theme/selection_color", "Editor", selection_color);
- theme->set_color("text_editor/theme/brace_mismatch_color", "Editor", brace_mismatch_color);
- theme->set_color("text_editor/theme/current_line_color", "Editor", current_line_color);
- theme->set_color("text_editor/theme/line_length_guideline_color", "Editor", line_length_guideline_color);
- theme->set_color("text_editor/theme/word_highlighted_color", "Editor", word_highlighted_color);
- theme->set_color("text_editor/theme/number_color", "Editor", number_color);
- theme->set_color("text_editor/theme/function_color", "Editor", function_color);
- theme->set_color("text_editor/theme/member_variable_color", "Editor", member_variable_color);
- theme->set_color("text_editor/theme/mark_color", "Editor", mark_color);
- theme->set_color("text_editor/theme/breakpoint_color", "Editor", breakpoint_color);
- theme->set_color("text_editor/theme/code_folding_color", "Editor", code_folding_color);
- theme->set_color("text_editor/theme/search_result_color", "Editor", search_result_color);
- theme->set_color("text_editor/theme/search_result_border_color", "Editor", search_result_border_color);
+ EditorSettings *setting = EditorSettings::get_singleton();
+ String text_editor_color_theme = setting->get("text_editor/theme/color_theme");
+ if (text_editor_color_theme == "Adaptive") {
+ setting->set_manually("text_editor/highlighting/symbol_color", symbol_color);
+ setting->set_manually("text_editor/highlighting/keyword_color", keyword_color);
+ setting->set_manually("text_editor/highlighting/base_type_color", basetype_color);
+ setting->set_manually("text_editor/highlighting/engine_type_color", type_color);
+ setting->set_manually("text_editor/highlighting/comment_color", comment_color);
+ setting->set_manually("text_editor/highlighting/string_color", string_color);
+ setting->set_manually("text_editor/highlighting/background_color", background_color);
+ setting->set_manually("text_editor/highlighting/completion_background_color", completion_background_color);
+ setting->set_manually("text_editor/highlighting/completion_selected_color", completion_selected_color);
+ setting->set_manually("text_editor/highlighting/completion_existing_color", completion_existing_color);
+ setting->set_manually("text_editor/highlighting/completion_scroll_color", completion_scroll_color);
+ setting->set_manually("text_editor/highlighting/completion_font_color", completion_font_color);
+ setting->set_manually("text_editor/highlighting/text_color", text_color);
+ setting->set_manually("text_editor/highlighting/line_number_color", line_number_color);
+ setting->set_manually("text_editor/highlighting/caret_color", caret_color);
+ setting->set_manually("text_editor/highlighting/caret_background_color", caret_background_color);
+ setting->set_manually("text_editor/highlighting/text_selected_color", text_selected_color);
+ setting->set_manually("text_editor/highlighting/selection_color", selection_color);
+ setting->set_manually("text_editor/highlighting/brace_mismatch_color", brace_mismatch_color);
+ setting->set_manually("text_editor/highlighting/current_line_color", current_line_color);
+ setting->set_manually("text_editor/highlighting/line_length_guideline_color", line_length_guideline_color);
+ setting->set_manually("text_editor/highlighting/word_highlighted_color", word_highlighted_color);
+ setting->set_manually("text_editor/highlighting/number_color", number_color);
+ setting->set_manually("text_editor/highlighting/function_color", function_color);
+ setting->set_manually("text_editor/highlighting/member_variable_color", member_variable_color);
+ setting->set_manually("text_editor/highlighting/mark_color", mark_color);
+ setting->set_manually("text_editor/highlighting/breakpoint_color", breakpoint_color);
+ setting->set_manually("text_editor/highlighting/code_folding_color", code_folding_color);
+ setting->set_manually("text_editor/highlighting/search_result_color", search_result_color);
+ setting->set_manually("text_editor/highlighting/search_result_border_color", search_result_border_color);
+ } else if (text_editor_color_theme == "Default") {
+ setting->set_manually("text_editor/highlighting/symbol_color", Color::html("badfff"));
+ setting->set_manually("text_editor/highlighting/keyword_color", Color::html("ffffb3"));
+ setting->set_manually("text_editor/highlighting/base_type_color", Color::html("a4ffd4"));
+ setting->set_manually("text_editor/highlighting/engine_type_color", Color::html("83d3ff"));
+ setting->set_manually("text_editor/highlighting/comment_color", Color::html("676767"));
+ setting->set_manually("text_editor/highlighting/string_color", Color::html("ef6ebe"));
+ setting->set_manually("text_editor/highlighting/background_color", Color::html("3b000000"));
+ setting->set_manually("text_editor/highlighting/completion_background_color", Color::html("2C2A32"));
+ setting->set_manually("text_editor/highlighting/completion_selected_color", Color::html("434244"));
+ setting->set_manually("text_editor/highlighting/completion_existing_color", Color::html("21dfdfdf"));
+ setting->set_manually("text_editor/highlighting/completion_scroll_color", Color::html("ffffff"));
+ setting->set_manually("text_editor/highlighting/completion_font_color", Color::html("aaaaaa"));
+ setting->set_manually("text_editor/highlighting/text_color", Color::html("aaaaaa"));
+ setting->set_manually("text_editor/highlighting/line_number_color", Color::html("66aaaaaa"));
+ setting->set_manually("text_editor/highlighting/caret_color", Color::html("aaaaaa"));
+ setting->set_manually("text_editor/highlighting/caret_background_color", Color::html("000000"));
+ setting->set_manually("text_editor/highlighting/text_selected_color", Color::html("000000"));
+ setting->set_manually("text_editor/highlighting/selection_color", Color::html("6ca9c2"));
+ setting->set_manually("text_editor/highlighting/brace_mismatch_color", Color(1, 0.2, 0.2));
+ setting->set_manually("text_editor/highlighting/current_line_color", Color(0.3, 0.5, 0.8, 0.15));
+ setting->set_manually("text_editor/highlighting/line_length_guideline_color", Color(0.3, 0.5, 0.8, 0.1));
+ setting->set_manually("text_editor/highlighting/word_highlighted_color", Color(0.8, 0.9, 0.9, 0.15));
+ setting->set_manually("text_editor/highlighting/number_color", Color::html("EB9532"));
+ setting->set_manually("text_editor/highlighting/function_color", Color::html("66a2ce"));
+ setting->set_manually("text_editor/highlighting/member_variable_color", Color::html("e64e59"));
+ setting->set_manually("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4));
+ setting->set_manually("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2));
+ setting->set_manually("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
+ setting->set_manually("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
+ setting->set_manually("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1));
+ }
return theme;
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index c30f077888..812379faca 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -147,7 +147,7 @@ void FileSystemDock::_notification(int p_what) {
if (low_height_mode) {
- file_list_vb->hide();
+ tree->hide();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
button_tree->show();
} else {
@@ -158,6 +158,7 @@ void FileSystemDock::_notification(int p_what) {
button_favorite->show();
_update_tree(true);
}
+ tree->ensure_cursor_is_visible();
if (!file_list_vb->is_visible()) {
file_list_vb->show();
@@ -345,11 +346,7 @@ void FileSystemDock::navigate_to_path(const String &p_path) {
_update_tree(true);
_update_files(false);
} else {
- if (file_name.empty()) {
- _go_to_tree();
- } else {
- _go_to_file_list();
- }
+ _go_to_file_list();
}
if (!file_name.empty()) {
@@ -406,12 +403,12 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List<FileInfo> *
_search(p_path->get_subdir(i), matches, p_max_items);
}
- String match = search_box->get_text();
+ String match = search_box->get_text().to_lower();
for (int i = 0; i < p_path->get_file_count(); i++) {
String file = p_path->get_file(i);
- if (file.find(match) != -1) {
+ if (file.to_lower().find(match) != -1) {
FileInfo fi;
fi.name = file;
@@ -837,6 +834,58 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
memdelete(da);
}
+void FileSystemDock::_update_resource_paths_after_move(const Map<String, String> &p_renames) const {
+
+ //Rename all resources loaded, be it subresources or actual resources
+ List<Ref<Resource> > cached;
+ ResourceCache::get_cached_resources(&cached);
+
+ for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) {
+
+ Ref<Resource> r = E->get();
+
+ String base_path = r->get_path();
+ String extra_path;
+ int sep_pos = r->get_path().find("::");
+ if (sep_pos >= 0) {
+ extra_path = base_path.substr(sep_pos, base_path.length());
+ base_path = base_path.substr(0, sep_pos);
+ }
+
+ if (p_renames.has(base_path)) {
+ base_path = p_renames[base_path];
+ }
+
+ r->set_path(base_path + extra_path);
+ }
+
+ for (int i = 0; i < EditorNode::get_editor_data().get_edited_scene_count(); i++) {
+
+ String path;
+ if (i == EditorNode::get_editor_data().get_edited_scene()) {
+ if (!get_tree()->get_edited_scene_root())
+ continue;
+
+ path = get_tree()->get_edited_scene_root()->get_filename();
+ } else {
+
+ path = EditorNode::get_editor_data().get_scene_path(i);
+ }
+
+ if (p_renames.has(path)) {
+ path = p_renames[path];
+ }
+
+ if (i == EditorNode::get_editor_data().get_edited_scene()) {
+
+ get_tree()->get_edited_scene_root()->set_filename(path);
+ } else {
+
+ EditorNode::get_editor_data().set_scene_path(i, path);
+ }
+ }
+}
+
void FileSystemDock::_update_dependencies_after_move(const Map<String, String> &p_renames) const {
//The following code assumes that the following holds:
// 1) EditorFileSystem contains the old paths/folder structure from before the rename/move.
@@ -913,6 +962,7 @@ void FileSystemDock::_rename_operation_confirm() {
Map<String, String> renames;
_try_move_item(to_rename, new_path, renames);
_update_dependencies_after_move(renames);
+ _update_resource_paths_after_move(renames);
//Rescan everything
print_line("call rescan!");
@@ -962,6 +1012,8 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path) {
}
_update_dependencies_after_move(renames);
+ _update_resource_paths_after_move(renames);
+
print_line("call rescan!");
_rescan();
}
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index bc8d835ba1..65a71b86e0 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -178,6 +178,7 @@ private:
void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, Map<String, String> &p_renames) const;
void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const;
void _update_dependencies_after_move(const Map<String, String> &p_renames) const;
+ void _update_resource_paths_after_move(const Map<String, String> &p_renames) const;
void _make_dir_confirm();
void _rename_operation_confirm();
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index 00eb69a568..189e98ea68 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -185,11 +185,13 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
}
if (n.has("skin")) {
node->skin = n["skin"];
+ /*
if (!state.skin_users.has(node->skin)) {
state.skin_users[node->skin] = Vector<int>();
}
state.skin_users[node->skin].push_back(i);
+ */
}
if (n.has("matrix")) {
node->xform = _arr_to_xform(n["matrix"]);
@@ -1316,8 +1318,10 @@ Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) {
for (int j = 0; j < joints.size(); j++) {
int index = joints[j];
ERR_FAIL_INDEX_V(index, state.nodes.size(), ERR_PARSE_ERROR);
- state.nodes[index]->joint_skin = state.skins.size();
- state.nodes[index]->joint_bone = j;
+ GLTFNode::Joint joint;
+ joint.skin = state.skins.size();
+ joint.bone = j;
+ state.nodes[index]->joints.push_back(joint);
GLTFSkin::Bone bone;
bone.node = index;
if (bind_matrices.size()) {
@@ -1331,7 +1335,7 @@ Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) {
if (d.has("skeleton")) {
int skeleton = d["skeleton"];
ERR_FAIL_INDEX_V(skeleton, state.nodes.size(), ERR_PARSE_ERROR);
- state.nodes[skeleton]->skeleton_skin = state.skins.size();
+ //state.nodes[skeleton]->skeleton_skin = state.skins.size();
print_line("setting skeleton skin to" + itos(skeleton));
skin.skeleton = skeleton;
}
@@ -1341,7 +1345,7 @@ Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) {
}
//locate the right place to put a Skeleton node
-
+ /*
if (state.skin_users.has(i)) {
Vector<int> users = state.skin_users[i];
int skin_node = -1;
@@ -1382,6 +1386,7 @@ Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) {
state.nodes[skin_node]->skeleton_children.push_back(i);
}
}
+ */
state.skins.push_back(skin);
}
print_line("total skins: " + itos(state.skins.size()));
@@ -1577,7 +1582,7 @@ void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) {
if (n->name == "") {
if (n->mesh >= 0) {
n->name = "Mesh";
- } else if (n->joint_skin >= 0) {
+ } else if (n->joints.size()) {
n->name = "Bone";
} else {
n->name = "Node";
@@ -1607,6 +1612,7 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node
}
node = mi;
+
} else if (n->camera >= 0) {
ERR_FAIL_INDEX(n->camera, state.cameras.size());
Camera *camera = memnew(Camera);
@@ -1625,18 +1631,20 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node
node->set_name(n->name);
- if (n->child_of_skeleton >= 0) {
- //move skeleton around and place it on node, as the node _is_ a skeleton.
- Skeleton *s = skeletons[n->child_of_skeleton];
- p_parent = s;
- }
-
p_parent->add_child(node);
node->set_owner(p_owner);
node->set_transform(n->xform);
- n->godot_node = node;
+ n->godot_nodes.push_back(node);
+
+ if (n->skin >= 0 && Object::cast_to<MeshInstance>(node)) {
+ MeshInstance *mi = Object::cast_to<MeshInstance>(node);
+ //move skeleton around and place it on node, as the node _is_ a skeleton.
+ Skeleton *s = skeletons[n->skin];
+ mi->set_skeleton_path(mi->get_path_to(s));
+ }
+#if 0
for (int i = 0; i < n->skeleton_children.size(); i++) {
Skeleton *s = skeletons[n->skeleton_children[i]];
@@ -1644,36 +1652,39 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node
node->add_child(s);
s->set_owner(p_owner);
}
-
+#endif
for (int i = 0; i < n->children.size(); i++) {
- if (state.nodes[n->children[i]]->joint_skin >= 0) {
- _generate_bone(state, n->children[i], skeletons, -1);
+ if (state.nodes[n->children[i]]->joints.size()) {
+ _generate_bone(state, n->children[i], skeletons, Vector<int>());
} else {
_generate_node(state, n->children[i], node, p_owner, skeletons);
}
}
}
-void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, int p_parent_bone) {
+void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, const Vector<int> &p_parent_bones) {
ERR_FAIL_INDEX(p_node, state.nodes.size());
GLTFNode *n = state.nodes[p_node];
+ Vector<int> parent_bones;
- ERR_FAIL_COND(n->joint_skin < 0);
+ for (int i = 0; i < n->joints.size(); i++) {
+ ERR_FAIL_COND(n->joints[i].skin < 0);
- int bone_index = skeletons[n->joint_skin]->get_bone_count();
- skeletons[n->joint_skin]->add_bone(n->name);
- if (p_parent_bone >= 0) {
- skeletons[n->joint_skin]->set_bone_parent(bone_index, p_parent_bone);
- }
- skeletons[n->joint_skin]->set_bone_rest(bone_index, state.skins[n->joint_skin].bones[n->joint_bone].inverse_bind.affine_inverse());
+ int bone_index = skeletons[n->joints[i].skin]->get_bone_count();
+ skeletons[n->joints[i].skin]->add_bone(n->name);
+ if (p_parent_bones.size()) {
+ skeletons[n->joints[i].skin]->set_bone_parent(bone_index, p_parent_bones[i]);
+ }
+ skeletons[n->joints[i].skin]->set_bone_rest(bone_index, state.skins[n->joints[i].skin].bones[n->joints[i].bone].inverse_bind.affine_inverse());
- n->godot_node = skeletons[n->joint_skin];
- n->godot_bone_index = bone_index;
+ n->godot_nodes.push_back(skeletons[n->joints[i].skin]);
+ n->joints[i].godot_bone_index = bone_index;
+ parent_bones.push_back(bone_index);
+ }
for (int i = 0; i < n->children.size(); i++) {
- ERR_CONTINUE(state.nodes[n->children[i]]->joint_skin < 0);
- _generate_bone(state, n->children[i], skeletons, bone_index);
+ _generate_bone(state, n->children[i], skeletons, parent_bones);
}
}
@@ -1818,141 +1829,104 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
NodePath node_path;
GLTFNode *node = state.nodes[E->key()];
- ERR_CONTINUE(!node->godot_node);
-
- if (node->godot_bone_index >= 0) {
- Skeleton *sk = (Skeleton *)node->godot_node;
- String path = ap->get_parent()->get_path_to(sk);
- String bone = sk->get_bone_name(node->godot_bone_index);
- node_path = path + ":" + bone;
- } else {
- node_path = ap->get_parent()->get_path_to(node->godot_node);
- }
-
- float length = 0;
+ for (int i = 0; i < node->godot_nodes.size(); i++) {
- for (int i = 0; i < track.rotation_track.times.size(); i++) {
- length = MAX(length, track.rotation_track.times[i]);
- }
- for (int i = 0; i < track.translation_track.times.size(); i++) {
- length = MAX(length, track.translation_track.times[i]);
- }
- for (int i = 0; i < track.scale_track.times.size(); i++) {
- length = MAX(length, track.scale_track.times[i]);
- }
-
- for (int i = 0; i < track.weight_tracks.size(); i++) {
- for (int j = 0; j < track.weight_tracks[i].times.size(); j++) {
- length = MAX(length, track.weight_tracks[i].times[j]);
+ if (node->joints.size()) {
+ Skeleton *sk = (Skeleton *)node->godot_nodes[i];
+ String path = ap->get_parent()->get_path_to(sk);
+ String bone = sk->get_bone_name(node->joints[i].godot_bone_index);
+ node_path = path + ":" + bone;
+ } else {
+ node_path = ap->get_parent()->get_path_to(node->godot_nodes[i]);
}
- }
-
- animation->set_length(length);
-
- if (track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) {
- //make transform track
- int track_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_TRANSFORM);
- animation->track_set_path(track_idx, node_path);
- //first determine animation length
- float increment = 1.0 / float(bake_fps);
- float time = 0.0;
+ float length = 0;
- Vector3 base_pos;
- Quat base_rot;
- Vector3 base_scale = Vector3(1, 1, 1);
-
- if (!track.rotation_track.values.size()) {
- base_rot = state.nodes[E->key()]->rotation;
+ for (int i = 0; i < track.rotation_track.times.size(); i++) {
+ length = MAX(length, track.rotation_track.times[i]);
}
-
- if (!track.translation_track.values.size()) {
- base_pos = state.nodes[E->key()]->translation;
+ for (int i = 0; i < track.translation_track.times.size(); i++) {
+ length = MAX(length, track.translation_track.times[i]);
+ }
+ for (int i = 0; i < track.scale_track.times.size(); i++) {
+ length = MAX(length, track.scale_track.times[i]);
}
- if (!track.scale_track.values.size()) {
- base_scale = state.nodes[E->key()]->scale;
+ for (int i = 0; i < track.weight_tracks.size(); i++) {
+ for (int j = 0; j < track.weight_tracks[i].times.size(); j++) {
+ length = MAX(length, track.weight_tracks[i].times[j]);
+ }
}
- bool last = false;
- while (true) {
+ animation->set_length(length);
+
+ if (track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) {
+ //make transform track
+ int track_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_TRANSFORM);
+ animation->track_set_path(track_idx, node_path);
+ //first determine animation length
- Vector3 pos = base_pos;
- Quat rot = base_rot;
- Vector3 scale = base_scale;
+ float increment = 1.0 / float(bake_fps);
+ float time = 0.0;
- if (track.translation_track.times.size()) {
+ Vector3 base_pos;
+ Quat base_rot;
+ Vector3 base_scale = Vector3(1, 1, 1);
- pos = _interpolate_track<Vector3>(track.translation_track.times, track.translation_track.values, time, track.translation_track.interpolation);
+ if (!track.rotation_track.values.size()) {
+ base_rot = state.nodes[E->key()]->rotation;
}
- if (track.rotation_track.times.size()) {
+ if (!track.translation_track.values.size()) {
+ base_pos = state.nodes[E->key()]->translation;
+ }
- rot = _interpolate_track<Quat>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation);
+ if (!track.scale_track.values.size()) {
+ base_scale = state.nodes[E->key()]->scale;
}
- if (track.scale_track.times.size()) {
+ bool last = false;
+ while (true) {
- scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation);
- }
+ Vector3 pos = base_pos;
+ Quat rot = base_rot;
+ Vector3 scale = base_scale;
- if (node->godot_bone_index >= 0) {
+ if (track.translation_track.times.size()) {
- Transform xform;
- xform.basis = Basis(rot);
- xform.basis.scale(scale);
- xform.origin = pos;
+ pos = _interpolate_track<Vector3>(track.translation_track.times, track.translation_track.values, time, track.translation_track.interpolation);
+ }
- Skeleton *skeleton = skeletons[node->joint_skin];
- int bone = node->godot_bone_index;
- xform = skeleton->get_bone_rest(bone).affine_inverse() * xform;
+ if (track.rotation_track.times.size()) {
- rot = xform.basis;
- rot.normalize();
- scale = xform.basis.get_scale();
- pos = xform.origin;
- }
+ rot = _interpolate_track<Quat>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation);
+ }
- animation->transform_track_insert_key(track_idx, time, pos, rot, scale);
+ if (track.scale_track.times.size()) {
- if (last) {
- break;
- }
- time += increment;
- if (time >= length) {
- last = true;
- time = length;
- }
- }
- }
+ scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation);
+ }
- for (int i = 0; i < track.weight_tracks.size(); i++) {
- ERR_CONTINUE(node->mesh < 0 || node->mesh >= state.meshes.size());
- const GLTFMesh &mesh = state.meshes[node->mesh];
- String prop = "blend_shapes/" + mesh.mesh->get_blend_shape_name(i);
- node_path = String(node_path) + ":" + prop;
+ if (node->joints.size()) {
- int track_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_VALUE);
- animation->track_set_path(track_idx, node_path);
+ Transform xform;
+ xform.basis = Basis(rot);
+ xform.basis.scale(scale);
+ xform.origin = pos;
- if (track.weight_tracks[i].interpolation <= GLTFAnimation::INTERP_STEP) {
- animation->track_set_interpolation_type(track_idx, track.weight_tracks[i].interpolation == GLTFAnimation::INTERP_STEP ? Animation::INTERPOLATION_NEAREST : Animation::INTERPOLATION_NEAREST);
- for (int j = 0; j < track.weight_tracks[i].times.size(); j++) {
- float t = track.weight_tracks[i].times[j];
- float w = track.weight_tracks[i].values[j];
- animation->track_insert_key(track_idx, t, w);
- }
- } else {
- //must bake, apologies.
- float increment = 1.0 / float(bake_fps);
- float time = 0.0;
+ Skeleton *skeleton = skeletons[node->joints[i].skin];
+ int bone = node->joints[i].godot_bone_index;
+ xform = skeleton->get_bone_rest(bone).affine_inverse() * xform;
- bool last = false;
- while (true) {
+ rot = xform.basis;
+ rot.normalize();
+ scale = xform.basis.get_scale();
+ pos = xform.origin;
+ }
+
+ animation->transform_track_insert_key(track_idx, time, pos, rot, scale);
- _interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, track.weight_tracks[i].interpolation);
if (last) {
break;
}
@@ -1963,6 +1937,44 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
}
}
}
+
+ for (int i = 0; i < track.weight_tracks.size(); i++) {
+ ERR_CONTINUE(node->mesh < 0 || node->mesh >= state.meshes.size());
+ const GLTFMesh &mesh = state.meshes[node->mesh];
+ String prop = "blend_shapes/" + mesh.mesh->get_blend_shape_name(i);
+ node_path = String(node_path) + ":" + prop;
+
+ int track_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_VALUE);
+ animation->track_set_path(track_idx, node_path);
+
+ if (track.weight_tracks[i].interpolation <= GLTFAnimation::INTERP_STEP) {
+ animation->track_set_interpolation_type(track_idx, track.weight_tracks[i].interpolation == GLTFAnimation::INTERP_STEP ? Animation::INTERPOLATION_NEAREST : Animation::INTERPOLATION_NEAREST);
+ for (int j = 0; j < track.weight_tracks[i].times.size(); j++) {
+ float t = track.weight_tracks[i].times[j];
+ float w = track.weight_tracks[i].values[j];
+ animation->track_insert_key(track_idx, t, w);
+ }
+ } else {
+ //must bake, apologies.
+ float increment = 1.0 / float(bake_fps);
+ float time = 0.0;
+
+ bool last = false;
+ while (true) {
+
+ _interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, track.weight_tracks[i].interpolation);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= length) {
+ last = true;
+ time = length;
+ }
+ }
+ }
+ }
}
}
@@ -1987,8 +1999,8 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f
skeletons.push_back(s);
}
for (int i = 0; i < state.root_nodes.size(); i++) {
- if (state.nodes[state.root_nodes[i]]->joint_skin >= 0) {
- _generate_bone(state, state.root_nodes[i], skeletons, -1);
+ if (state.nodes[state.root_nodes[i]]->joints.size()) {
+ _generate_bone(state, state.root_nodes[i], skeletons, Vector<int>());
} else {
_generate_node(state, state.root_nodes[i], root, root, skeletons);
}
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index 91c584a05a..abbdfa418b 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -52,18 +52,29 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Transform xform;
String name;
- Node *godot_node;
- int godot_bone_index;
+ //Node *godot_node;
+ //int godot_bone_index;
int mesh;
int camera;
int skin;
- int skeleton_skin;
- int child_of_skeleton; // put as children of skeleton
- Vector<int> skeleton_children; //skeleton put as children of this
+ //int skeleton_skin;
+ //int child_of_skeleton; // put as children of skeleton
+ //Vector<int> skeleton_children; //skeleton put as children of this
+
+ struct Joint {
+ int skin;
+ int bone;
+ int godot_bone_index;
+
+ Joint() {
+ skin = -1;
+ bone = -1;
+ godot_bone_index = -1;
+ }
+ };
- int joint_skin;
- int joint_bone;
+ Vector<Joint> joints;
//keep them for animation
Vector3 translation;
@@ -71,17 +82,15 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector3 scale;
Vector<int> children;
+ Vector<Node *> godot_nodes;
GLTFNode() {
- godot_node = NULL;
- godot_bone_index = -1;
- joint_skin = -1;
- joint_bone = -1;
- child_of_skeleton = -1;
- skeleton_skin = -1;
+ // child_of_skeleton = -1;
+ // skeleton_skin = -1;
mesh = -1;
camera = -1;
parent = -1;
+ skin = -1;
scale = Vector3(1, 1, 1);
}
};
@@ -235,7 +244,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<GLTFAnimation> animations;
- Map<int, Vector<int> > skin_users; //cache skin users
+ //Map<int, Vector<int> > skin_users; //cache skin users
~GLTFState() {
for (int i = 0; i < nodes.size(); i++) {
@@ -269,7 +278,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<Basis> _decode_accessor_as_basis(GLTFState &state, int p_accessor, bool p_for_vertex);
Vector<Transform> _decode_accessor_as_xform(GLTFState &state, int p_accessor, bool p_for_vertex);
- void _generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, int p_parent_bone);
+ void _generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, const Vector<int> &p_parent_bones);
void _generate_node(GLTFState &state, int p_node, Node *p_parent, Node *p_owner, Vector<Skeleton *> &skeletons);
void _import_animation(GLTFState &state, AnimationPlayer *ap, int index, int bake_fps, Vector<Skeleton *> skeletons);
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index ff72a5a25e..b19cc8e565 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -235,7 +235,7 @@ void AbstractPolygon2DEditor::_wip_close() {
if (_is_line()) {
_set_polygon(0, wip);
- } else if (wip.size() >= 3) {
+ } else if (wip.size() >= (_is_line() ? 2 : 3)) {
undo_redo->create_action(TTR("Create Poly"));
_action_add_polygon(wip);
@@ -281,46 +281,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Vector2 gpoint = mb->get_position();
Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
- if (mode == MODE_CREATE) {
-
- if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
-
- if (!wip_active) {
-
- wip.clear();
- wip.push_back(cpoint);
- wip_active = true;
- _wip_changed();
- edited_point = PosVertex(-1, 1, cpoint);
- canvas_item_editor->get_viewport_control()->update();
- hover_point = Vertex();
- selected_point = Vertex(0);
- edge_point = PosVertex();
- return true;
- } else {
-
- const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
-
- if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) {
- //wip closed
- _wip_close();
-
- return true;
- } else {
-
- //add wip point
- wip.push_back(cpoint);
- _wip_changed();
- edited_point = PosVertex(-1, wip.size(), cpoint);
- selected_point = Vertex(wip.size() - 1);
- canvas_item_editor->get_viewport_control()->update();
- return true;
- }
- }
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
- _wip_close();
- }
- } else if (mode == MODE_EDIT) {
+ if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
if (mb->get_button_index() == BUTTON_LEFT) {
@@ -332,7 +293,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Vector<Vector2> vertices = _get_polygon(insert.polygon);
- if (vertices.size() < 3) {
+ if (vertices.size() < (_is_line() ? 2 : 3)) {
vertices.push_back(cpoint);
undo_redo->create_action(TTR("Edit Poly"));
@@ -344,6 +305,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Vector<Vector2> vertices = _get_polygon(insert.polygon);
pre_move_edit = vertices;
+ printf("setting pre_move_edit\n");
edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos));
vertices.insert(edited_point.vertex, edited_point.pos);
selected_point = edited_point;
@@ -362,6 +324,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (closest.valid()) {
+ printf("setting pre_move_edit\n");
pre_move_edit = _get_polygon(closest.polygon);
edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos));
selected_point = closest;
@@ -414,6 +377,56 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
}
}
}
+
+ if (mode == MODE_CREATE) {
+
+ if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+
+ if (_is_line()) {
+
+ // for lines, we don't have a wip mode, and we can undo each single add point.
+ Vector<Vector2> vertices = _get_polygon(0);
+ vertices.push_back(cpoint);
+ undo_redo->create_action(TTR("Insert Point"));
+ _action_set_polygon(0, vertices);
+ _commit_action();
+ return true;
+ } else if (!wip_active) {
+
+ wip.clear();
+ wip.push_back(cpoint);
+ wip_active = true;
+ _wip_changed();
+ edited_point = PosVertex(-1, 1, cpoint);
+ canvas_item_editor->get_viewport_control()->update();
+ hover_point = Vertex();
+ selected_point = Vertex(0);
+ edge_point = PosVertex();
+ return true;
+ } else {
+
+ const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
+
+ if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) {
+ //wip closed
+ _wip_close();
+
+ return true;
+ } else {
+
+ //add wip point
+ wip.push_back(cpoint);
+ _wip_changed();
+ edited_point = PosVertex(-1, wip.size(), cpoint);
+ selected_point = Vertex(wip.size() - 1);
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ }
+ } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
+ _wip_close();
+ }
+ }
}
Ref<InputEventMouseMotion> mm = p_event;
@@ -436,7 +449,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
}
canvas_item_editor->get_viewport_control()->update();
- } else if (mode == MODE_EDIT) {
+ } else if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
const PosVertex onEdgeVertex = closest_edge_point(gpoint);
@@ -535,7 +548,7 @@ void AbstractPolygon2DEditor::forward_draw_over_viewport(Control *p_overlay) {
const Color col = Color(0.5, 0.5, 0.5); // FIXME polygon->get_outline_color();
const int n = pre_move_edit.size();
- for (int i = 0; i < n - is_closed ? 0 : 1; i++) {
+ for (int i = 0; i < n - (is_closed ? 0 : 1); i++) {
Vector2 p, p2;
p = pre_move_edit[i] + offset;
@@ -544,7 +557,7 @@ void AbstractPolygon2DEditor::forward_draw_over_viewport(Control *p_overlay) {
Vector2 point = xform.xform(p);
Vector2 next_point = xform.xform(p2);
- vpc->draw_line(point, next_point, col, 2);
+ vpc->draw_line(point, next_point, col, 2 * EDSCALE);
}
}
@@ -568,7 +581,7 @@ void AbstractPolygon2DEditor::forward_draw_over_viewport(Control *p_overlay) {
p2 = points[(i + 1) % n_points] + offset;
const Vector2 next_point = xform.xform(p2);
- vpc->draw_line(point, next_point, col, 2);
+ vpc->draw_line(point, next_point, col, 2 * EDSCALE);
}
}
@@ -630,7 +643,7 @@ void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) {
PoolVector<Vector2> vertices = _get_polygon(p_vertex.polygon);
- if (vertices.size() > 3) {
+ if (vertices.size() > (_is_line() ? 2 : 3)) {
vertices.remove(p_vertex.vertex);
@@ -705,8 +718,9 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(c
PoolVector<Vector2> points = _get_polygon(j);
const Vector2 offset = _get_offset(j);
const int n_points = points.size();
+ const int n_segments = n_points - (_is_line() ? 1 : 0);
- for (int i = 0; i < n_points; i++) {
+ for (int i = 0; i < n_segments; i++) {
Vector2 segment[2] = { xform.xform(points[i] + offset),
xform.xform(points[(i + 1) % n_points] + offset) };
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index 8fe6538653..0c6c608d3d 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -1435,7 +1435,7 @@ AnimationTreeEditorPlugin::AnimationTreeEditorPlugin(EditorNode *p_node) {
anim_tree_editor = memnew(AnimationTreeEditor);
anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
- button = editor->add_bottom_panel_item("AnimationTree", anim_tree_editor);
+ button = editor->add_bottom_panel_item(TTR("AnimationTree"), anim_tree_editor);
button->hide();
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index f5bfea3395..1241441d43 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4100,7 +4100,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
select_button->connect("pressed", this, "_tool_select", make_binds(TOOL_SELECT));
select_button->set_pressed(true);
select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), KEY_Q));
- select_button->set_tooltip(TTR("Select Mode") + " $sc\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate") + "\n" + TTR("Alt+Drag: Move") + "\n" + TTR("Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving).") + "\n" + TTR("Alt+RMB: Depth list selection"));
+ select_button->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate") + "\n" + TTR("Alt+Drag: Move") + "\n" + TTR("Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving).") + "\n" + TTR("Alt+RMB: Depth list selection"));
move_button = memnew(ToolButton);
hb->add_child(move_button);
@@ -4344,7 +4344,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
additive_selection = false;
// Update the menus checkboxes
- call_deferred("set_state", get_state());
+ set_state(get_state());
}
CanvasItemEditor *CanvasItemEditor::singleton = NULL;
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index 3210af1433..88649ca267 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -444,7 +444,7 @@ ResourcePreloaderEditorPlugin::ResourcePreloaderEditorPlugin(EditorNode *p_node)
preloader_editor = memnew(ResourcePreloaderEditor);
preloader_editor->set_custom_minimum_size(Size2(0, 250));
- button = editor->add_bottom_panel_item("ResourcePreloader", preloader_editor);
+ button = editor->add_bottom_panel_item(TTR("ResourcePreloader"), preloader_editor);
button->hide();
//preloader_editor->set_anchor( MARGIN_TOP, Control::ANCHOR_END);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 591e6dac56..2f0f21cc0e 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -132,7 +132,7 @@ public:
I = I->next();
}
- if (O != E) { //should never heppane..
+ if (O != E) { //should never happen..
cached.erase(O);
}
}
@@ -234,7 +234,6 @@ ScriptEditorQuickOpen::ScriptEditorQuickOpen() {
VBoxContainer *vbc = memnew(VBoxContainer);
add_child(vbc);
- //set_child_rect(vbc);
search_box = memnew(LineEdit);
vbc->add_margin_child(TTR("Search:"), search_box);
search_box->connect("text_changed", this, "_text_changed");
@@ -257,8 +256,6 @@ ScriptEditor *ScriptEditor::script_editor = NULL;
String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) {
- //ScriptEditorBase *se=Object::cast_to<ScriptEditorBase>(_se);
-
String val = debugger->get_var_value(p_text);
if (val != String()) {
return p_text + ": " + val;
@@ -551,8 +548,6 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save) {
idx = history[history_pos].control->get_index();
}
tab_container->set_current_tab(idx);
-
- //script_list->select(idx);
}
_update_history_arrows();
@@ -698,7 +693,6 @@ void ScriptEditor::_reload_scripts() {
uint64_t last_date = script->get_last_modified_time();
uint64_t date = FileAccess::get_modified_time(script->get_path());
- //printf("last date: %lli vs date: %lli\n",last_date,date);
if (last_date == date) {
continue;
}
@@ -776,7 +770,6 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) {
uint64_t last_date = script->get_last_modified_time();
uint64_t date = FileAccess::get_modified_time(script->get_path());
- //printf("last date: %lli vs date: %lli\n",last_date,date);
if (last_date != date) {
TreeItem *ti = disk_changed_list->create_item(r);
@@ -786,7 +779,6 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) {
need_ask = true;
}
need_reload = true;
- //r->set_metadata(0,);
}
}
}
@@ -1205,9 +1197,6 @@ void ScriptEditor::_notification(int p_what) {
_update_modified_scripts_for_external_editor();
} break;
- case NOTIFICATION_PROCESS: {
- } break;
-
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
help_search->set_icon(get_icon("HelpSearch", "EditorIcons"));
@@ -1367,18 +1356,9 @@ void ScriptEditor::ensure_select_current() {
if (!grab_focus_block && is_visible_in_tree())
se->ensure_focus();
-
- //edit_menu->show();
- //search_menu->show();
}
EditorHelp *eh = Object::cast_to<EditorHelp>(current);
-
- if (eh) {
- //edit_menu->hide();
- //search_menu->hide();
- //script_search_menu->show();
- }
}
_update_selected_editor_menu();
@@ -1823,12 +1803,8 @@ void ScriptEditor::save_all_scripts() {
if (script.is_valid())
se->apply_code();
- if (script->get_path() != "" && script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) {
- //external script, save it
-
- editor->save_resource(script);
- //ResourceSaver::save(script->get_path(),script);
- }
+ if (script->get_path() != "" && script->get_path().find("local://") == -1 && script->get_path().find("::") == -1)
+ editor->save_resource(script); //external script, save it
}
_update_script_names();
@@ -1886,7 +1862,6 @@ void ScriptEditor::_editor_stop() {
void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const PoolStringArray &p_args) {
- //print_line("add callback! hohoho"); kinda sad to remove this
ERR_FAIL_COND(!p_obj);
Ref<Script> script = p_obj->get_script();
ERR_FAIL_COND(!script.is_valid());
@@ -1981,8 +1956,6 @@ void ScriptEditor::_script_split_dragged(float) {
Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
- // return Variant(); // return this if drag disabled
-
Node *cur_node = tab_container->get_child(tab_container->get_current_tab());
HBoxContainer *drag_preview = memnew(HBoxContainer);
@@ -2202,9 +2175,6 @@ void ScriptEditor::_make_script_list_context_menu() {
}
EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(selected));
- if (eh) {
- // nothing
- }
context_menu->add_separator();
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_up"), WINDOW_MOVE_UP);
@@ -2547,9 +2517,9 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method("_script_changed", &ScriptEditor::_script_changed);
ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ScriptEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ScriptEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &ScriptEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw);
+ 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("get_current_script"), &ScriptEditor::_get_current_script);
ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts);
@@ -2588,10 +2558,9 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
script_list = memnew(ItemList);
list_split->add_child(script_list);
- script_list->set_custom_minimum_size(Size2(150 * EDSCALE, 100)); //need to give a bit of limit to avoid it from disappearing
+ script_list->set_custom_minimum_size(Size2(150 * EDSCALE, 90)); //need to give a bit of limit to avoid it from disappearing
script_list->set_v_size_flags(SIZE_EXPAND_FILL);
script_split->set_split_offset(140);
- //list_split->set_split_offset(500);
_sort_list_on_update = true;
script_list->connect("gui_input", this, "_script_list_gui_input");
script_list->set_allow_rmb_select(true);
@@ -2603,18 +2572,18 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
members_overview = memnew(ItemList);
list_split->add_child(members_overview);
- members_overview->set_custom_minimum_size(Size2(0, 100)); //need to give a bit of limit to avoid it from disappearing
+ members_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing
members_overview->set_v_size_flags(SIZE_EXPAND_FILL);
help_overview = memnew(ItemList);
list_split->add_child(help_overview);
- help_overview->set_custom_minimum_size(Size2(0, 100)); //need to give a bit of limit to avoid it from disappearing
+ help_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing
help_overview->set_v_size_flags(SIZE_EXPAND_FILL);
tab_container = memnew(TabContainer);
tab_container->set_tabs_visible(false);
+ tab_container->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
script_split->add_child(tab_container);
-
tab_container->set_h_size_flags(SIZE_EXPAND_FILL);
ED_SHORTCUT("script_editor/window_sort", TTR("Sort"));
@@ -2762,7 +2731,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
{
VBoxContainer *vbc = memnew(VBoxContainer);
disk_changed->add_child(vbc);
- //disk_changed->set_child_rect(vbc);
Label *dl = memnew(Label);
dl->set_text(TTR("The following files are newer on disk.\nWhat action should be taken?:"));
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 0610f55b3f..a59f1a3690 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -75,72 +75,36 @@ void ScriptTextEditor::_load_theme_settings() {
text_edit->clear_colors();
- Color background_color = EDITOR_DEF("text_editor/highlighting/background_color", Color(0, 0, 0, 0));
- Color completion_background_color = EDITOR_DEF("text_editor/highlighting/completion_background_color", Color(0, 0, 0, 0));
- Color completion_selected_color = EDITOR_DEF("text_editor/highlighting/completion_selected_color", Color::html("434244"));
- Color completion_existing_color = EDITOR_DEF("text_editor/highlighting/completion_existing_color", Color::html("21dfdfdf"));
- Color completion_scroll_color = EDITOR_DEF("text_editor/highlighting/completion_scroll_color", Color::html("ffffff"));
- Color completion_font_color = EDITOR_DEF("text_editor/highlighting/completion_font_color", Color::html("aaaaaa"));
- Color text_color = EDITOR_DEF("text_editor/highlighting/text_color", Color(0, 0, 0));
- Color line_number_color = EDITOR_DEF("text_editor/highlighting/line_number_color", Color(0, 0, 0));
- Color caret_color = EDITOR_DEF("text_editor/highlighting/caret_color", Color(0, 0, 0));
- Color caret_background_color = EDITOR_DEF("text_editor/highlighting/caret_background_color", Color(0, 0, 0));
- Color text_selected_color = EDITOR_DEF("text_editor/highlighting/text_selected_color", Color(1, 1, 1));
- Color selection_color = EDITOR_DEF("text_editor/highlighting/selection_color", Color(0.2, 0.2, 1));
- Color brace_mismatch_color = EDITOR_DEF("text_editor/highlighting/brace_mismatch_color", Color(1, 0.2, 0.2));
- Color current_line_color = EDITOR_DEF("text_editor/highlighting/current_line_color", Color(0.3, 0.5, 0.8, 0.15));
- Color line_length_guideline_color = EDITOR_DEF("text_editor/highlighting/line_length_guideline_color", Color(0, 0, 0));
- Color word_highlighted_color = EDITOR_DEF("text_editor/highlighting/word_highlighted_color", Color(0.8, 0.9, 0.9, 0.15));
- Color number_color = EDITOR_DEF("text_editor/highlighting/number_color", Color(0.9, 0.6, 0.0, 2));
- Color function_color = EDITOR_DEF("text_editor/highlighting/function_color", Color(0.4, 0.6, 0.8));
- Color member_variable_color = EDITOR_DEF("text_editor/highlighting/member_variable_color", Color(0.9, 0.3, 0.3));
- Color mark_color = EDITOR_DEF("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4));
- Color breakpoint_color = EDITOR_DEF("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2));
- Color code_folding_color = EDITOR_DEF("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
- Color search_result_color = EDITOR_DEF("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
- Color search_result_border_color = EDITOR_DEF("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1));
- Color symbol_color = EDITOR_DEF("text_editor/highlighting/symbol_color", Color::hex(0x005291ff));
- Color keyword_color = EDITOR_DEF("text_editor/highlighting/keyword_color", Color(0.5, 0.0, 0.2));
- Color basetype_color = EDITOR_DEF("text_editor/highlighting/base_type_color", Color(0.3, 0.3, 0.0));
- Color type_color = EDITOR_DEF("text_editor/highlighting/engine_type_color", Color(0.0, 0.2, 0.4));
- Color comment_color = EDITOR_DEF("text_editor/highlighting/comment_color", Color::hex(0x797e7eff));
- Color string_color = EDITOR_DEF("text_editor/highlighting/string_color", Color::hex(0x6b6f00ff));
-
- // Adapt
- if (EditorSettings::get_singleton()->get("text_editor/theme/color_theme") == "Adaptive") {
- Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
-
- symbol_color = tm->get_color("text_editor/theme/symbol_color", "Editor");
- keyword_color = tm->get_color("text_editor/theme/keyword_color", "Editor");
- basetype_color = tm->get_color("text_editor/theme/basetype_color", "Editor");
- type_color = tm->get_color("text_editor/theme/type_color", "Editor");
- comment_color = tm->get_color("text_editor/theme/comment_color", "Editor");
- string_color = tm->get_color("text_editor/theme/string_color", "Editor");
- background_color = tm->get_color("text_editor/theme/background_color", "Editor");
- completion_background_color = tm->get_color("text_editor/theme/completion_background_color", "Editor");
- completion_selected_color = tm->get_color("text_editor/theme/completion_selected_color", "Editor");
- completion_existing_color = tm->get_color("text_editor/theme/completion_existing_color", "Editor");
- completion_scroll_color = tm->get_color("text_editor/theme/completion_scroll_color", "Editor");
- completion_font_color = tm->get_color("text_editor/theme/completion_font_color", "Editor");
- text_color = tm->get_color("text_editor/theme/text_color", "Editor");
- line_number_color = tm->get_color("text_editor/theme/line_number_color", "Editor");
- caret_color = tm->get_color("text_editor/theme/caret_color", "Editor");
- caret_background_color = tm->get_color("text_editor/theme/caret_background_color", "Editor");
- text_selected_color = tm->get_color("text_editor/theme/text_selected_color", "Editor");
- selection_color = tm->get_color("text_editor/theme/selection_color", "Editor");
- brace_mismatch_color = tm->get_color("text_editor/theme/brace_mismatch_color", "Editor");
- current_line_color = tm->get_color("text_editor/theme/current_line_color", "Editor");
- line_length_guideline_color = tm->get_color("text_editor/theme/line_length_guideline_color", "Editor");
- word_highlighted_color = tm->get_color("text_editor/theme/word_highlighted_color", "Editor");
- number_color = tm->get_color("text_editor/theme/number_color", "Editor");
- function_color = tm->get_color("text_editor/theme/function_color", "Editor");
- member_variable_color = tm->get_color("text_editor/theme/member_variable_color", "Editor");
- mark_color = tm->get_color("text_editor/theme/mark_color", "Editor");
- breakpoint_color = tm->get_color("text_editor/theme/breakpoint_color", "Editor");
- code_folding_color = tm->get_color("text_editor/theme/code_folding_color", "Editor");
- search_result_color = tm->get_color("text_editor/theme/search_result_color", "Editor");
- search_result_border_color = tm->get_color("text_editor/theme/search_result_border_color", "Editor");
- }
+ Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
+ Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color");
+ Color completion_selected_color = EDITOR_GET("text_editor/highlighting/completion_selected_color");
+ Color completion_existing_color = EDITOR_GET("text_editor/highlighting/completion_existing_color");
+ Color completion_scroll_color = EDITOR_GET("text_editor/highlighting/completion_scroll_color");
+ Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color");
+ Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
+ Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color");
+ Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color");
+ Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color");
+ Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color");
+ Color selection_color = EDITOR_GET("text_editor/highlighting/selection_color");
+ Color brace_mismatch_color = EDITOR_GET("text_editor/highlighting/brace_mismatch_color");
+ Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color");
+ Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color");
+ Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color");
+ Color number_color = EDITOR_GET("text_editor/highlighting/number_color");
+ Color function_color = EDITOR_GET("text_editor/highlighting/function_color");
+ 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 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");
+ Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
+ Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color");
+ Color type_color = EDITOR_GET("text_editor/highlighting/engine_type_color");
+ Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
+ Color string_color = EDITOR_GET("text_editor/highlighting/string_color");
text_edit->add_color_override("background_color", background_color);
text_edit->add_color_override("completion_background_color", completion_background_color);
@@ -1396,48 +1360,70 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_RIGHT && !mb->is_pressed()) {
+ if (mb->get_button_index() == BUTTON_RIGHT) {
int col, row;
TextEdit *tx = code_editor->get_text_edit();
tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col);
Vector2 mpos = mb->get_global_position() - tx->get_global_position();
- bool have_selection = (tx->get_selection_text().length() > 0);
- bool have_color = (tx->get_word_at_pos(mpos) == "Color");
+
+ tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret"));
+ bool has_color = (tx->get_word_at_pos(mpos) == "Color");
int fold_state = 0;
bool can_fold = tx->can_fold(row);
bool is_folded = tx->is_folded(row);
- if (have_color) {
-
- String line = tx->get_line(row);
- color_line = row;
- int begin = 0;
- int end = 0;
- bool valid = false;
- for (int i = col; i < line.length(); i++) {
- if (line[i] == '(') {
- begin = i;
- continue;
- } else if (line[i] == ')') {
- end = i + 1;
- valid = true;
- break;
+
+ if (tx->is_right_click_moving_caret()) {
+ if (tx->is_selection_active()) {
+
+ int from_line = tx->get_selection_from_line();
+ int to_line = tx->get_selection_to_line();
+ int from_column = tx->get_selection_from_column();
+ int to_column = tx->get_selection_to_column();
+
+ if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) {
+ // Right click is outside the seleted text
+ tx->deselect();
}
}
- if (valid) {
- color_args = line.substr(begin, end - begin);
- String stripped = color_args.replace(" ", "").replace("(", "").replace(")", "");
- Vector<float> color = stripped.split_floats(",");
- if (color.size() > 2) {
- float alpha = color.size() > 3 ? color[3] : 1.0f;
- color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha));
+ if (!tx->is_selection_active()) {
+ tx->cursor_set_line(row, true, false);
+ tx->cursor_set_column(col);
+ }
+ }
+
+ if (!mb->is_pressed()) {
+ if (has_color) {
+ String line = tx->get_line(row);
+ color_line = row;
+ int begin = 0;
+ int end = 0;
+ bool valid = false;
+ for (int i = col; i < line.length(); i++) {
+ if (line[i] == '(') {
+ begin = i;
+ continue;
+ } else if (line[i] == ')') {
+ end = i + 1;
+ valid = true;
+ break;
+ }
+ }
+ if (valid) {
+ color_args = line.substr(begin, end - begin);
+ String stripped = color_args.replace(" ", "").replace("(", "").replace(")", "");
+ Vector<float> color = stripped.split_floats(",");
+ if (color.size() > 2) {
+ float alpha = color.size() > 3 ? color[3] : 1.0f;
+ color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha));
+ }
+ color_panel->set_position(get_global_transform().xform(get_local_mouse_position()));
+ } else {
+ has_color = false;
}
- color_panel->set_position(get_global_transform().xform(get_local_mouse_position()));
- } else {
- have_color = false;
}
+ _make_context_menu(tx->is_selection_active(), has_color, can_fold, is_folded);
}
- _make_context_menu(have_selection, have_color, can_fold, is_folded);
}
}
}
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 3e00776dfd..aa0607dfc0 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -60,73 +60,36 @@ void ShaderTextEditor::_load_theme_settings() {
get_text_edit()->clear_colors();
- Color background_color = EDITOR_DEF("text_editor/highlighting/background_color", Color(0, 0, 0, 0));
- Color completion_background_color = EDITOR_DEF("text_editor/highlighting/completion_background_color", Color(0, 0, 0, 0));
- Color completion_selected_color = EDITOR_DEF("text_editor/highlighting/completion_selected_color", Color::html("434244"));
- Color completion_existing_color = EDITOR_DEF("text_editor/highlighting/completion_existing_color", Color::html("21dfdfdf"));
- Color completion_scroll_color = EDITOR_DEF("text_editor/highlighting/completion_scroll_color", Color::html("ffffff"));
- Color completion_font_color = EDITOR_DEF("text_editor/highlighting/completion_font_color", Color::html("aaaaaa"));
- Color text_color = EDITOR_DEF("text_editor/highlighting/text_color", Color(0, 0, 0));
- Color line_number_color = EDITOR_DEF("text_editor/highlighting/line_number_color", Color(0, 0, 0));
- Color caret_color = EDITOR_DEF("text_editor/highlighting/caret_color", Color(0, 0, 0));
- Color caret_background_color = EDITOR_DEF("text_editor/highlighting/caret_background_color", Color(0, 0, 0));
- Color text_selected_color = EDITOR_DEF("text_editor/highlighting/text_selected_color", Color(1, 1, 1));
- Color selection_color = EDITOR_DEF("text_editor/highlighting/selection_color", Color(0.2, 0.2, 1));
- Color brace_mismatch_color = EDITOR_DEF("text_editor/highlighting/brace_mismatch_color", Color(1, 0.2, 0.2));
- Color current_line_color = EDITOR_DEF("text_editor/highlighting/current_line_color", Color(0.3, 0.5, 0.8, 0.15));
- Color line_length_guideline_color = EDITOR_DEF("text_editor/highlighting/line_length_guideline_color", Color(0, 0, 0));
- Color word_highlighted_color = EDITOR_DEF("text_editor/highlighting/word_highlighted_color", Color(0.8, 0.9, 0.9, 0.15));
- Color number_color = EDITOR_DEF("text_editor/highlighting/number_color", Color(0.9, 0.6, 0.0, 2));
- Color function_color = EDITOR_DEF("text_editor/highlighting/function_color", Color(0.4, 0.6, 0.8));
- Color member_variable_color = EDITOR_DEF("text_editor/highlighting/member_variable_color", Color(0.9, 0.3, 0.3));
- Color mark_color = EDITOR_DEF("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4));
- Color breakpoint_color = EDITOR_DEF("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2));
- Color code_folding_color = EDITOR_DEF("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
- Color search_result_color = EDITOR_DEF("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
- Color search_result_border_color = EDITOR_DEF("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1));
- Color symbol_color = EDITOR_DEF("text_editor/highlighting/symbol_color", Color::hex(0x005291ff));
-
- Color keyword_color = EDITOR_DEF("text_editor/highlighting/keyword_color", Color(0.5, 0.0, 0.2));
- Color basetype_color = EDITOR_DEF("text_editor/highlighting/base_type_color", Color(0.3, 0.3, 0.0));
- Color type_color = EDITOR_DEF("text_editor/highlighting/engine_type_color", Color(0.0, 0.2, 0.4));
- Color comment_color = EDITOR_DEF("text_editor/highlighting/comment_color", Color::hex(0x797e7eff));
- Color string_color = EDITOR_DEF("text_editor/highlighting/string_color", Color::hex(0x6b6f00ff));
-
- // Adapt
- if (EditorSettings::get_singleton()->get("text_editor/theme/color_theme") == "Adaptive") {
- Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
-
- symbol_color = tm->get_color("text_editor/theme/symbol_color", "Editor");
- keyword_color = tm->get_color("text_editor/theme/keyword_color", "Editor");
- basetype_color = tm->get_color("text_editor/theme/basetype_color", "Editor");
- type_color = tm->get_color("text_editor/theme/type_color", "Editor");
- comment_color = tm->get_color("text_editor/theme/comment_color", "Editor");
- string_color = tm->get_color("text_editor/theme/string_color", "Editor");
- background_color = tm->get_color("text_editor/theme/background_color", "Editor");
- completion_background_color = tm->get_color("text_editor/theme/completion_background_color", "Editor");
- completion_selected_color = tm->get_color("text_editor/theme/completion_selected_color", "Editor");
- completion_existing_color = tm->get_color("text_editor/theme/completion_existing_color", "Editor");
- completion_scroll_color = tm->get_color("text_editor/theme/completion_scroll_color", "Editor");
- completion_font_color = tm->get_color("text_editor/theme/completion_font_color", "Editor");
- text_color = tm->get_color("text_editor/theme/text_color", "Editor");
- line_number_color = tm->get_color("text_editor/theme/line_number_color", "Editor");
- caret_color = tm->get_color("text_editor/theme/caret_color", "Editor");
- caret_background_color = tm->get_color("text_editor/theme/caret_background_color", "Editor");
- text_selected_color = tm->get_color("text_editor/theme/text_selected_color", "Editor");
- selection_color = tm->get_color("text_editor/theme/selection_color", "Editor");
- brace_mismatch_color = tm->get_color("text_editor/theme/brace_mismatch_color", "Editor");
- current_line_color = tm->get_color("text_editor/theme/current_line_color", "Editor");
- line_length_guideline_color = tm->get_color("text_editor/theme/line_length_guideline_color", "Editor");
- word_highlighted_color = tm->get_color("text_editor/theme/word_highlighted_color", "Editor");
- number_color = tm->get_color("text_editor/theme/number_color", "Editor");
- function_color = tm->get_color("text_editor/theme/function_color", "Editor");
- member_variable_color = tm->get_color("text_editor/theme/member_variable_color", "Editor");
- mark_color = tm->get_color("text_editor/theme/mark_color", "Editor");
- breakpoint_color = tm->get_color("text_editor/theme/breakpoint_color", "Editor");
- code_folding_color = tm->get_color("text_editor/theme/code_folding_color", "Editor");
- search_result_color = tm->get_color("text_editor/theme/search_result_color", "Editor");
- search_result_border_color = tm->get_color("text_editor/theme/search_result_border_color", "Editor");
- }
+ Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
+ Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color");
+ Color completion_selected_color = EDITOR_GET("text_editor/highlighting/completion_selected_color");
+ Color completion_existing_color = EDITOR_GET("text_editor/highlighting/completion_existing_color");
+ Color completion_scroll_color = EDITOR_GET("text_editor/highlighting/completion_scroll_color");
+ Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color");
+ Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
+ Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color");
+ Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color");
+ Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color");
+ Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color");
+ Color selection_color = EDITOR_GET("text_editor/highlighting/selection_color");
+ Color brace_mismatch_color = EDITOR_GET("text_editor/highlighting/brace_mismatch_color");
+ Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color");
+ Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color");
+ Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color");
+ Color number_color = EDITOR_GET("text_editor/highlighting/number_color");
+ Color function_color = EDITOR_GET("text_editor/highlighting/function_color");
+ 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 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");
+ Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
+ Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color");
+ Color type_color = EDITOR_GET("text_editor/highlighting/engine_type_color");
+ Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
+ Color string_color = EDITOR_GET("text_editor/highlighting/string_color");
get_text_edit()->add_color_override("background_color", background_color);
get_text_edit()->add_color_override("completion_background_color", completion_background_color);
@@ -620,14 +583,36 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_RIGHT && !mb->is_pressed()) {
+ if (mb->get_button_index() == BUTTON_RIGHT) {
int col, row;
TextEdit *tx = shader_editor->get_text_edit();
tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col);
Vector2 mpos = mb->get_global_position() - tx->get_global_position();
- bool have_selection = (tx->get_selection_text().length() > 0);
- _make_context_menu(have_selection);
+ tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret"));
+
+ if (tx->is_right_click_moving_caret()) {
+ if (tx->is_selection_active()) {
+
+ int from_line = tx->get_selection_from_line();
+ int to_line = tx->get_selection_to_line();
+ int from_column = tx->get_selection_from_column();
+ int to_column = tx->get_selection_to_column();
+
+ if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) {
+ // Right click is outside the seleted text
+ tx->deselect();
+ }
+ }
+ if (!tx->is_selection_active()) {
+ tx->cursor_set_line(row, true, false);
+ tx->cursor_set_column(col);
+ }
+ }
+
+ if (!mb->is_pressed()) {
+ _make_context_menu(tx->is_selection_active());
+ }
}
}
}
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 59da5112ae..e0a697ec26 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -51,7 +51,6 @@
#define GIZMO_ARROW_SIZE 0.35
#define GIZMO_RING_HALF_WIDTH 0.1
-//#define GIZMO_SCALE_DEFAULT 0.28
#define GIZMO_SCALE_DEFAULT 0.15
#define GIZMO_PLANE_SIZE 0.2
#define GIZMO_PLANE_DST 0.3
@@ -94,7 +93,6 @@ void SpatialEditorViewport::_update_camera(float p_interp_delta) {
// We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos
camera_cursor.eye_pos = old_camera_cursor.eye_pos.linear_interpolate(cursor.eye_pos, CLAMP(factor, 0, 1));
- //camera_cursor.pos = camera_cursor.eye_pos + (cursor.pos - cursor.eye_pos);
float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
orbit_inertia = MAX(0.0001, orbit_inertia);
@@ -153,13 +151,13 @@ void SpatialEditorViewport::_update_camera(float p_interp_delta) {
if (!equal || p_interp_delta == 0 || is_freelook_active() || is_orthogonal != orthogonal) {
camera->set_global_transform(to_camera_transform(camera_cursor));
- update_transform_gizmo_view();
- if (orthogonal) {
- //camera->set_orthogonal(size.width*cursor.distance,get_znear(),get_zfar());
+ if (orthogonal)
camera->set_orthogonal(2 * cursor.distance, 0.1, 8192);
- } else
+ else
camera->set_perspective(get_fov(), get_znear(), get_zfar());
+
+ update_transform_gizmo_view();
}
}
@@ -392,9 +390,6 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append,
ERR_PRINT("Bug?");
}
}
-
- // if (editor_selection->is_selected(spat))
- // r_includes_current=true;
}
if (!item)
@@ -561,6 +556,8 @@ void SpatialEditorViewport::_update_name() {
view_menu->set_text("[ " + name + " " + ortho + " ]");
else
view_menu->set_text("[ " + ortho + " ]");
+
+ view_menu->set_size(Vector2(0, 0)); // resets the button size
}
void SpatialEditorViewport::_compute_edit(const Point2 &p_point) {
@@ -812,17 +809,27 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig
return false;
}
-void SpatialEditorViewport::_smouseenter() {
+void SpatialEditorViewport::_surface_mouse_enter() {
if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
surface->grab_focus();
}
-void SpatialEditorViewport::_smouseexit() {
+void SpatialEditorViewport::_surface_mouse_exit() {
_remove_preview();
}
+void SpatialEditorViewport::_surface_focus_enter() {
+
+ view_menu->set_disable_shortcuts(false);
+}
+
+void SpatialEditorViewport::_surface_focus_exit() {
+
+ view_menu->set_disable_shortcuts(true);
+}
+
void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
_find_items_at_pos(b->get_position(), clicked_includes_current, selection_results, b->get_shift());
@@ -949,7 +956,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (_edit.mode != TRANSFORM_NONE && b->is_pressed()) {
//cancel motion
_edit.mode = TRANSFORM_NONE;
- //_validate_selection();
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -966,7 +972,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
sp->set_global_transform(se->original);
}
surface->update();
- //VisualServer::get_singleton()->poly_clear(indicators);
set_message(TTR("Transform Aborted."), 3);
}
@@ -1059,7 +1064,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.gizmo = seg;
_edit.gizmo_handle = handle;
- //_edit.gizmo_initial_pos=seg->get_handle_pos(gizmo_handle);
_edit.gizmo_initial_value = seg->get_handle_value(handle);
break;
}
@@ -1134,13 +1138,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.gizmo = seg;
_edit.gizmo_handle = gizmo_handle;
- //_edit.gizmo_initial_pos=seg->get_handle_pos(gizmo_handle);
_edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle);
- //print_line("GIZMO: "+itos(gizmo_handle)+" FROMPOS: "+_edit.orig_gizmo_pos);
break;
}
}
- //_compute_edit(Point2(b.x,b.y)); //in case a motion happens..
}
surface->update();
@@ -1186,7 +1187,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
undo_redo->commit_action();
_edit.mode = TRANSFORM_NONE;
- //VisualServer::get_singleton()->poly_clear(indicators);
set_message("");
}
@@ -1785,51 +1785,36 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) {
- cursor.y_rot = 0;
- cursor.x_rot = -Math_PI / 2.0;
- set_message(TTR("Bottom View."), 2);
- name = TTR("Bottom");
- _update_name();
+ _menu_option(VIEW_BOTTOM);
}
if (ED_IS_SHORTCUT("spatial_editor/top_view", p_event)) {
- cursor.y_rot = 0;
- cursor.x_rot = Math_PI / 2.0;
- set_message(TTR("Top View."), 2);
- name = TTR("Top");
- _update_name();
+ _menu_option(VIEW_TOP);
}
if (ED_IS_SHORTCUT("spatial_editor/rear_view", p_event)) {
- cursor.x_rot = 0;
- cursor.y_rot = Math_PI;
- set_message(TTR("Rear View."), 2);
- name = TTR("Rear");
- _update_name();
+ _menu_option(VIEW_REAR);
}
if (ED_IS_SHORTCUT("spatial_editor/front_view", p_event)) {
- cursor.x_rot = 0;
- cursor.y_rot = 0;
- set_message(TTR("Front View."), 2);
- name = TTR("Front");
- _update_name();
+ _menu_option(VIEW_FRONT);
}
if (ED_IS_SHORTCUT("spatial_editor/left_view", p_event)) {
- cursor.x_rot = 0;
- cursor.y_rot = Math_PI / 2.0;
- set_message(TTR("Left View."), 2);
- name = TTR("Left");
- _update_name();
+ _menu_option(VIEW_LEFT);
}
if (ED_IS_SHORTCUT("spatial_editor/right_view", p_event)) {
- cursor.x_rot = 0;
- cursor.y_rot = -Math_PI / 2.0;
- set_message(TTR("Right View."), 2);
- name = TTR("Right");
- _update_name();
+ _menu_option(VIEW_RIGHT);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/focus_origin", p_event)) {
+ _menu_option(VIEW_CENTER_TO_ORIGIN);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/focus_selection", p_event)) {
+ _menu_option(VIEW_CENTER_TO_SELECTION);
}
if (ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
_menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL);
_update_name();
}
+ if (ED_IS_SHORTCUT("spatial_editor/align_selection_with_view", p_event)) {
+ _menu_option(VIEW_ALIGN_SELECTION_WITH_VIEW);
+ }
if (ED_IS_SHORTCUT("spatial_editor/insert_anim_key", p_event)) {
if (!get_selected_count() || _edit.mode != TRANSFORM_NONE)
return;
@@ -2114,15 +2099,6 @@ void SpatialEditorViewport::_notification(int p_what) {
if (p_what == NOTIFICATION_PROCESS) {
- //force editr camera
- /*
- current_camera=get_root_node()->get_current_camera();
- if (current_camera!=camera) {
-
-
- }
- */
-
real_t delta = get_process_delta_time();
if (zoom_indicator_delay > 0) {
@@ -2248,8 +2224,10 @@ void SpatialEditorViewport::_notification(int p_what) {
surface->connect("draw", this, "_draw");
surface->connect("gui_input", this, "_sinput");
- surface->connect("mouse_entered", this, "_smouseenter");
- surface->connect("mouse_exited", this, "_smouseexit");
+ surface->connect("mouse_entered", this, "_surface_mouse_enter");
+ surface->connect("mouse_exited", this, "_surface_mouse_exit");
+ surface->connect("focus_entered", this, "_surface_focus_enter");
+ surface->connect("focus_exited", this, "_surface_focus_exit");
info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
@@ -2423,47 +2401,54 @@ void SpatialEditorViewport::_menu_option(int p_option) {
case VIEW_TOP: {
- cursor.x_rot = Math_PI / 2.0;
cursor.y_rot = 0;
+ cursor.x_rot = Math_PI / 2.0;
+ set_message(TTR("Top View."), 2);
name = TTR("Top");
_update_name();
+
} break;
case VIEW_BOTTOM: {
- cursor.x_rot = -Math_PI / 2.0;
cursor.y_rot = 0;
+ cursor.x_rot = -Math_PI / 2.0;
+ set_message(TTR("Bottom View."), 2);
name = TTR("Bottom");
_update_name();
} break;
case VIEW_LEFT: {
- cursor.y_rot = Math_PI / 2.0;
cursor.x_rot = 0;
+ cursor.y_rot = Math_PI / 2.0;
+ set_message(TTR("Left View."), 2);
name = TTR("Left");
_update_name();
} break;
case VIEW_RIGHT: {
- cursor.y_rot = -Math_PI / 2.0;
cursor.x_rot = 0;
+ cursor.y_rot = -Math_PI / 2.0;
+ set_message(TTR("Right View."), 2);
name = TTR("Right");
_update_name();
} break;
case VIEW_FRONT: {
- cursor.y_rot = 0;
cursor.x_rot = 0;
+ cursor.y_rot = 0;
+ set_message(TTR("Front View."), 2);
name = TTR("Front");
_update_name();
} break;
case VIEW_REAR: {
- cursor.y_rot = Math_PI;
cursor.x_rot = 0;
+ cursor.y_rot = Math_PI;
+ set_message(TTR("Rear View."), 2);
name = TTR("Rear");
_update_name();
@@ -2590,6 +2575,11 @@ void SpatialEditorViewport::_menu_option(int p_option) {
bool current = view_menu->get_popup()->is_item_checked(idx);
view_menu->get_popup()->set_item_checked(idx, !current);
+ if (current)
+ preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
+ else
+ preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 15 * EDSCALE + fps_label->get_size().height);
+
} break;
case VIEW_DISPLAY_NORMAL: {
@@ -2641,14 +2631,13 @@ void SpatialEditorViewport::_preview_exited_scene() {
void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
- uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx); //|(1<<GIZMO_GRID_LAYER);
+ uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx);
for (int i = 0; i < 3; i++) {
move_gizmo_instance[i] = VS::get_singleton()->instance_create();
VS::get_singleton()->instance_set_base(move_gizmo_instance[i], spatial_editor->get_move_gizmo(i)->get_rid());
VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_visible(move_gizmo_instance[i], false);
- //VS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
VS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer);
@@ -2656,7 +2645,6 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
VS::get_singleton()->instance_set_base(move_plane_gizmo_instance[i], spatial_editor->get_move_plane_gizmo(i)->get_rid());
VS::get_singleton()->instance_set_scenario(move_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false);
- //VS::get_singleton()->instance_geometry_set_flag(move_plane_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
VS::get_singleton()->instance_set_layer_mask(move_plane_gizmo_instance[i], layer);
@@ -2664,7 +2652,6 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
VS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid());
VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
- //VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
@@ -2672,7 +2659,6 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
VS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid());
VS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
- //VS::get_singleton()->instance_geometry_set_flag(scale_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
VS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer);
@@ -2680,7 +2666,6 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
VS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid());
VS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
- //VS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
VS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer);
}
@@ -2745,16 +2730,8 @@ void SpatialEditorViewport::set_can_preview(Camera *p_preview) {
preview = p_preview;
- if (!preview_camera->is_pressed()) {
-
- if (p_preview) {
- fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 15 * EDSCALE + preview_camera->get_size().height);
- preview_camera->show();
- } else {
- fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
- preview_camera->hide();
- }
- }
+ if (!preview_camera->is_pressed())
+ preview_camera->set_visible(p_preview);
}
void SpatialEditorViewport::update_transform_gizmo_view() {
@@ -2781,8 +2758,6 @@ void SpatialEditorViewport::update_transform_gizmo_view() {
xform.basis.scale(scale);
- //xform.basis.scale(GIZMO_SCALE_DEFAULT*Vector3(1,1,1));
-
for (int i = 0; i < 3; i++) {
VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
@@ -2799,18 +2774,36 @@ void SpatialEditorViewport::update_transform_gizmo_view() {
void SpatialEditorViewport::set_state(const Dictionary &p_state) {
- cursor.pos = p_state["position"];
- cursor.x_rot = p_state["x_rotation"];
- cursor.y_rot = p_state["y_rotation"];
- cursor.distance = p_state["distance"];
- bool env = p_state["use_environment"];
- bool orth = p_state["use_orthogonal"];
- if (orth)
- _menu_option(VIEW_ORTHOGONAL);
- else
- _menu_option(VIEW_PERSPECTIVE);
- if (env != camera->get_environment().is_valid())
- _menu_option(VIEW_ENVIRONMENT);
+ if (p_state.has("position"))
+ cursor.pos = p_state["position"];
+ if (p_state.has("x_rotation"))
+ cursor.x_rot = p_state["x_rotation"];
+ if (p_state.has("y_rotation"))
+ cursor.y_rot = p_state["y_rotation"];
+ if (p_state.has("distance"))
+ cursor.distance = p_state["distance"];
+
+ if (p_state.has("use_orthogonal")) {
+ bool orth = p_state["use_orthogonal"];
+
+ if (orth)
+ _menu_option(VIEW_ORTHOGONAL);
+ else
+ _menu_option(VIEW_PERSPECTIVE);
+ }
+ if (p_state.has("display_mode")) {
+ int display = p_state["display_mode"];
+
+ int idx = view_menu->get_popup()->get_item_index(display);
+ if (!view_menu->get_popup()->is_item_checked(idx))
+ _menu_option(display);
+ }
+ if (p_state.has("use_environment")) {
+ bool env = p_state["use_environment"];
+
+ if (env != camera->get_environment().is_valid())
+ _menu_option(VIEW_ENVIRONMENT);
+ }
if (p_state.has("listener")) {
bool listener = p_state["listener"];
@@ -2839,6 +2832,13 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) {
if (view_menu->get_popup()->is_item_checked(idx) != information)
_menu_option(VIEW_INFORMATION);
}
+ if (p_state.has("fps")) {
+ bool fps = p_state["fps"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
+ if (view_menu->get_popup()->is_item_checked(idx) != fps)
+ _menu_option(VIEW_FPS);
+ }
if (p_state.has("half_res")) {
bool half_res = p_state["half_res"];
@@ -2869,14 +2869,22 @@ Dictionary SpatialEditorViewport::get_state() const {
d["distance"] = cursor.distance;
d["use_environment"] = camera->get_environment().is_valid();
d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
+ if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL)))
+ d["display_mode"] = VIEW_DISPLAY_NORMAL;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME)))
+ d["display_mode"] = VIEW_DISPLAY_WIREFRAME;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW)))
+ d["display_mode"] = VIEW_DISPLAY_OVERDRAW;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS)))
+ d["display_mode"] = VIEW_DISPLAY_SHADELESS;
d["listener"] = viewport->is_audio_listener();
d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
+ d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
d["half_res"] = viewport_container->get_stretch_shrink() > 1;
- if (previewing) {
+ if (previewing)
d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
- }
return d;
}
@@ -2884,8 +2892,11 @@ Dictionary SpatialEditorViewport::get_state() const {
void SpatialEditorViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("_draw"), &SpatialEditorViewport::_draw);
- ClassDB::bind_method(D_METHOD("_smouseenter"), &SpatialEditorViewport::_smouseenter);
- ClassDB::bind_method(D_METHOD("_smouseexit"), &SpatialEditorViewport::_smouseexit);
+
+ ClassDB::bind_method(D_METHOD("_surface_mouse_enter"), &SpatialEditorViewport::_surface_mouse_enter);
+ ClassDB::bind_method(D_METHOD("_surface_mouse_exit"), &SpatialEditorViewport::_surface_mouse_exit);
+ ClassDB::bind_method(D_METHOD("_surface_focus_enter"), &SpatialEditorViewport::_surface_focus_enter);
+ ClassDB::bind_method(D_METHOD("_surface_focus_exit"), &SpatialEditorViewport::_surface_focus_exit);
ClassDB::bind_method(D_METHOD("_sinput"), &SpatialEditorViewport::_sinput);
ClassDB::bind_method(D_METHOD("_menu_option"), &SpatialEditorViewport::_menu_option);
ClassDB::bind_method(D_METHOD("_toggle_camera_preview"), &SpatialEditorViewport::_toggle_camera_preview);
@@ -3202,7 +3213,7 @@ bool SpatialEditorViewport::can_drop_data_fw(const Point2 &p_point, const Varian
continue;
}
memdelete(instanced_scene);
- } else if (type == "Mesh" || "ArrayMesh" || "PrimitiveMesh") {
+ } else if (type == "Mesh" || type == "ArrayMesh" || type == "PrimitiveMesh") {
Ref<Mesh> mesh = ResourceLoader::load(files[i]);
if (!mesh.is_valid()) {
continue;
@@ -3309,7 +3320,6 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
camera = memnew(Camera);
camera->set_disable_gizmo(true);
camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + p_index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
- //camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment());
viewport->add_child(camera);
camera->make_current();
surface->set_focus_mode(FOCUS_ALL);
@@ -3353,6 +3363,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_selection_with_view"), VIEW_ALIGN_SELECTION_WITH_VIEW);
view_menu->get_popup()->connect("id_pressed", this, "_menu_option");
+ view_menu->set_disable_shortcuts(true);
+
ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A);
ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D);
ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W);
@@ -3367,7 +3379,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
preview_camera->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
preview_camera->set_h_grow_direction(GROW_DIRECTION_BEGIN);
- preview_camera->set_text(TTR("preview"));
+ preview_camera->set_text(TTR("Preview"));
surface->add_child(preview_camera);
preview_camera->hide();
preview_camera->connect("toggled", this, "_toggle_camera_preview");
@@ -3771,7 +3783,6 @@ void SpatialEditor::update_transform_gizmo() {
center.expand_to(xf.origin);
gizmo_basis = Basis();
}
- //count++;
}
Vector3 pcenter = center.position + center.size * 0.5;
@@ -3994,17 +4005,6 @@ void SpatialEditor::edit(Spatial *p_spatial) {
}
}
}
-
- /*
- if (p_spatial) {
- _validate_selection();
- if (selected.has(p_spatial->get_instance_id()) && selected.size()==1)
- return;
- _select(p_spatial->get_instance_id(),false,true);
-
- // should become the selection
- }
- */
}
void SpatialEditor::_xform_dialog_action() {
@@ -4348,9 +4348,6 @@ void SpatialEditor::_init_indicators() {
VisualServer::get_singleton()->mesh_add_surface_from_arrays(origin, VisualServer::PRIMITIVE_LINES, d);
VisualServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid());
- //origin = VisualServer::get_singleton()->poly_create();
- //VisualServer::get_singleton()->poly_add_primitive(origin,origin_points,Vector<Vector3>(),origin_colors,Vector<Vector3>());
- //VisualServer::get_singleton()->poly_set_material(origin,indicator_mat,true);
origin_instance = VisualServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world()->get_scenario());
VS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
@@ -4635,9 +4632,6 @@ void SpatialEditor::_finish_indicators() {
VisualServer::get_singleton()->free(grid_instance[i]);
VisualServer::get_singleton()->free(grid[i]);
}
- //VisualServer::get_singleton()->free(poly);
- //VisualServer::get_singleton()->free(indicators_instance);
- //VisualServer::get_singleton()->free(indicators);
}
bool SpatialEditor::is_any_freelook_active() const {
@@ -4879,7 +4873,6 @@ void SpatialEditor::_node_removed(Node *p_node) {
void SpatialEditor::_bind_methods() {
- //ClassDB::bind_method("_gui_input",&SpatialEditor::_gui_input);
ClassDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input);
ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed);
ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed);
@@ -4940,8 +4933,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
snap_enabled = false;
tool_mode = TOOL_MODE_SELECT;
- //set_focus_mode(FOCUS_ALL);
-
hbc_menu = memnew(HBoxContainer);
vbc->add_child(hbc_menu);
@@ -5116,7 +5107,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
viewport_base->add_child(viewports[i]);
}
- //vbc->add_child(viewport_base);
/* SNAP DIALOG */
@@ -5126,7 +5116,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer);
snap_dialog->add_child(snap_dialog_vbc);
- //snap_dialog->set_child_rect(snap_dialog_vbc);
snap_translate = memnew(LineEdit);
snap_translate->set_text("1");
@@ -5148,7 +5137,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
settings_vbc = memnew(VBoxContainer);
settings_vbc->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
settings_dialog->add_child(settings_vbc);
- //settings_dialog->set_child_rect(settings_vbc);
settings_fov = memnew(SpinBox);
settings_fov->set_max(MAX_FOV);
@@ -5171,7 +5159,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500));
settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
- //settings_dialog->get_cancel()->hide();
/* XFORM DIALOG */
xform_dialog = memnew(ConfirmationDialog);
@@ -5257,14 +5244,12 @@ void SpatialEditorPlugin::make_visible(bool p_visible) {
spatial_editor->show();
spatial_editor->set_process(true);
- //VisualServer::get_singleton()->viewport_set_hide_scenario(editor->get_scene_root()->get_viewport(),false);
spatial_editor->grab_focus();
} else {
spatial_editor->hide();
spatial_editor->set_process(false);
- //VisualServer::get_singleton()->viewport_set_hide_scenario(editor->get_scene_root()->get_viewport(),true);
}
}
void SpatialEditorPlugin::edit(Object *p_object) {
@@ -5317,11 +5302,8 @@ SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) {
spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
editor->get_viewport()->add_child(spatial_editor);
- //spatial_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE);
spatial_editor->hide();
spatial_editor->connect("transform_key_request", editor, "_transform_keyed");
-
- //spatial_editor->set_process(true);
}
SpatialEditorPlugin::~SpatialEditorPlugin() {
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index 4aa1d9c0c1..d080745dc9 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -273,8 +273,11 @@ private:
Transform to_camera_transform(const Cursor &p_cursor) const;
void _draw();
- void _smouseenter();
- void _smouseexit();
+ void _surface_mouse_enter();
+ void _surface_mouse_exit();
+ void _surface_focus_enter();
+ void _surface_focus_exit();
+
void _sinput(const Ref<InputEvent> &p_event);
void _update_freelook(real_t delta);
SpatialEditor *spatial_editor;
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 175655119f..71c81f7111 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -840,7 +840,7 @@ SpriteFramesEditorPlugin::SpriteFramesEditorPlugin(EditorNode *p_node) {
editor = p_node;
frames_editor = memnew(SpriteFramesEditor);
frames_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
- button = editor->add_bottom_panel_item("SpriteFrames", frames_editor);
+ button = editor->add_bottom_panel_item(TTR("SpriteFrames"), frames_editor);
button->hide();
}
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index 5c965e4a05..9840d9021c 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -103,6 +103,6 @@ StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) {
stylebox_editor->set_custom_minimum_size(Size2(0, 250));
//p_node->get_viewport()->add_child(stylebox_editor);
- button = p_node->add_bottom_panel_item("StyleBox", stylebox_editor);
+ button = p_node->add_bottom_panel_item(TTR("StyleBox"), stylebox_editor);
button->hide();
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 7f956b01ff..38a4bfbfc6 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -934,6 +934,6 @@ ThemeEditorPlugin::ThemeEditorPlugin(EditorNode *p_node) {
theme_editor->set_custom_minimum_size(Size2(0, 200));
//p_node->get_viewport()->add_child(theme_editor);
- button = editor->add_bottom_panel_item("Theme", theme_editor);
+ button = editor->add_bottom_panel_item(TTR("Theme"), theme_editor);
button->hide();
}
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 5eb3435e24..a8e4d73cd2 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -314,7 +314,7 @@ TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) {
autotile_editor->side_panel->set_anchors_and_margins_preset(Control::PRESET_WIDE);
autotile_editor->side_panel->set_custom_minimum_size(Size2(200, 0));
autotile_editor->side_panel->hide();
- autotile_button = p_node->add_bottom_panel_item("Autotiles", autotile_editor);
+ autotile_button = p_node->add_bottom_panel_item(TTR("Autotiles"), autotile_editor);
autotile_button->hide();
}
@@ -343,12 +343,13 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) {
split->add_child(property_editor);
helper = memnew(AutotileEditorHelper(this));
- property_editor->call_deferred("edit", helper);
+ property_editor->edit(helper);
// Editor
dragging_point = -1;
creating_shape = false;
+ snap_step = Vector2(32, 32);
set_custom_minimum_size(Size2(0, 150));
@@ -387,7 +388,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) {
tools[TOOL_SELECT] = memnew(ToolButton);
tool_containers[TOOLBAR_DUMMY]->add_child(tools[TOOL_SELECT]);
- tools[TOOL_SELECT]->set_tooltip("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.");
+ tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings."));
tools[TOOL_SELECT]->set_toggle_mode(true);
tools[TOOL_SELECT]->set_button_group(tg);
tools[TOOL_SELECT]->set_pressed(true);
@@ -426,10 +427,78 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) {
tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true);
tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true);
tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_KEEP_INSIDE_TILE]);
- tools[SHAPE_SNAP_TO_BITMASK_GRID] = memnew(ToolButton);
- tools[SHAPE_SNAP_TO_BITMASK_GRID]->set_toggle_mode(true);
- tools[SHAPE_SNAP_TO_BITMASK_GRID]->set_pressed(true);
- tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_SNAP_TO_BITMASK_GRID]);
+ tools[SHAPE_GRID_SNAP] = memnew(ToolButton);
+ tools[SHAPE_GRID_SNAP]->set_toggle_mode(true);
+ tools[SHAPE_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled");
+ tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_GRID_SNAP]);
+
+ hb_grid = memnew(HBoxContainer);
+ tool_containers[TOOLBAR_SHAPE]->add_child(hb_grid);
+
+ hb_grid->add_child(memnew(VSeparator));
+ hb_grid->add_child(memnew(Label(TTR("Offset:"))));
+
+ sb_off_x = memnew(SpinBox);
+ sb_off_x->set_min(-256);
+ sb_off_x->set_max(256);
+ sb_off_x->set_step(1);
+ sb_off_x->set_value(snap_offset.x);
+ sb_off_x->set_suffix("px");
+ sb_off_x->connect("value_changed", this, "_set_snap_off_x");
+ hb_grid->add_child(sb_off_x);
+
+ sb_off_y = memnew(SpinBox);
+ sb_off_y->set_min(-256);
+ sb_off_y->set_max(256);
+ sb_off_y->set_step(1);
+ sb_off_y->set_value(snap_offset.y);
+ sb_off_y->set_suffix("px");
+ sb_off_y->connect("value_changed", this, "_set_snap_off_y");
+ hb_grid->add_child(sb_off_y);
+
+ hb_grid->add_child(memnew(VSeparator));
+ hb_grid->add_child(memnew(Label(TTR("Step:"))));
+
+ sb_step_x = memnew(SpinBox);
+ sb_step_x->set_min(-256);
+ sb_step_x->set_max(256);
+ sb_step_x->set_step(1);
+ sb_step_x->set_value(snap_step.x);
+ sb_step_x->set_suffix("px");
+ sb_step_x->connect("value_changed", this, "_set_snap_step_x");
+ hb_grid->add_child(sb_step_x);
+
+ sb_step_y = memnew(SpinBox);
+ sb_step_y->set_min(-256);
+ sb_step_y->set_max(256);
+ sb_step_y->set_step(1);
+ sb_step_y->set_value(snap_step.y);
+ sb_step_y->set_suffix("px");
+ sb_step_y->connect("value_changed", this, "_set_snap_step_y");
+ hb_grid->add_child(sb_step_y);
+
+ hb_grid->add_child(memnew(VSeparator));
+ hb_grid->add_child(memnew(Label(TTR("Separation:"))));
+
+ sb_sep_x = memnew(SpinBox);
+ sb_sep_x->set_min(0);
+ sb_sep_x->set_max(256);
+ sb_sep_x->set_step(1);
+ sb_sep_x->set_value(snap_separation.x);
+ sb_sep_x->set_suffix("px");
+ sb_sep_x->connect("value_changed", this, "_set_snap_sep_x");
+ hb_grid->add_child(sb_sep_x);
+
+ sb_sep_y = memnew(SpinBox);
+ sb_sep_y->set_min(0);
+ sb_sep_y->set_max(256);
+ sb_sep_y->set_step(1);
+ sb_sep_y->set_value(snap_separation.y);
+ sb_sep_y->set_suffix("px");
+ sb_sep_y->connect("value_changed", this, "_set_snap_sep_y");
+ hb_grid->add_child(sb_sep_y);
+
+ hb_grid->hide();
spin_priority = memnew(SpinBox);
spin_priority->set_min(1);
@@ -489,6 +558,13 @@ void AutotileEditor::_bind_methods() {
ClassDB::bind_method("_on_workspace_input", &AutotileEditor::_on_workspace_input);
ClassDB::bind_method("_on_tool_clicked", &AutotileEditor::_on_tool_clicked);
ClassDB::bind_method("_on_priority_changed", &AutotileEditor::_on_priority_changed);
+ ClassDB::bind_method("_on_grid_snap_toggled", &AutotileEditor::_on_grid_snap_toggled);
+ ClassDB::bind_method("_set_snap_step_x", &AutotileEditor::_set_snap_step_x);
+ ClassDB::bind_method("_set_snap_step_y", &AutotileEditor::_set_snap_step_y);
+ ClassDB::bind_method("_set_snap_off_x", &AutotileEditor::_set_snap_off_x);
+ ClassDB::bind_method("_set_snap_off_y", &AutotileEditor::_set_snap_off_y);
+ ClassDB::bind_method("_set_snap_sep_x", &AutotileEditor::_set_snap_sep_x);
+ ClassDB::bind_method("_set_snap_sep_y", &AutotileEditor::_set_snap_sep_y);
}
void AutotileEditor::_notification(int p_what) {
@@ -501,7 +577,7 @@ void AutotileEditor::_notification(int p_what) {
tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons"));
tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons"));
tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons"));
- tools[SHAPE_SNAP_TO_BITMASK_GRID]->set_icon(get_icon("SnapGrid", "EditorIcons"));
+ tools[SHAPE_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons"));
tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons"));
tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons"));
tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons"));
@@ -533,7 +609,7 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) {
tool_containers[TOOLBAR_BITMASK]->show();
tool_containers[TOOLBAR_SHAPE]->hide();
tools[TOOL_SELECT]->set_pressed(true);
- tools[TOOL_SELECT]->set_tooltip("LMB: set bit on.\nRMB: set bit off.");
+ tools[TOOL_SELECT]->set_tooltip(TTR("LMB: set bit on.\nRMB: set bit off."));
spin_priority->hide();
} break;
case EDITMODE_COLLISION:
@@ -542,7 +618,7 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) {
tool_containers[TOOLBAR_DUMMY]->show();
tool_containers[TOOLBAR_BITMASK]->hide();
tool_containers[TOOLBAR_SHAPE]->show();
- tools[TOOL_SELECT]->set_tooltip("Select current edited sub-tile.");
+ tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile."));
spin_priority->hide();
} break;
default: {
@@ -550,10 +626,10 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) {
tool_containers[TOOLBAR_BITMASK]->hide();
tool_containers[TOOLBAR_SHAPE]->hide();
if (edit_mode == EDITMODE_ICON) {
- tools[TOOL_SELECT]->set_tooltip("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.");
+ tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings."));
spin_priority->hide();
} else {
- tools[TOOL_SELECT]->set_tooltip("Select sub-tile to change it's priority.");
+ tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change it's priority."));
spin_priority->show();
}
} break;
@@ -632,6 +708,7 @@ void AutotileEditor::_on_workspace_draw() {
Vector2 coord = edited_shape_coord;
draw_highlight_tile(coord);
draw_polygon_shapes();
+ draw_grid_snap();
} break;
case EDITMODE_PRIORITY: {
spin_priority->set_value(tile_set->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord));
@@ -880,15 +957,15 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(get_current_tile());
for (int i = 0; i < sd.size(); i++) {
if (sd[i].autotile_coord == coord) {
- Ref<ConcavePolygonShape2D> shape = sd[i].shape;
+ Ref<ConvexPolygonShape2D> shape = sd[i].shape;
if (shape.is_valid()) {
- //FIXME: i need a way to know if the point is countained on the polygon instead of the rect
+
Rect2 bounding_rect;
PoolVector2Array polygon;
- bounding_rect.position = shape->get_segments()[0];
- for (int j = 0; j < shape->get_segments().size(); j += 2) {
- polygon.push_back(shape->get_segments()[j] + shape_anchor);
- bounding_rect.expand_to(shape->get_segments()[j] + shape_anchor);
+ bounding_rect.position = shape->get_points()[0];
+ for (int j = 0; j < shape->get_points().size(); j++) {
+ polygon.push_back(shape->get_points()[j] + shape_anchor);
+ bounding_rect.expand_to(shape->get_points()[j] + shape_anchor);
}
if (bounding_rect.has_point(mb->get_position())) {
current_shape = polygon;
@@ -905,17 +982,17 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if (dragging_point >= 0) {
dragging_point = -1;
- PoolVector<Vector2> segments;
- segments.resize(current_shape.size() * 2);
- PoolVector<Vector2>::Write w = segments.write();
+ Vector<Vector2> points;
for (int i = 0; i < current_shape.size(); i++) {
- w[(i << 1) + 0] = current_shape[i] - shape_anchor;
- w[(i << 1) + 1] = current_shape[(i + 1) % current_shape.size()] - shape_anchor;
+ Vector2 p = current_shape[i];
+ if (tools[SHAPE_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) {
+ p = snap_point(p);
+ }
+ points.push_back(p - shape_anchor);
}
- w = PoolVector<Vector2>::Write();
- edited_collision_shape->set_segments(segments);
+ edited_collision_shape->set_points(points);
workspace->update();
}
@@ -982,11 +1059,30 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
current_shape.push_back(pos);
workspace->update();
} else {
+ int t_id = get_current_tile();
+ if (t_id >= 0) {
+ Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(t_id);
+ for (int i = 0; i < sd.size(); i++) {
+ if (sd[i].autotile_coord == edited_shape_coord) {
+ Ref<ConvexPolygonShape2D> shape = sd[i].shape;
+
+ if (!shape.is_null()) {
+ sd.remove(i);
+ tile_set->tile_set_shapes(get_current_tile(), sd);
+ edited_collision_shape = Ref<Shape2D>();
+ current_shape.resize(0);
+ workspace->update();
+ }
+ break;
+ }
+ }
+ }
+
creating_shape = true;
current_shape.resize(0);
current_shape.push_back(snap_point(pos));
}
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) {
if (creating_shape) {
close_shape(shape_anchor);
}
@@ -1034,7 +1130,7 @@ void AutotileEditor::_on_tool_clicked(int p_tool) {
if (index >= 0) {
sd.remove(index);
tile_set->tile_set_shapes(get_current_tile(), sd);
- edited_collision_shape = Ref<ConcavePolygonShape2D>();
+ edited_collision_shape = Ref<Shape2D>();
current_shape.resize(0);
workspace->update();
}
@@ -1081,6 +1177,43 @@ void AutotileEditor::_on_priority_changed(float val) {
workspace->update();
}
+void AutotileEditor::_on_grid_snap_toggled(bool p_val) {
+ if (p_val)
+ hb_grid->show();
+ else
+ hb_grid->hide();
+ workspace->update();
+}
+
+void AutotileEditor::_set_snap_step_x(float p_val) {
+ snap_step.x = p_val;
+ workspace->update();
+}
+
+void AutotileEditor::_set_snap_step_y(float p_val) {
+ snap_step.y = p_val;
+ workspace->update();
+}
+
+void AutotileEditor::_set_snap_off_x(float p_val) {
+ snap_offset.x = p_val;
+ workspace->update();
+}
+
+void AutotileEditor::_set_snap_off_y(float p_val) {
+ snap_offset.y = p_val;
+ workspace->update();
+}
+void AutotileEditor::_set_snap_sep_x(float p_val) {
+ snap_separation.x = p_val;
+ workspace->update();
+}
+
+void AutotileEditor::_set_snap_sep_y(float p_val) {
+ snap_separation.y = p_val;
+ workspace->update();
+}
+
void AutotileEditor::draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted) {
Vector2 size = tile_set->autotile_get_size(get_current_tile());
@@ -1103,6 +1236,49 @@ void AutotileEditor::draw_highlight_tile(Vector2 coord, const Vector<Vector2> &o
}
}
+void AutotileEditor::draw_grid_snap() {
+ if (tools[SHAPE_GRID_SNAP]->is_pressed()) {
+ Color grid_color = Color(0.39, 0, 1, 0.2f);
+ Size2 s = workspace->get_size();
+
+ Vector2 size = tile_set->autotile_get_size(get_current_tile());
+
+ int width_count = (int)(s.width / (snap_step.x + snap_separation.x));
+ int height_count = (int)(s.height / (snap_step.y + snap_separation.y));
+
+ if (snap_step.x != 0) {
+ int last_p = 0;
+ for (int i = 0; i <= width_count; i++) {
+ if (i == 0 && snap_offset.x != 0) {
+ last_p = snap_offset.x;
+ }
+ if (snap_separation.x != 0 && i != 0) {
+ workspace->draw_rect(Rect2(last_p, 0, snap_separation.x, s.height), grid_color);
+ last_p += snap_separation.x;
+ } else
+ workspace->draw_line(Point2(last_p, 0), Point2(last_p, s.height), grid_color);
+
+ last_p += snap_step.x;
+ }
+ }
+
+ if (snap_step.y != 0) {
+ int last_p = 0;
+ for (int i = 0; i <= height_count; i++) {
+ if (i == 0 && snap_offset.y != 0) {
+ last_p = snap_offset.y;
+ }
+ if (snap_separation.x != 0 && i != 0) {
+ workspace->draw_rect(Rect2(0, last_p, s.width, snap_separation.y), grid_color);
+ last_p += snap_separation.y;
+ } else
+ workspace->draw_line(Point2(0, last_p), Point2(s.width, last_p), grid_color);
+ last_p += snap_step.y;
+ }
+ }
+ }
+}
+
void AutotileEditor::draw_polygon_shapes() {
int t_id = get_current_tile();
@@ -1119,7 +1295,7 @@ void AutotileEditor::draw_polygon_shapes() {
anchor.y += tile_set->autotile_get_spacing(t_id);
anchor.x *= coord.x;
anchor.y *= coord.y;
- Ref<ConcavePolygonShape2D> shape = sd[i].shape;
+ Ref<ConvexPolygonShape2D> shape = sd[i].shape;
if (shape.is_valid()) {
Color c_bg;
Color c_border;
@@ -1138,19 +1314,22 @@ void AutotileEditor::draw_polygon_shapes() {
colors.push_back(c_bg);
}
} else {
- for (int j = 0; j < shape->get_segments().size(); j += 2) {
- polygon.push_back(shape->get_segments()[j] + anchor);
+ for (int j = 0; j < shape->get_points().size(); j++) {
+ polygon.push_back(shape->get_points()[j] + anchor);
colors.push_back(c_bg);
}
}
- workspace->draw_polygon(polygon, colors);
+ if (polygon.size() > 2) {
+ workspace->draw_polygon(polygon, colors);
+ }
if (coord == edited_shape_coord) {
- for (int j = 0; j < shape->get_segments().size(); j += 2) {
- workspace->draw_line(shape->get_segments()[j] + anchor, shape->get_segments()[j + 1] + anchor, c_border, 1, true);
+ for (int j = 0; j < shape->get_points().size() - 1; j++) {
+ workspace->draw_line(shape->get_points()[j] + anchor, shape->get_points()[j + 1] + anchor, c_border, 1, true);
}
+
if (shape == edited_collision_shape) {
for (int j = 0; j < current_shape.size(); j++) {
- workspace->draw_circle(current_shape[j], 5, Color(1, 0, 0));
+ workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0, 0.7f));
}
}
}
@@ -1198,7 +1377,7 @@ void AutotileEditor::draw_polygon_shapes() {
workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1] + anchor, shape->get_polygon()[0] + anchor, c_border, 1, true);
if (shape == edited_occlusion_shape) {
for (int j = 0; j < current_shape.size(); j++) {
- workspace->draw_circle(current_shape[j], 5, Color(1, 0, 0));
+ workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0));
}
}
}
@@ -1248,7 +1427,7 @@ void AutotileEditor::draw_polygon_shapes() {
}
if (shape == edited_navigation_shape) {
for (int j = 0; j < current_shape.size(); j++) {
- workspace->draw_circle(current_shape[j], 5, Color(1, 0, 0));
+ workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0));
}
}
}
@@ -1270,22 +1449,21 @@ void AutotileEditor::close_shape(const Vector2 &shape_anchor) {
creating_shape = false;
if (edit_mode == EDITMODE_COLLISION) {
- Ref<ConcavePolygonShape2D> shape = memnew(ConcavePolygonShape2D);
+ if (current_shape.size() >= 3) {
+ Ref<ConvexPolygonShape2D> shape = memnew(ConvexPolygonShape2D);
- PoolVector<Vector2> segments;
- segments.resize(current_shape.size() * 2);
- PoolVector<Vector2>::Write w = segments.write();
+ Vector<Vector2> segments;
- for (int i = 0; i < current_shape.size(); i++) {
- w[(i << 1) + 0] = current_shape[i] - shape_anchor;
- w[(i << 1) + 1] = current_shape[(i + 1) % current_shape.size()] - shape_anchor;
- }
+ for (int i = 0; i < current_shape.size(); i++) {
+ segments.push_back(current_shape[i] - shape_anchor);
+ }
- w = PoolVector<Vector2>::Write();
- shape->set_segments(segments);
+ shape->set_points(segments);
+
+ tile_set->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord);
+ edited_collision_shape = shape;
+ }
- tile_set->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord);
- edited_collision_shape = shape;
tools[TOOL_SELECT]->set_pressed(true);
workspace->update();
} else if (edit_mode == EDITMODE_OCCLUSION) {
@@ -1338,6 +1516,10 @@ Vector2 AutotileEditor::snap_point(const Vector2 &point) {
anchor.x *= (tile_size.x + spacing);
anchor.y *= (tile_size.y + spacing);
Rect2 region(anchor, tile_size);
+ if (tools[SHAPE_GRID_SNAP]->is_pressed()) {
+ p.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p.x, snap_separation.x);
+ p.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p.y, snap_separation.y);
+ }
if (tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) {
if (p.x < region.position.x)
p.x = region.position.x;
@@ -1348,23 +1530,6 @@ Vector2 AutotileEditor::snap_point(const Vector2 &point) {
if (p.y > region.position.y + region.size.y)
p.y = region.position.y + region.size.y;
}
- if (tools[SHAPE_SNAP_TO_BITMASK_GRID]->is_pressed()) {
- Vector2 p2 = p;
- if (tile_set->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
- p2.x = Math::stepify(p2.x, tile_size.x / 2);
- p2.y = Math::stepify(p2.y, tile_size.y / 2);
- if ((p2 - p).length_squared() <= MAX(tile_size.y / 4, MIN_DISTANCE_SQUARED)) {
- p = p2;
- }
- } else if (tile_set->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) {
- p2.x = Math::stepify(p2.x, tile_size.x / 3);
- p2.y = Math::stepify(p2.y, tile_size.y / 3);
- if ((p2 - p).length_squared() <= MAX(tile_size.y / 6, MIN_DISTANCE_SQUARED)) {
- p = p2;
- }
- }
- }
- p.floor();
return p;
}
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index d60d0d5c3c..34284cb90f 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -33,7 +33,7 @@
#include "editor/editor_name_dialog.h"
#include "editor/editor_node.h"
#include "scene/2d/sprite.h"
-#include "scene/resources/concave_polygon_shape_2d.h"
+#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/tile_set.h"
class AutotileEditorHelper;
@@ -70,7 +70,7 @@ class AutotileEditor : public Control {
SHAPE_CREATE_FROM_BITMASK,
SHAPE_CREATE_FROM_NOT_BITMASK,
SHAPE_KEEP_INSIDE_TILE,
- SHAPE_SNAP_TO_BITMASK_GRID,
+ SHAPE_GRID_SNAP,
ZOOM_OUT,
ZOOM_1,
ZOOM_IN,
@@ -78,7 +78,7 @@ class AutotileEditor : public Control {
};
Ref<TileSet> tile_set;
- Ref<ConcavePolygonShape2D> edited_collision_shape;
+ Ref<ConvexPolygonShape2D> edited_collision_shape;
Ref<OccluderPolygon2D> edited_occlusion_shape;
Ref<NavigationPolygon> edited_navigation_shape;
@@ -91,10 +91,21 @@ class AutotileEditor : public Control {
Button *tool_editmode[EDITMODE_MAX];
HBoxContainer *tool_containers[TOOLBAR_MAX];
HBoxContainer *toolbar;
+ HBoxContainer *hb_grid;
ToolButton *tools[TOOL_MAX];
SpinBox *spin_priority;
+ SpinBox *sb_step_y;
+ SpinBox *sb_step_x;
+ SpinBox *sb_off_y;
+ SpinBox *sb_off_x;
+ SpinBox *sb_sep_y;
+ SpinBox *sb_sep_x;
EditMode edit_mode;
+ Vector2 snap_step;
+ Vector2 snap_offset;
+ Vector2 snap_separation;
+
bool creating_shape;
int dragging_point;
Vector2 edited_shape_coord;
@@ -119,9 +130,16 @@ private:
void _on_workspace_input(const Ref<InputEvent> &p_ie);
void _on_tool_clicked(int p_tool);
void _on_priority_changed(float val);
+ void _on_grid_snap_toggled(bool p_val);
+ void _set_snap_step_x(float p_val);
+ void _set_snap_step_y(float p_val);
+ void _set_snap_off_x(float p_val);
+ void _set_snap_off_y(float p_val);
+ void _set_snap_sep_x(float p_val);
+ void _set_snap_sep_y(float p_val);
void draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>());
- void draw_grid(const Vector2 &size, int spacing);
+ void draw_grid_snap();
void draw_polygon_shapes();
void close_shape(const Vector2 &shape_anchor);
Vector2 snap_point(const Vector2 &point);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 00488a2a88..04e9f0adc1 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -536,21 +536,21 @@ public:
if (mode == MODE_IMPORT) {
set_title(TTR("Import Existing Project"));
- get_ok()->set_text(TTR("Import"));
+ get_ok()->set_text(TTR("Import & Edit"));
name_container->hide();
project_path->grab_focus();
} else if (mode == MODE_NEW) {
set_title(TTR("Create New Project"));
- get_ok()->set_text(TTR("Create"));
+ get_ok()->set_text(TTR("Create & Edit"));
name_container->show();
project_name->grab_focus();
} else if (mode == MODE_INSTALL) {
set_title(TTR("Install Project:") + " " + zip_title);
- get_ok()->set_text(TTR("Install"));
+ get_ok()->set_text(TTR("Install & Edit"));
name_container->hide();
project_path->grab_focus();
}
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 6f8573cd70..e69577489e 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -1460,7 +1460,6 @@ void ProjectSettingsEditor::_update_translations() {
t2->set_editable(1, true);
t2->set_metadata(1, path);
int idx = langs.find(locale);
- //print_line("find " + locale + " at " + itos(idx));
if (idx < 0)
idx = 0;
@@ -1709,7 +1708,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
add = memnew(Button);
hbc->add_child(add);
- add->set_custom_minimum_size(Size2(150, 0) * EDSCALE);
add->set_text(TTR("Add"));
add->set_disabled(true);
add->connect("pressed", this, "_action_add");
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 47feac9a12..16cf325bc2 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -335,6 +335,8 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
easing_draw->hide();
spinbox->hide();
slider->hide();
+ menu->clear();
+ menu->set_size(Size2(1, 1) * EDSCALE);
for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
@@ -413,7 +415,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_ENUM) {
- menu->clear();
Vector<String> options = hint_text.split(",");
for (int i = 0; i < options.size(); i++) {
if (options[i].find(":") != -1) {
@@ -494,7 +495,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
easing_draw->show();
set_size(Size2(200, 150) * EDSCALE);
} else if (hint == PROPERTY_HINT_FLAGS) {
- menu->clear();
Vector<String> flags = hint_text.split(",");
for (int i = 0; i < flags.size(); i++) {
String flag = flags[i];
@@ -536,7 +536,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
config_action_buttons(names);
} else if (hint == PROPERTY_HINT_ENUM) {
- menu->clear();
Vector<String> options = hint_text.split(",");
for (int i = 0; i < options.size(); i++) {
menu->add_item(options[i], i);
@@ -869,9 +868,6 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
if (hint != PROPERTY_HINT_RESOURCE_TYPE)
break;
- menu->clear();
- menu->set_size(Size2(1, 1) * EDSCALE);
-
if (p_name == "script" && hint_text == "Script" && Object::cast_to<Node>(owner)) {
menu->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
menu->add_separator();
@@ -1764,24 +1760,40 @@ void CustomPropertyEditor::_focus_exit() {
void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) {
- int cell_width = 60;
- int cell_height = 25;
- int cell_margin = 5;
+ Ref<StyleBox> sb = get_stylebox("panel");
+ int margin_top = sb->get_margin(MARGIN_TOP);
+ int margin_left = sb->get_margin(MARGIN_LEFT);
+ int margin_bottom = sb->get_margin(MARGIN_BOTTOM);
+ int margin_right = sb->get_margin(MARGIN_RIGHT);
- set_size(Size2(cell_margin + (cell_width + cell_margin) * p_strings.size(), (cell_margin * 2) + cell_height) * EDSCALE);
+ int max_width = 0;
+ int height = 0;
for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
if (i < p_strings.size()) {
+
action_buttons[i]->show();
action_buttons[i]->set_text(p_strings[i]);
- action_buttons[i]->set_position(Point2(cell_margin + (cell_width + cell_margin) * i, cell_margin) * EDSCALE);
- action_buttons[i]->set_size(Size2(cell_width, cell_height - cell_margin * 2) * EDSCALE);
- action_buttons[i]->set_flat(true);
+
+ Size2 btn_m_size = action_buttons[i]->get_minimum_size();
+ if (btn_m_size.width > max_width)
+ max_width = btn_m_size.width;
+
} else {
action_buttons[i]->hide();
}
}
+
+ for (int i = 0; i < p_strings.size(); i++) {
+
+ Size2 btn_m_size = action_buttons[i]->get_size();
+ action_buttons[i]->set_position(Point2(0, height) + Point2(margin_left, margin_top));
+ action_buttons[i]->set_size(Size2(max_width, btn_m_size.height));
+
+ height += btn_m_size.height;
+ }
+ set_size(Size2(max_width, height) + Size2(margin_left + margin_right, margin_top + margin_bottom));
}
void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns, int p_label_w, const List<String> &p_strings) {
@@ -1902,6 +1914,7 @@ CustomPropertyEditor::CustomPropertyEditor() {
Vector<Variant> binds;
binds.push_back(i);
action_buttons[i]->connect("pressed", this, "_action_pressed", binds);
+ action_buttons[i]->set_flat(true);
}
color_picker = NULL;
@@ -3956,11 +3969,13 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
if (t == Variant::NODE_PATH) {
Variant v = obj->get(n);
- custom_editor->edit(obj, n, (Variant::Type)t, v, h, ht);
Rect2 where = tree->get_item_rect(ti, 1);
where.position -= tree->get_scroll();
- where.position += tree->get_global_position();
+ where.position += tree->get_global_position() + Point2(where.size.width, 0);
+ for (int i = ti->get_button_count(p_column) - 1; i >= p_button; i--)
+ where.position.x -= ti->get_button(p_column, i)->get_width();
custom_editor->set_position(where.position);
+ custom_editor->edit(obj, n, (Variant::Type)t, v, h, ht);
custom_editor->popup();
} else if (t == Variant::STRING) {
@@ -3971,7 +3986,9 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
Rect2 where = tree->get_item_rect(ti, 1);
where.position -= tree->get_scroll();
- where.position += tree->get_global_position();
+ where.position += tree->get_global_position() + Point2(where.size.width, 0);
+ for (int i = ti->get_button_count(p_column) - 1; i >= p_button; i--)
+ where.position.x -= ti->get_button(p_column, i)->get_width();
custom_editor->set_position(where.position);
custom_editor->popup();
} else {
@@ -4591,6 +4608,8 @@ SectionedPropertyEditor::SectionedPropertyEditor() {
search_box = NULL;
+ add_constant_override("autohide", 1); // Fixes the dragger always showing up
+
VBoxContainer *left_vb = memnew(VBoxContainer);
left_vb->set_custom_minimum_size(Size2(170, 0) * EDSCALE);
add_child(left_vb);
@@ -4602,6 +4621,7 @@ SectionedPropertyEditor::SectionedPropertyEditor() {
left_vb->add_child(sections, true);
VBoxContainer *right_vb = memnew(VBoxContainer);
+ right_vb->set_custom_minimum_size(Size2(300, 0) * EDSCALE);
right_vb->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(right_vb);
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 6fbca5c904..06dd6bd375 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1360,6 +1360,7 @@ void SceneTreeDock::_create() {
editor_data->get_undo_redo().commit_action();
editor->push_item(c);
editor_selection->clear();
+ editor_selection->add_node(child);
if (Object::cast_to<Control>(c)) {
//make editor more comfortable, so some controls don't appear super shrunk
Control *ct = Object::cast_to<Control>(c);
@@ -1699,7 +1700,7 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
icon = get_icon("Object", "EditorIcons");
if (menu->get_item_count() == 0) {
- menu->add_submenu_item(TTR("Sub-Resources:"), "Sub-Resources");
+ menu->add_submenu_item(TTR("Sub-Resources"), "Sub-Resources");
}
int index = menu_subresources->get_item_count();
menu_subresources->add_icon_item(icon, E->get().name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size());
@@ -1733,6 +1734,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (selection.size() == 1) {
subresources.clear();
+ menu_subresources->clear();
_add_children_to_popup(selection.front()->get(), 0);
if (menu->get_item_count() > 0)
menu->add_separator();
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 2bdc824248..345f647608 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -61,6 +61,8 @@ void EditorSettingsDialog::_settings_property_edited(const String &p_name) {
property_editor->get_property_editor()->update_tree();
} else if (full_name == "interface/theme/accent_color" || full_name == "interface/theme/base_color" || full_name == "interface/theme/contrast") {
EditorSettings::get_singleton()->set_manually("interface/theme/preset", 6); // set preset to Custom
+ } else if (full_name.begins_with("text_editor/highlighting")) {
+ EditorSettings::get_singleton()->set_manually("text_editor/theme/color_theme", "Custom");
}
}
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index 7342dd5b5d..1a3ab309f7 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -2964,227 +2964,220 @@ NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p
navmesh = p_navmesh;
}
-//////
-///
-///
+ //////
+ ///
+ ///
+ ///
-void PinJointSpatialGizmo::redraw() {
+#define BODY_A_RADIUS 0.25
+#define BODY_B_RADIUS 0.27
- clear();
- Vector<Vector3> cursor_points;
- float cs = 0.25;
- cursor_points.push_back(Vector3(+cs, 0, 0));
- cursor_points.push_back(Vector3(-cs, 0, 0));
- cursor_points.push_back(Vector3(0, +cs, 0));
- cursor_points.push_back(Vector3(0, -cs, 0));
- cursor_points.push_back(Vector3(0, 0, +cs));
- cursor_points.push_back(Vector3(0, 0, -cs));
- add_collision_segments(cursor_points);
+Basis JointGizmosDrawer::look_body(const Transform &p_joint_transform, const Transform &p_body_transform) {
+ const Vector3 &p_eye(p_joint_transform.origin);
+ const Vector3 &p_target(p_body_transform.origin);
- Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+ Vector3 v_x, v_y, v_z;
- add_lines(cursor_points, material);
+ // Look the body with X
+ v_x = p_target - p_eye;
+ v_x.normalize();
+
+ v_z = v_x.cross(Vector3(0, 1, 0));
+ v_z.normalize();
+
+ v_y = v_z.cross(v_x);
+ v_y.normalize();
+
+ Basis base;
+ base.set(v_x, v_y, v_z);
+
+ // Absorb current joint transform
+ base = p_joint_transform.basis.inverse() * base;
+
+ return base;
}
-PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint *p_p3d) {
+Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform) {
- p3d = p_p3d;
- set_spatial_node(p3d);
+ switch (p_axis) {
+ case Vector3::AXIS_X:
+ return look_body_toward_x(joint_transform, body_transform);
+ case Vector3::AXIS_Y:
+ return look_body_toward_y(joint_transform, body_transform);
+ case Vector3::AXIS_Z:
+ return look_body_toward_z(joint_transform, body_transform);
+ default:
+ return Basis();
+ }
}
-////
+Basis JointGizmosDrawer::look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform) {
-void HingeJointSpatialGizmo::redraw() {
+ const Vector3 &p_eye(p_joint_transform.origin);
+ const Vector3 &p_target(p_body_transform.origin);
- clear();
- Vector<Vector3> cursor_points;
- float cs = 0.25;
- /*cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));*/
- cursor_points.push_back(Vector3(0, 0, +cs * 2));
- cursor_points.push_back(Vector3(0, 0, -cs * 2));
+ const Vector3 p_front(p_joint_transform.basis.get_axis(0));
- float ll = p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER);
- float ul = p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER);
+ Vector3 v_x, v_y, v_z;
- if (p3d->get_flag(HingeJoint::FLAG_USE_LIMIT) && ll < ul) {
+ // Look the body with X
+ v_x = p_target - p_eye;
+ v_x.normalize();
- const int points = 32;
+ v_y = p_front.cross(v_x);
+ v_y.normalize();
- for (int i = 0; i < points; i++) {
+ v_z = v_y.cross(p_front);
+ v_z.normalize();
- float s = ll + i * (ul - ll) / points;
- float n = ll + (i + 1) * (ul - ll) / points;
+ // Clamp X to FRONT axis
+ v_x = p_front;
+ v_x.normalize();
- Vector3 from = Vector3(-Math::sin(s), Math::cos(s), 0) * cs;
- Vector3 to = Vector3(-Math::sin(n), Math::cos(n), 0) * cs;
+ Basis base;
+ base.set(v_x, v_y, v_z);
- if (i == points - 1) {
- cursor_points.push_back(to);
- cursor_points.push_back(Vector3());
- }
- if (i == 0) {
- cursor_points.push_back(from);
- cursor_points.push_back(Vector3());
- }
+ // Absorb current joint transform
+ base = p_joint_transform.basis.inverse() * base;
- cursor_points.push_back(from);
- cursor_points.push_back(to);
- }
+ return base;
+}
- cursor_points.push_back(Vector3(0, cs * 1.5, 0));
- cursor_points.push_back(Vector3());
+Basis JointGizmosDrawer::look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform) {
- } else {
+ const Vector3 &p_eye(p_joint_transform.origin);
+ const Vector3 &p_target(p_body_transform.origin);
- const int points = 32;
+ const Vector3 p_up(p_joint_transform.basis.get_axis(1));
- for (int i = 0; i < points; i++) {
+ Vector3 v_x, v_y, v_z;
- float s = ll + i * (Math_PI * 2.0) / points;
- float n = ll + (i + 1) * (Math_PI * 2.0) / points;
+ // Look the body with X
+ v_x = p_target - p_eye;
+ v_x.normalize();
- Vector3 from = Vector3(-Math::sin(s), Math::cos(s), 0) * cs;
- Vector3 to = Vector3(-Math::sin(n), Math::cos(n), 0) * cs;
+ v_z = v_x.cross(p_up);
+ v_z.normalize();
- cursor_points.push_back(from);
- cursor_points.push_back(to);
- }
- }
+ v_x = p_up.cross(v_z);
+ v_x.normalize();
- Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+ // Clamp Y to UP axis
+ v_y = p_up;
+ v_y.normalize();
- add_collision_segments(cursor_points);
- add_lines(cursor_points, material);
-}
+ Basis base;
+ base.set(v_x, v_y, v_z);
-HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint *p_p3d) {
+ // Absorb current joint transform
+ base = p_joint_transform.basis.inverse() * base;
- p3d = p_p3d;
- set_spatial_node(p3d);
+ return base;
}
-///////
-///
-////
+Basis JointGizmosDrawer::look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform) {
-void SliderJointSpatialGizmo::redraw() {
+ const Vector3 &p_eye(p_joint_transform.origin);
+ const Vector3 &p_target(p_body_transform.origin);
- clear();
- Vector<Vector3> cursor_points;
- float cs = 0.25;
- /*cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));*/
- cursor_points.push_back(Vector3(0, 0, +cs * 2));
- cursor_points.push_back(Vector3(0, 0, -cs * 2));
-
- float ll = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER);
- float ul = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER);
- float lll = p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER);
- float lul = p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER);
-
- if (lll <= lul) {
-
- cursor_points.push_back(Vector3(lul, 0, 0));
- cursor_points.push_back(Vector3(lll, 0, 0));
-
- cursor_points.push_back(Vector3(lul, -cs, -cs));
- cursor_points.push_back(Vector3(lul, -cs, cs));
- cursor_points.push_back(Vector3(lul, -cs, cs));
- cursor_points.push_back(Vector3(lul, cs, cs));
- cursor_points.push_back(Vector3(lul, cs, cs));
- cursor_points.push_back(Vector3(lul, cs, -cs));
- cursor_points.push_back(Vector3(lul, cs, -cs));
- cursor_points.push_back(Vector3(lul, -cs, -cs));
-
- cursor_points.push_back(Vector3(lll, -cs, -cs));
- cursor_points.push_back(Vector3(lll, -cs, cs));
- cursor_points.push_back(Vector3(lll, -cs, cs));
- cursor_points.push_back(Vector3(lll, cs, cs));
- cursor_points.push_back(Vector3(lll, cs, cs));
- cursor_points.push_back(Vector3(lll, cs, -cs));
- cursor_points.push_back(Vector3(lll, cs, -cs));
- cursor_points.push_back(Vector3(lll, -cs, -cs));
+ const Vector3 p_lateral(p_joint_transform.basis.get_axis(2));
- } else {
+ Vector3 v_x, v_y, v_z;
- cursor_points.push_back(Vector3(+cs * 2, 0, 0));
- cursor_points.push_back(Vector3(-cs * 2, 0, 0));
- }
+ // Look the body with X
+ v_x = p_target - p_eye;
+ v_x.normalize();
- if (ll < ul) {
+ v_z = p_lateral;
+ v_z.normalize();
- const int points = 32;
+ v_y = v_z.cross(v_x);
+ v_y.normalize();
- for (int i = 0; i < points; i++) {
+ // Clamp X to Z axis
+ v_x = v_y.cross(v_z);
+ v_x.normalize();
- float s = ll + i * (ul - ll) / points;
- float n = ll + (i + 1) * (ul - ll) / points;
+ Basis base;
+ base.set(v_x, v_y, v_z);
- Vector3 from = Vector3(0, Math::cos(s), -Math::sin(s)) * cs;
- Vector3 to = Vector3(0, Math::cos(n), -Math::sin(n)) * cs;
+ // Absorb current joint transform
+ base = p_joint_transform.basis.inverse() * base;
- if (i == points - 1) {
- cursor_points.push_back(to);
- cursor_points.push_back(Vector3());
- }
- if (i == 0) {
- cursor_points.push_back(from);
- cursor_points.push_back(Vector3());
- }
+ return base;
+}
- cursor_points.push_back(from);
- cursor_points.push_back(to);
- }
+void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse) {
+
+ if (p_limit_lower == p_limit_upper) {
- cursor_points.push_back(Vector3(0, cs * 1.5, 0));
- cursor_points.push_back(Vector3());
+ r_points.push_back(p_offset.translated(Vector3()).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(0.5, 0, 0))).origin);
} else {
+ if (p_limit_lower > p_limit_upper) {
+ p_limit_lower = -Math_PI;
+ p_limit_upper = Math_PI;
+ }
+
const int points = 32;
for (int i = 0; i < points; i++) {
- float s = ll + i * (Math_PI * 2.0) / points;
- float n = ll + (i + 1) * (Math_PI * 2.0) / points;
+ real_t s = p_limit_lower + i * (p_limit_upper - p_limit_lower) / points;
+ real_t n = p_limit_lower + (i + 1) * (p_limit_upper - p_limit_lower) / points;
+
+ Vector3 from;
+ Vector3 to;
+ switch (p_axis) {
+ case Vector3::AXIS_X:
+ if (p_inverse) {
+ from = p_base.xform(Vector3(0, Math::sin(s), Math::cos(s))) * p_radius;
+ to = p_base.xform(Vector3(0, Math::sin(n), Math::cos(n))) * p_radius;
+ } else {
+ from = p_base.xform(Vector3(0, -Math::sin(s), Math::cos(s))) * p_radius;
+ to = p_base.xform(Vector3(0, -Math::sin(n), Math::cos(n))) * p_radius;
+ }
+ break;
+ case Vector3::AXIS_Y:
+ if (p_inverse) {
+ from = p_base.xform(Vector3(Math::cos(s), 0, -Math::sin(s))) * p_radius;
+ to = p_base.xform(Vector3(Math::cos(n), 0, -Math::sin(n))) * p_radius;
+ } else {
+ from = p_base.xform(Vector3(Math::cos(s), 0, Math::sin(s))) * p_radius;
+ to = p_base.xform(Vector3(Math::cos(n), 0, Math::sin(n))) * p_radius;
+ }
+ break;
+ case Vector3::AXIS_Z:
+ from = p_base.xform(Vector3(Math::cos(s), Math::sin(s), 0)) * p_radius;
+ to = p_base.xform(Vector3(Math::cos(n), Math::sin(n), 0)) * p_radius;
+ break;
+ }
- Vector3 from = Vector3(0, Math::cos(s), -Math::sin(s)) * cs;
- Vector3 to = Vector3(0, Math::cos(n), -Math::sin(n)) * cs;
+ if (i == points - 1) {
+ r_points.push_back(p_offset.translated(to).origin);
+ r_points.push_back(p_offset.translated(Vector3()).origin);
+ }
+ if (i == 0) {
+ r_points.push_back(p_offset.translated(from).origin);
+ r_points.push_back(p_offset.translated(Vector3()).origin);
+ }
- cursor_points.push_back(from);
- cursor_points.push_back(to);
+ r_points.push_back(p_offset.translated(from).origin);
+ r_points.push_back(p_offset.translated(to).origin);
}
- }
-
- Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
-
- add_collision_segments(cursor_points);
- add_lines(cursor_points, material);
-}
-
-SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint *p_p3d) {
- p3d = p_p3d;
- set_spatial_node(p3d);
+ r_points.push_back(p_offset.translated(Vector3(0, p_radius * 1.5, 0)).origin);
+ r_points.push_back(p_offset.translated(Vector3()).origin);
+ }
}
-///////
-///
-////
-
-void ConeTwistJointSpatialGizmo::redraw() {
-
- clear();
- Vector<Vector3> points;
+void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points) {
float r = 1.0;
- float w = r * Math::sin(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN));
- float d = r * Math::cos(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN));
+ float w = r * Math::sin(p_swing);
+ float d = r * Math::cos(p_swing);
//swing
for (int i = 0; i < 360; i += 10) {
@@ -3194,27 +3187,21 @@ void ConeTwistJointSpatialGizmo::redraw() {
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
- /*points.push_back(Vector3(a.x,0,a.y));
- points.push_back(Vector3(b.x,0,b.y));
- points.push_back(Vector3(0,a.x,a.y));
- points.push_back(Vector3(0,b.x,b.y));*/
- points.push_back(Vector3(d, a.x, a.y));
- points.push_back(Vector3(d, b.x, b.y));
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, a.x, a.y))).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, b.x, b.y))).origin);
if (i % 90 == 0) {
- points.push_back(Vector3(d, a.x, a.y));
- points.push_back(Vector3());
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, a.x, a.y))).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3())).origin);
}
}
- points.push_back(Vector3());
- points.push_back(Vector3(1, 0, 0));
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3())).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(1, 0, 0))).origin);
- //twist
- /*
- */
- float ts = Math::rad2deg(p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN));
+ /// Twist
+ float ts = Math::rad2deg(p_twist);
ts = MIN(ts, 720);
for (int i = 0; i < int(ts); i += 5) {
@@ -3226,18 +3213,276 @@ void ConeTwistJointSpatialGizmo::redraw() {
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w * cn;
- /*points.push_back(Vector3(a.x,0,a.y));
- points.push_back(Vector3(b.x,0,b.y));
- points.push_back(Vector3(0,a.x,a.y));
- points.push_back(Vector3(0,b.x,b.y));*/
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(c, a.x, a.y))).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(cn, b.x, b.y))).origin);
+ }
+}
+
+void PinJointSpatialGizmo::CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) {
+ float cs = 0.25;
+
+ r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin);
+}
+
+void PinJointSpatialGizmo::redraw() {
+
+ clear();
+ Vector<Vector3> cursor_points;
+ CreateGizmo(Transform(), cursor_points);
+ add_collision_segments(cursor_points);
+
+ Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+
+ add_lines(cursor_points, material);
+}
+
+PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint *p_p3d) {
+
+ p3d = p_p3d;
+ set_spatial_node(p3d);
+}
+
+////
+
+void HingeJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+
+ r_common_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin);
+ r_common_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin);
+
+ if (!p_use_limit) {
+ p_limit_upper = -1;
+ p_limit_lower = 0;
+ }
+
+ if (r_body_a_points) {
+
+ JointGizmosDrawer::draw_circle(Vector3::AXIS_Z,
+ BODY_A_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_a),
+ p_limit_lower,
+ p_limit_upper,
+ *r_body_a_points);
+ }
- points.push_back(Vector3(c, a.x, a.y));
- points.push_back(Vector3(cn, b.x, b.y));
+ if (r_body_b_points) {
+ JointGizmosDrawer::draw_circle(Vector3::AXIS_Z,
+ BODY_B_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_b),
+ p_limit_lower,
+ p_limit_upper,
+ *r_body_b_points);
}
+}
+
+void HingeJointSpatialGizmo::redraw() {
+
+ const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a()));
+ const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b()));
+
+ Vector<Vector3> points;
+ Vector<Vector3> body_a_points;
+ Vector<Vector3> body_b_points;
+ CreateGizmo(
+ Transform(),
+ p3d->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER),
+ p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER),
+ p3d->get_flag(HingeJoint::FLAG_USE_LIMIT),
+ points,
+ node_body_a ? &body_a_points : NULL,
+ node_body_b ? &body_b_points : NULL);
+
+ clear();
+
+ Ref<Material> common_material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+ Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
+ Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
+
+ add_collision_segments(points);
+ add_collision_segments(body_a_points);
+ add_collision_segments(body_b_points);
+
+ add_lines(points, common_material);
+ add_lines(body_a_points, body_a_material);
+ add_lines(body_b_points, body_b_material);
+}
+
+HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint *p_p3d) {
+
+ p3d = p_p3d;
+ set_spatial_node(p3d);
+}
+
+///////
+///
+////
+
+void SliderJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+
+ p_linear_limit_lower = -p_linear_limit_lower;
+ p_linear_limit_upper = -p_linear_limit_upper;
+
+ float cs = 0.25;
+ r_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin);
+ r_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin);
+
+ if (p_linear_limit_lower >= p_linear_limit_upper) {
+
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, 0, 0)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, 0, 0)).origin);
+
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, -cs)).origin);
+
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, -cs)).origin);
+
+ } else {
+
+ r_points.push_back(p_offset.translated(Vector3(+cs * 2, 0, 0)).origin);
+ r_points.push_back(p_offset.translated(Vector3(-cs * 2, 0, 0)).origin);
+ }
+
+ if (r_body_a_points)
+ JointGizmosDrawer::draw_circle(
+ Vector3::AXIS_X,
+ BODY_A_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_a),
+ p_angular_limit_lower,
+ p_angular_limit_upper,
+ *r_body_a_points);
+
+ if (r_body_b_points)
+ JointGizmosDrawer::draw_circle(
+ Vector3::AXIS_X,
+ BODY_B_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_b),
+ p_angular_limit_lower,
+ p_angular_limit_upper,
+ *r_body_b_points,
+ true);
+}
+
+void SliderJointSpatialGizmo::redraw() {
+
+ const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a()));
+ const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b()));
+
+ clear();
+ Vector<Vector3> cursor_points;
+ Vector<Vector3> body_a_points;
+ Vector<Vector3> body_b_points;
+
+ CreateGizmo(
+ Transform(),
+ p3d->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER),
+ p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER),
+ p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER),
+ p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER),
+ cursor_points,
+ node_body_a ? &body_a_points : NULL,
+ node_body_b ? &body_b_points : NULL);
+
+ Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+ Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
+ Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
+
+ add_collision_segments(cursor_points);
+ add_collision_segments(body_a_points);
+ add_collision_segments(body_b_points);
+
+ add_lines(cursor_points, material);
+ add_lines(body_a_points, body_a_material);
+ add_lines(body_b_points, body_b_material);
+}
+
+SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint *p_p3d) {
+
+ p3d = p_p3d;
+ set_spatial_node(p3d);
+}
+
+///////
+///
+////
+
+void ConeTwistJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+
+ if (r_body_a_points)
+ JointGizmosDrawer::draw_cone(
+ p_offset,
+ JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_a),
+ p_swing,
+ p_twist,
+ *r_body_a_points);
+
+ if (r_body_b_points)
+ JointGizmosDrawer::draw_cone(
+ p_offset,
+ JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_b),
+ p_swing,
+ p_twist,
+ *r_body_b_points);
+}
+
+void ConeTwistJointSpatialGizmo::redraw() {
+
+ const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a()));
+ const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b()));
+
+ clear();
+ Vector<Vector3> points;
+ Vector<Vector3> body_a_points;
+ Vector<Vector3> body_b_points;
+
+ CreateGizmo(
+ Transform(),
+ p3d->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN),
+ p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN),
+ points,
+ node_body_a ? &body_a_points : NULL,
+ node_body_b ? &body_b_points : NULL);
Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+ Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
+ Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
+
add_collision_segments(points);
+ add_collision_segments(body_a_points);
+ add_collision_segments(body_b_points);
+
add_lines(points, material);
+ add_lines(body_a_points, body_a_material);
+ add_lines(body_b_points, body_b_material);
}
ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d) {
@@ -3246,26 +3491,46 @@ ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d) {
set_spatial_node(p3d);
}
-////////
-/// \brief SpatialEditorGizmos::singleton
-///
///////
///
////
-void Generic6DOFJointSpatialGizmo::redraw() {
+void Generic6DOFJointSpatialGizmo::CreateGizmo(
+ const Transform &p_offset,
+ const Transform &p_trs_joint,
+ const Transform &p_trs_body_a,
+ const Transform &p_trs_body_b,
+ real_t p_angular_limit_lower_x,
+ real_t p_angular_limit_upper_x,
+ real_t p_linear_limit_lower_x,
+ real_t p_linear_limit_upper_x,
+ bool p_enable_angular_limit_x,
+ bool p_enable_linear_limit_x,
+ real_t p_angular_limit_lower_y,
+ real_t p_angular_limit_upper_y,
+ real_t p_linear_limit_lower_y,
+ real_t p_linear_limit_upper_y,
+ bool p_enable_angular_limit_y,
+ bool p_enable_linear_limit_y,
+ real_t p_angular_limit_lower_z,
+ real_t p_angular_limit_upper_z,
+ real_t p_linear_limit_lower_z,
+ real_t p_linear_limit_upper_z,
+ bool p_enable_angular_limit_z,
+ bool p_enable_linear_limit_z,
+ Vector<Vector3> &r_points,
+ Vector<Vector3> *r_body_a_points,
+ Vector<Vector3> *r_body_b_points) {
- clear();
- Vector<Vector3> cursor_points;
float cs = 0.25;
for (int ax = 0; ax < 3; ax++) {
- /*cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));
- cursor_points.push_back(Vector3(0,0,+cs*2));
- cursor_points.push_back(Vector3(0,0,-cs*2)); */
+ /*r_points.push_back(p_offset.translated(Vector3(+cs,0,0)).origin);
+ r_points.push_back(p_offset.translated(Vector3(-cs,0,0)).origin);
+ r_points.push_back(p_offset.translated(Vector3(0,+cs,0)).origin);
+ r_points.push_back(p_offset.translated(Vector3(0,-cs,0)).origin);
+ r_points.push_back(p_offset.translated(Vector3(0,0,+cs*2)).origin);
+ r_points.push_back(p_offset.translated(Vector3(0,0,-cs*2)).origin); */
float ll;
float ul;
@@ -3278,61 +3543,50 @@ void Generic6DOFJointSpatialGizmo::redraw() {
switch (ax) {
case 0:
- ll = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
- ul = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
- lll = p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
- lul = p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
- enable_ang = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
- enable_lin = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
+ ll = p_angular_limit_lower_x;
+ ul = p_angular_limit_upper_x;
+ lll = -p_linear_limit_lower_x;
+ lul = -p_linear_limit_upper_x;
+ enable_ang = p_enable_angular_limit_x;
+ enable_lin = p_enable_linear_limit_x;
a1 = 0;
a2 = 1;
a3 = 2;
break;
case 1:
- ll = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
- ul = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
- lll = p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
- lul = p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
- enable_ang = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
- enable_lin = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
-
+ ll = p_angular_limit_lower_y;
+ ul = p_angular_limit_upper_y;
+ lll = -p_linear_limit_lower_y;
+ lul = -p_linear_limit_upper_y;
+ enable_ang = p_enable_angular_limit_y;
+ enable_lin = p_enable_linear_limit_y;
a1 = 1;
a2 = 2;
a3 = 0;
break;
case 2:
- ll = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
- ul = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
- lll = p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
- lul = p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
- enable_ang = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
- enable_lin = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
-
+ ll = p_angular_limit_lower_z;
+ ul = p_angular_limit_upper_z;
+ lll = -p_linear_limit_lower_z;
+ lul = -p_linear_limit_upper_z;
+ enable_ang = p_enable_angular_limit_z;
+ enable_lin = p_enable_linear_limit_z;
a1 = 2;
a2 = 0;
a3 = 1;
break;
}
-#define ADD_VTX(x, y, z) \
- { \
- Vector3 v; \
- v[a1] = (x); \
- v[a2] = (y); \
- v[a3] = (z); \
- cursor_points.push_back(v); \
- }
-
-#define SET_VTX(what, x, y, z) \
- { \
- Vector3 v; \
- v[a1] = (x); \
- v[a2] = (y); \
- v[a3] = (z); \
- what = v; \
+#define ADD_VTX(x, y, z) \
+ { \
+ Vector3 v; \
+ v[a1] = (x); \
+ v[a2] = (y); \
+ v[a3] = (z); \
+ r_points.push_back(p_offset.translated(v).origin); \
}
- if (enable_lin && lll <= lul) {
+ if (enable_lin && lll >= lul) {
ADD_VTX(lul, 0, 0);
ADD_VTX(lll, 0, 0);
@@ -3361,69 +3615,88 @@ void Generic6DOFJointSpatialGizmo::redraw() {
ADD_VTX(-cs * 2, 0, 0);
}
- if (enable_ang && ll <= ul) {
-
- const int points = 32;
-
- for (int i = 0; i < points; i++) {
-
- float s = ll + i * (ul - ll) / points;
- float n = ll + (i + 1) * (ul - ll) / points;
-
- Vector3 from;
- SET_VTX(from, 0, Math::cos(s), -Math::sin(s));
- from *= cs;
- Vector3 to;
- SET_VTX(to, 0, Math::cos(n), -Math::sin(n));
- to *= cs;
-
- if (i == points - 1) {
- cursor_points.push_back(to);
- cursor_points.push_back(Vector3());
- }
- if (i == 0) {
- cursor_points.push_back(from);
- cursor_points.push_back(Vector3());
- }
-
- cursor_points.push_back(from);
- cursor_points.push_back(to);
- }
-
- ADD_VTX(0, cs * 1.5, 0);
- cursor_points.push_back(Vector3());
-
- } else {
-
- const int points = 32;
-
- for (int i = 0; i < points; i++) {
+ if (!enable_ang) {
+ ll = 0;
+ ul = -1;
+ }
- float s = ll + i * (Math_PI * 2.0) / points;
- float n = ll + (i + 1) * (Math_PI * 2.0) / points;
+ if (r_body_a_points)
+ JointGizmosDrawer::draw_circle(
+ static_cast<Vector3::Axis>(ax),
+ BODY_A_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_a),
+ ll,
+ ul,
+ *r_body_a_points,
+ true);
+
+ if (r_body_b_points)
+ JointGizmosDrawer::draw_circle(
+ static_cast<Vector3::Axis>(ax),
+ BODY_B_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_b),
+ ll,
+ ul,
+ *r_body_b_points);
+ }
- //Vector3 from=Vector3(0,Math::cos(s),-Math::sin(s) )*cs;
- //Vector3 to=Vector3( 0,Math::cos(n),-Math::sin(n) )*cs;
+#undef ADD_VTX
+}
- Vector3 from;
- SET_VTX(from, 0, Math::cos(s), -Math::sin(s));
- from *= cs;
- Vector3 to;
- SET_VTX(to, 0, Math::cos(n), -Math::sin(n));
- to *= cs;
+void Generic6DOFJointSpatialGizmo::redraw() {
- cursor_points.push_back(from);
- cursor_points.push_back(to);
- }
- }
- }
+ const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a()));
+ const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b()));
-#undef ADD_VTX
-#undef SET_VTX
+ clear();
+ Vector<Vector3> cursor_points;
+ Vector<Vector3> body_a_points;
+ Vector<Vector3> body_b_points;
+
+ CreateGizmo(
+ Transform(),
+ p3d->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+
+ p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
+ p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
+ p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
+ p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
+ p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
+ p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
+
+ p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
+ p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
+ p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
+ p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
+ p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
+ p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
+
+ p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
+ p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
+ p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
+ p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
+ p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
+ p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
+
+ cursor_points,
+ node_body_a ? &body_a_points : NULL,
+ node_body_a ? &body_b_points : NULL);
Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+ Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
+ Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
+
add_collision_segments(cursor_points);
+ add_collision_segments(body_a_points);
+ add_collision_segments(body_b_points);
+
add_lines(cursor_points, material);
+ add_lines(body_a_points, body_a_material);
+ add_lines(body_b_points, body_b_material);
}
Generic6DOFJointSpatialGizmo::Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d) {
@@ -3616,6 +3889,8 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1));
+ EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1));
+ EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4));
diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h
index ea8a33d2c6..7bf632d371 100644
--- a/editor/spatial_editor_gizmos.h
+++ b/editor/spatial_editor_gizmos.h
@@ -107,6 +107,7 @@ protected:
void add_solid_box(Ref<Material> &p_material, Vector3 size);
void set_spatial_node(Spatial *p_node);
+ const Spatial *get_spatial_node() const { return spatial_node; }
static void _bind_methods();
@@ -372,6 +373,21 @@ public:
NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh = NULL);
};
+class JointGizmosDrawer {
+public:
+ static Basis look_body(const Transform &joint_transform, const Transform &body_transform);
+ static Basis look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform);
+ static Basis look_body_toward_x(const Transform &joint_transform, const Transform &body_transform);
+ static Basis look_body_toward_y(const Transform &joint_transform, const Transform &body_transform);
+ /// Special function just used for physics joints, it that returns a basis constrained toward Joint Z axis
+ /// with axis X and Y that are looking toward the body and oriented toward up
+ static Basis look_body_toward_z(const Transform &joint_transform, const Transform &body_transform);
+
+ // Draw circle around p_axis
+ static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse = false);
+ static void draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points);
+};
+
class PinJointSpatialGizmo : public EditorSpatialGizmo {
GDCLASS(PinJointSpatialGizmo, EditorSpatialGizmo);
@@ -379,6 +395,8 @@ class PinJointSpatialGizmo : public EditorSpatialGizmo {
PinJoint *p3d;
public:
+ static void CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points);
+
void redraw();
PinJointSpatialGizmo(PinJoint *p_p3d = NULL);
};
@@ -390,6 +408,8 @@ class HingeJointSpatialGizmo : public EditorSpatialGizmo {
HingeJoint *p3d;
public:
+ static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+
void redraw();
HingeJointSpatialGizmo(HingeJoint *p_p3d = NULL);
};
@@ -401,6 +421,8 @@ class SliderJointSpatialGizmo : public EditorSpatialGizmo {
SliderJoint *p3d;
public:
+ static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+
void redraw();
SliderJointSpatialGizmo(SliderJoint *p_p3d = NULL);
};
@@ -412,6 +434,8 @@ class ConeTwistJointSpatialGizmo : public EditorSpatialGizmo {
ConeTwistJoint *p3d;
public:
+ static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+
void redraw();
ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d = NULL);
};
@@ -423,6 +447,33 @@ class Generic6DOFJointSpatialGizmo : public EditorSpatialGizmo {
Generic6DOFJoint *p3d;
public:
+ static void CreateGizmo(
+ const Transform &p_offset,
+ const Transform &p_trs_joint,
+ const Transform &p_trs_body_a,
+ const Transform &p_trs_body_b,
+ real_t p_angular_limit_lower_x,
+ real_t p_angular_limit_upper_x,
+ real_t p_linear_limit_lower_x,
+ real_t p_linear_limit_upper_x,
+ bool p_enable_angular_limit_x,
+ bool p_enable_linear_limit_x,
+ real_t p_angular_limit_lower_y,
+ real_t p_angular_limit_upper_y,
+ real_t p_linear_limit_lower_y,
+ real_t p_linear_limit_upper_y,
+ bool p_enable_angular_limit_y,
+ bool p_enable_linear_limit_y,
+ real_t p_angular_limit_lower_z,
+ real_t p_angular_limit_upper_z,
+ real_t p_linear_limit_lower_z,
+ real_t p_linear_limit_upper_z,
+ bool p_enable_angular_limit_z,
+ bool p_enable_linear_limit_z,
+ Vector<Vector3> &r_points,
+ Vector<Vector3> *r_body_a_points,
+ Vector<Vector3> *r_body_b_points);
+
void redraw();
Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d = NULL);
};
diff --git a/main/main.cpp b/main/main.cpp
index 5648676c4c..b72ffb9850 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -755,8 +755,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (editor) {
Engine::get_singleton()->set_editor_hint(true);
main_args.push_back("--editor");
- init_maximized = true;
- video_mode.maximized = true;
+ if (!init_windowed) {
+ init_maximized = true;
+ video_mode.maximized = true;
+ }
use_custom_res = false;
}
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index b233edc0d4..ae062904b4 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -121,7 +121,7 @@ RID BulletPhysicsServer::shape_create(ShapeType p_shape) {
shape = bulletnew(RayShapeBullet);
} break;
case SHAPE_CUSTOM:
- defaul:
+ default:
ERR_FAIL_V(RID());
break;
}
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index cbf30c8a2e..37e45cfff8 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -142,6 +142,9 @@ bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) co
btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
+ if (m_count >= m_resultMax)
+ return cp.getDistance();
+
if (cp.getDistance() <= 0) {
PhysicsDirectSpaceState::ShapeResult &result = m_results[m_count];
@@ -165,7 +168,7 @@ btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, con
++m_count;
}
- return m_count < m_resultMax;
+ return cp.getDistance();
}
bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 669b2c3f0c..5e736c1856 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -264,6 +264,7 @@ RigidBodyBullet::RigidBodyBullet() :
can_sleep(true),
force_integration_callback(NULL),
isTransformChanged(false),
+ previousActiveState(true),
maxCollisionsDetection(0),
collisionsCount(0),
maxAreasWhereIam(10),
@@ -287,6 +288,7 @@ RigidBodyBullet::RigidBodyBullet() :
for (int i = areasWhereIam.size() - 1; 0 <= i; --i) {
areasWhereIam[i] = NULL;
}
+ btBody->setSleepingThresholds(0.2, 0.2);
}
RigidBodyBullet::~RigidBodyBullet() {
@@ -337,7 +339,7 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) {
void RigidBodyBullet::dispatch_callbacks() {
/// The check isTransformChanged is necessary in order to call integrated forces only when the first transform is sent
- if (btBody->isActive() && force_integration_callback && isTransformChanged) {
+ if ((btBody->isActive() || previousActiveState != btBody->isActive()) && force_integration_callback && isTransformChanged) {
BulletPhysicsDirectBodyState *bodyDirect = BulletPhysicsDirectBodyState::get_singleton(this);
@@ -364,6 +366,8 @@ void RigidBodyBullet::dispatch_callbacks() {
/// Lock axis
btBody->setLinearVelocity(btBody->getLinearVelocity() * btBody->getLinearFactor());
btBody->setAngularVelocity(btBody->getAngularVelocity() * btBody->getAngularFactor());
+
+ previousActiveState = btBody->isActive();
}
void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
@@ -580,7 +584,8 @@ Variant RigidBodyBullet::get_state(PhysicsServer::BodyState p_state) const {
void RigidBodyBullet::apply_central_impulse(const Vector3 &p_impulse) {
btVector3 btImpu;
G_TO_B(p_impulse, btImpu);
- btBody->activate();
+ if (Vector3() != p_impulse)
+ btBody->activate();
btBody->applyCentralImpulse(btImpu);
}
@@ -589,14 +594,16 @@ void RigidBodyBullet::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impul
btVector3 btPos;
G_TO_B(p_impulse, btImpu);
G_TO_B(p_pos, btPos);
- btBody->activate();
+ if (Vector3() != p_impulse)
+ btBody->activate();
btBody->applyImpulse(btImpu, btPos);
}
void RigidBodyBullet::apply_torque_impulse(const Vector3 &p_impulse) {
btVector3 btImp;
G_TO_B(p_impulse, btImp);
- btBody->activate();
+ if (Vector3() != p_impulse)
+ btBody->activate();
btBody->applyTorqueImpulse(btImp);
}
@@ -605,28 +612,32 @@ void RigidBodyBullet::apply_force(const Vector3 &p_force, const Vector3 &p_pos)
btVector3 btPos;
G_TO_B(p_force, btForce);
G_TO_B(p_pos, btPos);
- btBody->activate();
+ if (Vector3() != p_force)
+ btBody->activate();
btBody->applyForce(btForce, btPos);
}
void RigidBodyBullet::apply_central_force(const Vector3 &p_force) {
btVector3 btForce;
G_TO_B(p_force, btForce);
- btBody->activate();
+ if (Vector3() != p_force)
+ btBody->activate();
btBody->applyCentralForce(btForce);
}
void RigidBodyBullet::apply_torque(const Vector3 &p_torque) {
btVector3 btTorq;
G_TO_B(p_torque, btTorq);
- btBody->activate();
+ if (Vector3() != p_torque)
+ btBody->activate();
btBody->applyTorque(btTorq);
}
void RigidBodyBullet::set_applied_force(const Vector3 &p_force) {
btVector3 btVec = btBody->getTotalTorque();
- btBody->activate();
+ if (Vector3() != p_force)
+ btBody->activate();
btBody->clearForces();
btBody->applyTorque(btVec);
@@ -644,7 +655,8 @@ Vector3 RigidBodyBullet::get_applied_force() const {
void RigidBodyBullet::set_applied_torque(const Vector3 &p_torque) {
btVector3 btVec = btBody->getTotalForce();
- btBody->activate();
+ if (Vector3() != p_torque)
+ btBody->activate();
btBody->clearForces();
btBody->applyCentralForce(btVec);
@@ -711,7 +723,8 @@ bool RigidBodyBullet::is_continuous_collision_detection_enabled() const {
void RigidBodyBullet::set_linear_velocity(const Vector3 &p_velocity) {
btVector3 btVec;
G_TO_B(p_velocity, btVec);
- btBody->activate();
+ if (Vector3() != p_velocity)
+ btBody->activate();
btBody->setLinearVelocity(btVec);
}
@@ -724,7 +737,8 @@ Vector3 RigidBodyBullet::get_linear_velocity() const {
void RigidBodyBullet::set_angular_velocity(const Vector3 &p_velocity) {
btVector3 btVec;
G_TO_B(p_velocity, btVec);
- btBody->activate();
+ if (Vector3() != p_velocity)
+ btBody->activate();
btBody->setAngularVelocity(btVec);
}
@@ -833,6 +847,9 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) {
void RigidBodyBullet::reload_space_override_modificator() {
+ if (!is_active())
+ return;
+
Vector3 newGravity(space->get_gravity_direction() * space->get_gravity_magnitude());
real_t newLinearDamp(linearDamp);
real_t newAngularDamp(angularDamp);
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index c0eb148e24..c3b72172d9 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -207,6 +207,7 @@ private:
bool isScratchedSpaceOverrideModificator;
bool isTransformChanged;
+ bool previousActiveState; // Last check state
ForceIntegrationCallback *force_integration_callback;
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index af5a0334c3..61dedbf1d7 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -122,6 +122,16 @@ void CSharpLanguage::init() {
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
+
// Release gchandle bindings before finalizing mono runtime
gchandle_bindings.clear();
@@ -129,6 +139,8 @@ void CSharpLanguage::finish() {
memdelete(gdmono);
gdmono = NULL;
}
+
+ finalizing = false;
}
void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
@@ -742,6 +754,8 @@ CSharpLanguage::CSharpLanguage() {
ERR_FAIL_COND(singleton);
singleton = this;
+ finalizing = false;
+
gdmono = NULL;
#ifdef NO_THREADS
@@ -798,12 +812,9 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
ERR_FAIL_NULL_V(mono_object, NULL);
// Tie managed to unmanaged
- bool strong_handle = true;
Reference *ref = Object::cast_to<Reference>(p_object);
if (ref) {
- strong_handle = false;
-
// Unsafe refcount increment. The managed instance also counts as a reference.
// This way if the unmanaged world has no references to our owner
// but the managed instance is alive, the refcount will be 1 instead of 0.
@@ -812,8 +823,7 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
ref->reference();
}
- Ref<MonoGCHandle> gchandle = strong_handle ? MonoGCHandle::create_strong(mono_object) :
- MonoGCHandle::create_weak(mono_object);
+ Ref<MonoGCHandle> gchandle = MonoGCHandle::create_strong(mono_object);
#ifndef NO_THREADS
script_bind_lock->lock();
@@ -838,27 +848,38 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
return;
}
+ if (finalizing)
+ return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
+
#ifndef NO_THREADS
script_bind_lock->lock();
#endif
- gchandle_bindings.erase((Map<Object *, Ref<MonoGCHandle> >::Element *)p_data);
+ Map<Object *, Ref<MonoGCHandle> >::Element *data = (Map<Object *, Ref<MonoGCHandle> >::Element *)p_data;
+
+ // Set the native instance field to IntPtr.Zero, if not yet garbage collected
+ MonoObject *mono_object = data->value()->get_target();
+ if (mono_object) {
+ CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
+ }
+
+ gchandle_bindings.erase(data);
#ifndef NO_THREADS
script_bind_lock->unlock();
#endif
}
-void CSharpInstance::_ml_call_reversed(GDMonoClass *klass, const StringName &p_method, const Variant **p_args, int p_argcount) {
+void CSharpInstance::_ml_call_reversed(MonoObject *p_mono_object, GDMonoClass *p_klass, const StringName &p_method, const Variant **p_args, int p_argcount) {
- GDMonoClass *base = klass->get_parent_class();
+ GDMonoClass *base = p_klass->get_parent_class();
if (base && base != script->native)
- _ml_call_reversed(base, p_method, p_args, p_argcount);
+ _ml_call_reversed(p_mono_object, base, p_method, p_args, p_argcount);
- GDMonoMethod *method = klass->get_method(p_method, p_argcount);
+ GDMonoMethod *method = p_klass->get_method(p_method, p_argcount);
if (method) {
- method->invoke(get_mono_object(), p_args);
+ method->invoke(p_mono_object, p_args);
}
}
@@ -1020,7 +1041,6 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args,
MonoObject *mono_object = get_mono_object();
- ERR_EXPLAIN("Reference has been garbage collected?");
ERR_FAIL_NULL_V(mono_object, Variant());
if (!script.is_valid())
@@ -1054,23 +1074,34 @@ void CSharpInstance::call_multilevel(const StringName &p_method, const Variant *
if (script.is_valid()) {
MonoObject *mono_object = get_mono_object();
- GDMonoClass *top = script->script_class;
+ ERR_FAIL_NULL(mono_object);
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(p_method, p_argcount);
+ _call_multilevel(mono_object, p_method, p_args, p_argcount);
+ }
+}
- if (method)
- method->invoke(mono_object, p_args);
+void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
- top = top->get_parent_class();
- }
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoMethod *method = top->get_method(p_method, p_argcount);
+
+ if (method)
+ method->invoke(p_mono_object, p_args);
+
+ top = top->get_parent_class();
}
}
void CSharpInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
if (script.is_valid()) {
- _ml_call_reversed(script->script_class, p_method, p_args, p_argcount);
+ MonoObject *mono_object = get_mono_object();
+
+ ERR_FAIL_NULL(mono_object);
+
+ _ml_call_reversed(mono_object, script->script_class, p_method, p_args, p_argcount);
}
}
@@ -1118,7 +1149,7 @@ void CSharpInstance::refcount_incremented() {
Reference *ref_owner = Object::cast_to<Reference>(owner);
- if (ref_owner->reference_get_count() > 1) { // Remember the managed side holds a reference, hence 1 instead of 0 here
+ if (ref_owner->reference_get_count() > 1) { // The managed side also holds a reference, hence 1 instead of 0
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
@@ -1138,7 +1169,7 @@ bool CSharpInstance::refcount_decremented() {
int refcount = ref_owner->reference_get_count();
- if (refcount == 1) { // Remember the managed side holds a reference, hence 1 instead of 0 here
+ if (refcount == 1) { // The managed side also holds a reference, hence 1 instead of 0
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
@@ -1207,10 +1238,25 @@ ScriptInstance::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variab
void CSharpInstance::notification(int p_notification) {
+ MonoObject *mono_object = get_mono_object();
+
+ if (p_notification == Object::NOTIFICATION_PREDELETE) {
+ if (mono_object != NULL) { // otherwise it was collected, and the finalizer already called NOTIFICATION_PREDELETE
+ call_notification_no_check(mono_object, p_notification);
+ // Set the native instance field to IntPtr.Zero
+ CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
+ }
+ return;
+ }
+
+ call_notification_no_check(mono_object, p_notification);
+}
+
+void CSharpInstance::call_notification_no_check(MonoObject *p_mono_object, int p_notification) {
Variant value = p_notification;
const Variant *args[1] = { &value };
- call_multilevel(CACHED_STRING_NAME(_notification), args, 1);
+ _call_multilevel(p_mono_object, CACHED_STRING_NAME(_notification), args, 1);
}
Ref<Script> CSharpInstance::get_script() const {
@@ -1376,7 +1422,7 @@ bool CSharpScript::_update_exports() {
hint_string = NATIVE_GDMONOCLASS_NAME(field_type.type_class);
} else {
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
- hint_string = CACHED_FIELD(ExportAttribute, hint_string)->get_string_value(attr);
+ hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
}
PropertyInfo prop_info = PropertyInfo(type, name, hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 255665b495..1a07cf6835 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -167,7 +167,7 @@ class CSharpInstance : public ScriptInstance {
bool base_ref;
bool ref_dying;
- void _ml_call_reversed(GDMonoClass *klass, const StringName &p_method, const Variant **p_args, int p_argcount);
+ void _ml_call_reversed(MonoObject *p_mono_object, GDMonoClass *klass, const StringName &p_method, const Variant **p_args, int p_argcount);
void _reference_owner_unsafe();
void _unreference_owner_unsafe();
@@ -176,6 +176,8 @@ class CSharpInstance : public ScriptInstance {
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle);
+ void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+
public:
MonoObject *get_mono_object() const;
@@ -192,13 +194,14 @@ public:
void mono_object_disposed();
- void refcount_incremented();
- bool refcount_decremented();
+ virtual void refcount_incremented();
+ virtual bool refcount_decremented();
- RPCMode get_rpc_mode(const StringName &p_method) const;
- RPCMode get_rset_mode(const StringName &p_variable) const;
+ virtual RPCMode get_rpc_mode(const StringName &p_method) const;
+ virtual RPCMode get_rset_mode(const StringName &p_variable) const;
virtual void notification(int p_notification);
+ void call_notification_no_check(MonoObject *p_mono_object, int p_notification);
virtual Ref<Script> get_script() const;
@@ -215,6 +218,8 @@ class CSharpLanguage : public ScriptLanguage {
static CSharpLanguage *singleton;
+ bool finalizing;
+
GDMono *gdmono;
SelfList<CSharpScript>::List script_list;
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index fbb9b2ed14..cd12afb5dd 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -108,7 +108,9 @@ const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in
bool BindingsGenerator::verbose_output = false;
-static String snake_to_pascal_case(const String &p_identifier) {
+BindingsGenerator *BindingsGenerator::singleton = NULL;
+
+static String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper = false) {
String ret;
Vector<String> parts = p_identifier.split("_", true);
@@ -118,6 +120,10 @@ static String snake_to_pascal_case(const String &p_identifier) {
if (part.length()) {
part[0] = _find_upper(part[0]);
+ if (p_input_is_upper) {
+ for (int j = 1; j < part.length(); j++)
+ part[j] = _find_lower(part[j]);
+ }
ret += part;
} else {
if (i == 0 || i == (parts.size() - 1)) {
@@ -137,7 +143,7 @@ static String snake_to_pascal_case(const String &p_identifier) {
return ret;
}
-static String snake_to_camel_case(const String &p_identifier) {
+static String snake_to_camel_case(const String &p_identifier, bool p_input_is_upper = false) {
String ret;
Vector<String> parts = p_identifier.split("_", true);
@@ -146,8 +152,13 @@ static String snake_to_camel_case(const String &p_identifier) {
String part = parts[i];
if (part.length()) {
- if (i != 0)
+ if (i != 0) {
part[0] = _find_upper(part[0]);
+ }
+ if (p_input_is_upper) {
+ for (int j = i != 0 ? 1 : 0; j < part.length(); j++)
+ part[j] = _find_lower(part[j]);
+ }
ret += part;
} else {
if (i == 0 || i == (parts.size() - 1)) {
@@ -167,12 +178,31 @@ static String snake_to_camel_case(const String &p_identifier) {
return ret;
}
+String BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
+
+ CRASH_COND(p_ienum.constants.empty());
+
+ const List<ConstantInterface>::Element *front = p_ienum.constants.front();
+ int candidate_len = front->get().name.length();
+
+ for (const List<ConstantInterface>::Element *E = front->next(); E; E = E->next()) {
+ int j = 0;
+ for (j = 0; j < candidate_len && j < E->get().name.length(); j++) {
+ if (front->get().name[j] != E->get().name[j])
+ break;
+ }
+ candidate_len = j;
+ }
+
+ return front->get().name.substr(0, candidate_len);
+}
+
void BindingsGenerator::_generate_header_icalls() {
core_custom_icalls.clear();
core_custom_icalls.push_back(InternalCall(ICALL_GET_METHODBIND, "IntPtr", "string type, string method"));
- core_custom_icalls.push_back(InternalCall(ICALL_OBJECT_DTOR, "void", "IntPtr ptr"));
+ core_custom_icalls.push_back(InternalCall(ICALL_OBJECT_DTOR, "void", "object obj, IntPtr ptr"));
core_custom_icalls.push_back(InternalCall(ICALL_CONNECT_SIGNAL_AWAITER, "Error",
"IntPtr source, string signal, IntPtr target, " CS_CLASS_SIGNALAWAITER " awaiter"));
@@ -220,7 +250,7 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
const TypeInterface *return_type = _get_type_by_name_or_placeholder(imethod.return_type);
String im_sig = "IntPtr " CS_PARAM_METHODBIND ", IntPtr " CS_PARAM_INSTANCE;
- String im_unique_sig = imethod.return_type + ",IntPtr,IntPtr";
+ String im_unique_sig = imethod.return_type.operator String() + ",IntPtr,IntPtr";
// Get arguments information
int i = 0;
@@ -256,6 +286,129 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
}
}
+void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
+
+ // Constants (in partial GD class)
+
+ p_output.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ p_output.push_back(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
+
+ for (const List<ConstantInterface>::Element *E = global_constants.front(); E; E = E->next()) {
+ const ConstantInterface &iconstant = E->get();
+
+ if (iconstant.const_doc && iconstant.const_doc->description.size()) {
+ p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
+
+ Vector<String> description_lines = iconstant.const_doc->description.split("\n");
+
+ for (int i = 0; i < description_lines.size(); i++) {
+ String description_line = description_lines[i].strip_edges();
+ if (description_line.size()) {
+ p_output.push_back(INDENT2 "/// ");
+ p_output.push_back(description_line.xml_escape());
+ p_output.push_back("\n");
+ }
+ }
+
+ p_output.push_back(INDENT2 "/// </summary>");
+ }
+
+ p_output.push_back(MEMBER_BEGIN "public const int ");
+ p_output.push_back(iconstant.name);
+ p_output.push_back(" = ");
+ p_output.push_back(itos(iconstant.value));
+ p_output.push_back(";");
+ }
+
+ if (!global_constants.empty())
+ p_output.push_back("\n");
+
+ p_output.push_back(INDENT1 CLOSE_BLOCK); // end of GD class
+
+ // Enums
+
+ for (List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) {
+ const EnumInterface &ienum = E->get();
+
+ CRASH_COND(ienum.constants.empty());
+
+ String enum_proxy_name = ienum.cname.operator String();
+
+ bool enum_in_static_class = false;
+
+ if (enum_proxy_name.find(".") > 0) {
+ enum_in_static_class = true;
+ String enum_class_name = enum_proxy_name.get_slicec('.', 0);
+ enum_proxy_name = enum_proxy_name.get_slicec('.', 1);
+
+ 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 + "`");
+ }
+
+ p_output.push_back("\n" INDENT1 "public static partial class ");
+ p_output.push_back(enum_class_name);
+ p_output.push_back("\n" INDENT1 OPEN_BLOCK);
+ }
+
+ p_output.push_back("\n" INDENT1 "public enum ");
+ p_output.push_back(enum_proxy_name);
+ p_output.push_back("\n" INDENT1 OPEN_BLOCK);
+
+ for (const List<ConstantInterface>::Element *E = ienum.constants.front(); E; E = E->next()) {
+ const ConstantInterface &iconstant = E->get();
+
+ if (iconstant.const_doc && iconstant.const_doc->description.size()) {
+ p_output.push_back(INDENT2 "/// <summary>\n");
+
+ Vector<String> description_lines = iconstant.const_doc->description.split("\n");
+
+ for (int i = 0; i < description_lines.size(); i++) {
+ String description_line = description_lines[i].strip_edges();
+ if (description_line.size()) {
+ p_output.push_back(INDENT2 "/// ");
+ p_output.push_back(description_line.xml_escape());
+ p_output.push_back("\n");
+ }
+ }
+
+ p_output.push_back(INDENT2 "/// </summary>\n");
+ }
+
+ String constant_name = iconstant.name;
+
+ if (!ienum.prefix.empty() && constant_name.begins_with(ienum.prefix)) {
+ constant_name = constant_name.substr(ienum.prefix.length(), constant_name.length());
+ }
+
+ if (constant_name[0] >= '0' && constant_name[0] <= '9') {
+ // The name of enum constants may begin with a numeric digit when strip from the enum prefix,
+ // so we make the prefix one word shorter in those cases.
+ int i = 0;
+ for (i = ienum.prefix.length() - 1; i >= 0; i--) {
+ if (ienum.prefix[i] >= 'A' && ienum.prefix[i] <= 'Z')
+ break;
+ }
+ constant_name = ienum.prefix.substr(i, ienum.prefix.length()) + constant_name;
+ }
+
+ p_output.push_back(INDENT2);
+ p_output.push_back(constant_name);
+ p_output.push_back(" = ");
+ p_output.push_back(itos(iconstant.value));
+ p_output.push_back(E != ienum.constants.back() ? ",\n" : "\n");
+ }
+
+ p_output.push_back(INDENT1 CLOSE_BLOCK);
+
+ if (enum_in_static_class)
+ p_output.push_back(INDENT1 CLOSE_BLOCK);
+ }
+
+ p_output.push_back(CLOSE_BLOCK); // end of namespace
+}
+
Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bool p_verbose_output) {
verbose_output = p_verbose_output;
@@ -282,7 +435,19 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
if (!solution.set_path(p_output_dir))
return ERR_FILE_NOT_FOUND;
- for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) {
+ // Generate source file for global scope constants and enums
+ {
+ List<String> constants_source;
+ _generate_global_constants(constants_source);
+ String output_file = path_join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs");
+ Error save_err = _save_file(output_file, constants_source);
+ if (save_err != OK)
+ return save_err;
+
+ compile_items.push_back(output_file);
+ }
+
+ for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) {
const TypeInterface &itype = E->get();
if (itype.api_type == ClassDB::API_EDITOR)
@@ -314,49 +479,6 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
#undef GENERATE_BUILTIN_TYPE
- // Generate source for GlobalConstants
-
- String constants_source;
- int global_constants_count = GlobalConstants::get_global_constant_count();
-
- if (global_constants_count > 0) {
- Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope");
-
- ERR_EXPLAIN("Could not find `@GlobalScope` in DocData");
- ERR_FAIL_COND_V(!match, ERR_BUG);
-
- const DocData::ClassDoc &global_scope_doc = match->value();
-
- for (int i = 0; i < global_constants_count; i++) {
- const DocData::ConstantDoc &const_doc = global_scope_doc.constants[i];
-
- if (i > 0)
- constants_source += MEMBER_BEGIN;
-
- if (const_doc.description.size()) {
- constants_source += "/// <summary>\n";
-
- Vector<String> description_lines = const_doc.description.split("\n");
-
- for (int i = 0; i < description_lines.size(); i++) {
- if (description_lines[i].size()) {
- constants_source += INDENT2 "/// ";
- constants_source += description_lines[i].strip_edges().xml_escape();
- constants_source += "\n";
- }
- }
-
- constants_source += INDENT2 "/// </summary>" MEMBER_BEGIN;
- }
-
- constants_source += "public const int ";
- constants_source += GlobalConstants::get_global_constant_name(i);
- constants_source += " = ";
- constants_source += itos(GlobalConstants::get_global_constant_value(i));
- constants_source += ";";
- }
- }
-
// Generate sources from compressed files
Map<String, CompressedFile> compressed_files;
@@ -372,19 +494,6 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
data.resize(file_data.uncompressed_size);
Compression::decompress(data.ptrw(), file_data.uncompressed_size, file_data.data, file_data.compressed_size, Compression::MODE_DEFLATE);
- if (file_name.get_basename() == BINDINGS_GLOBAL_SCOPE_CLASS) {
- // GD.cs must be formatted to include the generated global constants
- String data_str = String::utf8(reinterpret_cast<const char *>(data.ptr()), data.size());
-
- Dictionary format_keys;
- format_keys["GodotGlobalConstants"] = constants_source;
- data_str = data_str.format(format_keys, "/*{_}*/");
-
- CharString data_utf8 = data_str.utf8();
- data.resize(data_utf8.length());
- copymem(data.ptrw(), reinterpret_cast<const uint8_t *>(data_utf8.get_data()), data_utf8.length());
- }
-
FileAccessRef file = FileAccess::open(output_file, FileAccess::WRITE);
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
file->store_buffer(data.ptr(), data.size());
@@ -470,7 +579,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
if (!solution.set_path(p_output_dir))
return ERR_FILE_NOT_FOUND;
- for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) {
+ for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) {
const TypeInterface &itype = E->get();
if (itype.api_type != ClassDB::API_EDITOR)
@@ -543,7 +652,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
// e.g.: warning CS0108: 'SpriteBase3D.FLAG_MAX' hides inherited member 'GeometryInstance.FLAG_MAX'. Use the new keyword if hiding was intended.
Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const String &p_output_file) {
- bool is_derived_type = itype.base_name.length();
+ bool is_derived_type = itype.base_name != StringName();
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
@@ -569,9 +678,10 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
Vector<String> description_lines = class_doc->description.split("\n");
for (int i = 0; i < description_lines.size(); i++) {
- if (description_lines[i].size()) {
+ String description_line = description_lines[i].strip_edges();
+ if (description_line.size()) {
output.push_back(INDENT1 "/// ");
- output.push_back(description_lines[i].strip_edges().xml_escape());
+ output.push_back(description_line.xml_escape());
output.push_back("\n");
}
}
@@ -592,7 +702,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.push_back(obj_types[itype.base_name].proxy_name);
output.push_back("\n");
} else {
- ERR_PRINTS("Base type '" + itype.base_name + "' does not exist, for class " + itype.name);
+ ERR_PRINTS("Base type '" + itype.base_name.operator String() + "' does not exist, for class " + itype.name);
return ERR_INVALID_DATA;
}
@@ -602,18 +712,19 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Add constants
- for (int i = 0; i < class_doc->constants.size(); i++) {
- const DocData::ConstantDoc &const_doc = class_doc->constants[i];
+ for (const List<ConstantInterface>::Element *E = itype.constants.front(); E; E = E->next()) {
+ const ConstantInterface &iconstant = E->get();
- if (const_doc.description.size()) {
+ if (iconstant.const_doc && iconstant.const_doc->description.size()) {
output.push_back(MEMBER_BEGIN "/// <summary>\n");
- Vector<String> description_lines = const_doc.description.split("\n");
+ Vector<String> description_lines = iconstant.const_doc->description.split("\n");
for (int i = 0; i < description_lines.size(); i++) {
- if (description_lines[i].size()) {
+ String description_line = description_lines[i].strip_edges();
+ if (description_line.size()) {
output.push_back(INDENT2 "/// ");
- output.push_back(description_lines[i].strip_edges().xml_escape());
+ output.push_back(description_line.xml_escape());
output.push_back("\n");
}
}
@@ -622,24 +733,84 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
output.push_back(MEMBER_BEGIN "public const int ");
- output.push_back(const_doc.name);
+ output.push_back(iconstant.name);
output.push_back(" = ");
- output.push_back(const_doc.value);
+ output.push_back(itos(iconstant.value));
output.push_back(";");
}
- if (class_doc->constants.size())
+ if (itype.constants.size())
output.push_back("\n");
- // Add properties
+ // Add enums
- const Vector<DocData::PropertyDoc> &properties = class_doc->properties;
+ for (const List<EnumInterface>::Element *E = itype.enums.front(); E; E = E->next()) {
+ const EnumInterface &ienum = E->get();
+
+ ERR_FAIL_COND_V(ienum.constants.empty(), ERR_BUG);
+
+ output.push_back(MEMBER_BEGIN "public enum ");
+ output.push_back(ienum.cname.operator String());
+ output.push_back(MEMBER_BEGIN OPEN_BLOCK);
+
+ for (const List<ConstantInterface>::Element *E = ienum.constants.front(); E; E = E->next()) {
+ const ConstantInterface &iconstant = E->get();
+
+ if (iconstant.const_doc && iconstant.const_doc->description.size()) {
+ output.push_back(INDENT3 "/// <summary>\n");
+
+ Vector<String> description_lines = iconstant.const_doc->description.split("\n");
+
+ for (int i = 0; i < description_lines.size(); i++) {
+ String description_line = description_lines[i].strip_edges();
+ if (description_line.size()) {
+ output.push_back(INDENT3 "/// ");
+ output.push_back(description_line.xml_escape());
+ output.push_back("\n");
+ }
+ }
- for (int i = 0; i < properties.size(); i++) {
- const DocData::PropertyDoc &prop_doc = properties[i];
- Error prop_err = _generate_cs_property(itype, prop_doc, output);
+ output.push_back(INDENT3 "/// </summary>\n");
+ }
+
+ String constant_name = iconstant.name;
+
+ if (!ienum.prefix.empty() && constant_name.begins_with(ienum.prefix)) {
+ constant_name = constant_name.substr(ienum.prefix.length(), constant_name.length());
+ }
+
+ if (constant_name[0] >= '0' && constant_name[0] <= '9') {
+ // The name of enum constants may begin with a numeric digit when strip from the enum prefix,
+ // so we make the prefix one word shorter in those cases.
+ int i = 0;
+ for (i = ienum.prefix.length() - 1; i >= 0; i--) {
+ if (ienum.prefix[i] >= 'A' && ienum.prefix[i] <= 'Z')
+ break;
+ }
+ constant_name = ienum.prefix.substr(i, ienum.prefix.length()) + constant_name;
+ }
+
+ output.push_back(INDENT3);
+ output.push_back(constant_name);
+ output.push_back(" = ");
+ output.push_back(itos(iconstant.value));
+ output.push_back(E != ienum.constants.back() ? ",\n" : "\n");
+ }
+
+ output.push_back(INDENT2 CLOSE_BLOCK);
+ }
+
+ if (itype.enums.size())
+ output.push_back("\n");
+
+ // Add properties
+
+ for (const List<PropertyInterface>::Element *E = itype.properties.front(); E; E = E->next()) {
+ const PropertyInterface &iprop = E->get();
+ Error prop_err = _generate_cs_property(itype, iprop, output);
if (prop_err != OK) {
- ERR_EXPLAIN("Failed to generate property '" + prop_doc.name + "' for class '" + itype.name + "'");
+ ERR_EXPLAIN("Failed to generate property '" + iprop.cname.operator String() +
+ "' for class '" + itype.name + "'");
ERR_FAIL_V(prop_err);
}
}
@@ -762,18 +933,18 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
"if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3
"if (" CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L4 CS_FIELD_MEMORYOWN
" = false;\n" INDENT5 CS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
- "(" BINDINGS_PTR_FIELD ");\n" INDENT5 BINDINGS_PTR_FIELD
- " = IntPtr.Zero;\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3
+ "(this, " BINDINGS_PTR_FIELD ");\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3
+ "this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" INDENT3
"GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
- Map<String, TypeInterface>::Element *array_itype = builtin_types.find("Array");
+ Map<StringName, TypeInterface>::Element *array_itype = builtin_types.find(name_cache.type_Array);
if (!array_itype) {
ERR_PRINT("BUG: Array type interface not found!");
return ERR_BUG;
}
- Map<String, TypeInterface>::Element *object_itype = obj_types.find("Object");
+ Map<StringName, TypeInterface>::Element *object_itype = obj_types.find("Object");
if (!object_itype) {
ERR_PRINT("BUG: Object type interface not found!");
@@ -787,7 +958,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
}
- Map<String, String>::Element *extra_member = extra_members.find(itype.name);
+ Map<StringName, String>::Element *extra_member = extra_members.find(itype.cname);
if (extra_member)
output.push_back(extra_member->get());
@@ -820,43 +991,39 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
return _save_file(p_output_file, output);
}
-Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInterface &p_itype, const DocData::PropertyDoc &p_prop_doc, List<String> &p_output) {
+Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInterface &p_itype, const PropertyInterface &p_iprop, List<String> &p_output) {
- const MethodInterface *setter = p_itype.find_method_by_name(p_prop_doc.setter);
+ const MethodInterface *setter = p_itype.find_method_by_name(p_iprop.setter);
// Search it in base types too
const TypeInterface *current_type = &p_itype;
- while (!setter && current_type->base_name.length()) {
- Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
+ while (!setter && current_type->base_name != StringName()) {
+ Map<StringName, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
ERR_FAIL_NULL_V(base_match, ERR_BUG);
current_type = &base_match->get();
- setter = current_type->find_method_by_name(p_prop_doc.setter);
+ setter = current_type->find_method_by_name(p_iprop.setter);
}
- const MethodInterface *getter = p_itype.find_method_by_name(p_prop_doc.getter);
+ const MethodInterface *getter = p_itype.find_method_by_name(p_iprop.getter);
// Search it in base types too
current_type = &p_itype;
- while (!getter && current_type->base_name.length()) {
- Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
+ while (!getter && current_type->base_name != StringName()) {
+ Map<StringName, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
ERR_FAIL_NULL_V(base_match, ERR_BUG);
current_type = &base_match->get();
- getter = current_type->find_method_by_name(p_prop_doc.getter);
+ getter = current_type->find_method_by_name(p_iprop.getter);
}
ERR_FAIL_COND_V(!setter && !getter, ERR_BUG);
- bool is_valid = false;
- int prop_index = ClassDB::get_property_index(p_itype.name, p_prop_doc.name, &is_valid);
- ERR_FAIL_COND_V(!is_valid, ERR_BUG);
-
if (setter) {
- int setter_argc = prop_index != -1 ? 2 : 1;
+ int setter_argc = p_iprop.index != -1 ? 2 : 1;
ERR_FAIL_COND_V(setter->arguments.size() != setter_argc, ERR_BUG);
}
if (getter) {
- int getter_argc = prop_index != -1 ? 1 : 0;
+ int getter_argc = p_iprop.index != -1 ? 1 : 0;
ERR_FAIL_COND_V(getter->arguments.size() != getter_argc, ERR_BUG);
}
@@ -864,18 +1031,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
ERR_FAIL_COND_V(getter->return_type != setter->arguments.back()->get().type, ERR_BUG);
}
- // Let's not trust PropertyDoc::type
- String proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type;
+ StringName proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type;
const TypeInterface *prop_itype = _get_type_by_name_or_null(proptype_name);
- if (!prop_itype) {
- // Try with underscore prefix
- prop_itype = _get_type_by_name_or_null("_" + proptype_name);
- }
-
- ERR_FAIL_NULL_V(prop_itype, ERR_BUG);
+ ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found
- String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_prop_doc.name));
+ String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname));
// Prevent property and enclosing type from sharing the same name
if (prop_proxy_name == p_itype.proxy_name) {
@@ -887,15 +1048,16 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
prop_proxy_name += "_";
}
- if (p_prop_doc.description.size()) {
+ if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) {
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
- Vector<String> description_lines = p_prop_doc.description.split("\n");
+ Vector<String> description_lines = p_iprop.prop_doc->description.split("\n");
for (int i = 0; i < description_lines.size(); i++) {
- if (description_lines[i].size()) {
+ String description_line = description_lines[i].strip_edges();
+ if (description_line.size()) {
p_output.push_back(INDENT2 "/// ");
- p_output.push_back(description_lines[i].strip_edges().xml_escape());
+ p_output.push_back(description_line.xml_escape());
p_output.push_back("\n");
}
}
@@ -917,16 +1079,34 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.push_back(INDENT3 "get\n" OPEN_BLOCK_L3);
p_output.push_back("return ");
p_output.push_back(getter->proxy_name + "(");
- if (prop_index != -1)
- p_output.push_back(itos(prop_index));
+ if (p_iprop.index != -1) {
+ const ArgumentInterface &idx_arg = getter->arguments.front()->get();
+ if (idx_arg.type != name_cache.type_int) {
+ // Assume the index parameter is an enum
+ const TypeInterface *idx_arg_type = _get_type_by_name_or_null(idx_arg.type);
+ CRASH_COND(idx_arg_type == NULL);
+ p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index));
+ } else {
+ p_output.push_back(itos(p_iprop.index));
+ }
+ }
p_output.push_back(");\n" CLOSE_BLOCK_L3);
}
if (setter) {
p_output.push_back(INDENT3 "set\n" OPEN_BLOCK_L3);
p_output.push_back(setter->proxy_name + "(");
- if (prop_index != -1)
- p_output.push_back(itos(prop_index) + ", ");
+ if (p_iprop.index != -1) {
+ const ArgumentInterface &idx_arg = setter->arguments.front()->get();
+ if (idx_arg.type != name_cache.type_int) {
+ // Assume the index parameter is an enum
+ const TypeInterface *idx_arg_type = _get_type_by_name_or_null(idx_arg.type);
+ CRASH_COND(idx_arg_type == NULL);
+ p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index) + ", ");
+ } else {
+ p_output.push_back(itos(p_iprop.index) + ", ");
+ }
+ }
p_output.push_back("value);\n" CLOSE_BLOCK_L3);
}
@@ -1033,9 +1213,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
Vector<String> description_lines = p_imethod.method_doc->description.split("\n");
for (int i = 0; i < description_lines.size(); i++) {
- if (description_lines[i].size()) {
+ String description_line = description_lines[i].strip_edges();
+ if (description_line.size()) {
p_output.push_back(INDENT2 "/// ");
- p_output.push_back(description_lines[i].strip_edges().xml_escape());
+ p_output.push_back(description_line.xml_escape());
p_output.push_back("\n");
}
}
@@ -1069,7 +1250,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
if (p_imethod.is_virtual) {
// Godot virtual method must be overridden, therefore we return a default value by default.
- if (return_type->name == "void") {
+ if (return_type->cname == name_cache.type_void) {
p_output.push_back("return;\n" CLOSE_BLOCK_L2);
} else {
p_output.push_back("return default(");
@@ -1108,7 +1289,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
if (p_imethod.arguments.size())
p_output.push_back(cs_in_statements);
- if (return_type->name == "void") {
+ if (return_type->cname == name_cache.type_void) {
p_output.push_back(im_call);
} else if (return_type->cs_out.empty()) {
p_output.push_back("return " + im_call);
@@ -1142,7 +1323,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
generated_icall_funcs.clear();
- for (Map<String, TypeInterface>::Element *type_elem = obj_types.front(); type_elem; type_elem = type_elem->next()) {
+ for (Map<StringName, TypeInterface>::Element *type_elem = obj_types.front(); type_elem; type_elem = type_elem->next()) {
const TypeInterface &itype = type_elem->get();
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
@@ -1295,7 +1476,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
if (p_imethod.is_virtual)
return OK; // Ignore
- bool ret_void = p_imethod.return_type == "void";
+ bool ret_void = p_imethod.return_type == name_cache.type_void;
const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type);
@@ -1447,14 +1628,19 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
return OK;
}
-const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const String &p_name) {
+const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const StringName &p_cname) {
+
+ const Map<StringName, TypeInterface>::Element *match = builtin_types.find(p_cname);
+
+ if (match)
+ return &match->get();
- const Map<String, TypeInterface>::Element *match = builtin_types.find(p_name);
+ match = obj_types.find(p_cname);
if (match)
return &match->get();
- match = obj_types.find(p_name);
+ match = enum_types.find(p_cname);
if (match)
return &match->get();
@@ -1462,24 +1648,27 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_
return NULL;
}
-const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_placeholder(const String &p_name) {
+const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_placeholder(const StringName &p_cname) {
- const TypeInterface *found = _get_type_by_name_or_null(p_name);
+ const TypeInterface *found = _get_type_by_name_or_null(p_cname);
if (found)
return found;
- ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_name);
+ ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_cname.operator String());
- const Map<String, TypeInterface>::Element *match = placeholder_types.find(p_name);
+ const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_cname);
if (match)
return &match->get();
TypeInterface placeholder;
- TypeInterface::create_placeholder_type(placeholder, p_name);
+ TypeInterface::create_placeholder_type(placeholder, p_cname);
+
+ return &placeholder_types.insert(placeholder.cname, placeholder)->get();
+}
- return &placeholder_types.insert(placeholder.name, placeholder)->get();
+static void _create_constant_interface_from(const StringName &p_constant, const DocData::ClassDoc &p_classdoc) {
}
void BindingsGenerator::_populate_object_type_interfaces() {
@@ -1490,8 +1679,6 @@ void BindingsGenerator::_populate_object_type_interfaces() {
ClassDB::get_class_list(&class_list);
class_list.sort_custom<StringName::AlphCompare>();
- StringName refclass_name = String("Reference");
-
while (class_list.size()) {
StringName type_cname = class_list.front()->get();
@@ -1502,21 +1689,23 @@ void BindingsGenerator::_populate_object_type_interfaces() {
continue;
}
+ if (!ClassDB::is_class_exposed(type_cname)) {
+ if (verbose_output)
+ WARN_PRINTS("Ignoring type " + type_cname.operator String() + " because it's not exposed");
+ class_list.pop_front();
+ continue;
+ }
+
+ ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(type_cname);
+
TypeInterface itype = TypeInterface::create_object_type(type_cname, api_type);
itype.base_name = ClassDB::get_parent_class(type_cname);
itype.is_singleton = Engine::get_singleton()->has_singleton(itype.proxy_name);
itype.is_instantiable = ClassDB::can_instance(type_cname) && !itype.is_singleton;
- itype.is_reference = ClassDB::is_parent_class(type_cname, refclass_name);
+ itype.is_reference = ClassDB::is_parent_class(type_cname, name_cache.type_Reference);
itype.memory_own = itype.is_reference;
- if (!ClassDB::is_class_exposed(type_cname)) {
- if (verbose_output)
- WARN_PRINTS("Ignoring type " + String(type_cname) + " because it's not exposed");
- class_list.pop_front();
- continue;
- }
-
itype.c_out = "\treturn ";
itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED;
itype.c_out += itype.is_reference ? "(%1.ptr());\n" : "(%1);\n";
@@ -1530,6 +1719,53 @@ void BindingsGenerator::_populate_object_type_interfaces() {
itype.im_type_in = "IntPtr";
itype.im_type_out = itype.proxy_name;
+ List<PropertyInfo> property_list;
+ ClassDB::get_property_list(type_cname, &property_list, true);
+
+ // Populate properties
+
+ for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
+ const PropertyInfo &property = E->get();
+
+ if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_CATEGORY)
+ continue;
+
+ PropertyInterface iprop;
+ iprop.cname = property.name;
+ iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
+ iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname);
+ iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname);
+
+ bool valid = false;
+ iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid);
+ ERR_FAIL_COND(!valid);
+
+ // Prevent property and 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 + "_`");
+ }
+
+ iprop.proxy_name += "_";
+ }
+
+ iprop.prop_doc = NULL;
+
+ for (int i = 0; i < itype.class_doc->properties.size(); i++) {
+ const DocData::PropertyDoc &prop_doc = itype.class_doc->properties[i];
+
+ if (prop_doc.name == iprop.cname) {
+ iprop.prop_doc = &prop_doc;
+ break;
+ }
+ }
+
+ itype.properties.push_back(iprop);
+ }
+
+ // Populate methods
+
List<MethodInfo> virtual_method_list;
ClassDB::get_virtual_methods(type_cname, &virtual_method_list, true);
@@ -1547,6 +1783,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
MethodInterface imethod;
imethod.name = method_info.name;
+ imethod.cname = imethod.name;
if (method_info.flags & METHOD_FLAG_VIRTUAL)
imethod.is_virtual = true;
@@ -1570,12 +1807,12 @@ void BindingsGenerator::_populate_object_type_interfaces() {
// The method Object.free is registered as a virtual method, but without the virtual flag.
// This is because this method is not supposed to be overridden, but called.
// We assume the return type is void.
- imethod.return_type = "void";
+ imethod.return_type = name_cache.type_void;
// Actually, more methods like this may be added in the future,
// which could actually will return something differnet.
// Let's put this to notify us if that ever happens.
- if (itype.name != "Object" || imethod.name != "free") {
+ 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 " +
@@ -1585,22 +1822,21 @@ void BindingsGenerator::_populate_object_type_interfaces() {
} else {
ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
}
- } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
- //imethod.return_type = return_info.class_name;
- imethod.return_type = "int";
+ } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { // TODO redundant?
+ imethod.return_type = return_info.class_name;
} else if (return_info.class_name != StringName()) {
imethod.return_type = return_info.class_name;
} else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
imethod.return_type = return_info.hint_string;
} else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
- imethod.return_type = "Variant";
+ imethod.return_type = name_cache.type_Variant;
} else if (return_info.type == Variant::NIL) {
- imethod.return_type = "void";
+ imethod.return_type = name_cache.type_void;
} else {
imethod.return_type = Variant::get_type_name(return_info.type);
}
- if (!itype.requires_collections && imethod.return_type == "Dictionary")
+ if (!itype.requires_collections && imethod.return_type == name_cache.type_Dictionary)
itype.requires_collections = true;
for (int i = 0; i < argc; i++) {
@@ -1609,22 +1845,21 @@ void BindingsGenerator::_populate_object_type_interfaces() {
ArgumentInterface iarg;
iarg.name = arginfo.name;
- if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
- //iarg.type = arginfo.class_name;
- iarg.type = "int";
+ if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { // TODO redundant?
+ iarg.type = arginfo.class_name;
} else if (arginfo.class_name != StringName()) {
iarg.type = arginfo.class_name;
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type = arginfo.hint_string;
} else if (arginfo.type == Variant::NIL) {
- iarg.type = "Variant";
+ iarg.type = name_cache.type_Variant;
} else {
iarg.type = Variant::get_type_name(arginfo.type);
}
iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
- if (!itype.requires_collections && iarg.type == "Dictionary")
+ if (!itype.requires_collections && iarg.type == name_cache.type_Dictionary)
itype.requires_collections = true;
if (m && m->has_default_argument(i)) {
@@ -1636,7 +1871,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
if (imethod.is_vararg) {
ArgumentInterface ivararg;
- ivararg.type = "VarArg";
+ ivararg.type = name_cache.type_VarArg;
ivararg.name = "@args";
imethod.add_argument(ivararg);
}
@@ -1663,12 +1898,10 @@ void BindingsGenerator::_populate_object_type_interfaces() {
}
if (!imethod.is_virtual && imethod.name[0] == '_') {
- const Vector<DocData::PropertyDoc> &properties = itype.class_doc->properties;
-
- for (int i = 0; i < properties.size(); i++) {
- const DocData::PropertyDoc &prop_doc = properties[i];
+ for (const List<PropertyInterface>::Element *E = itype.properties.front(); E; E = E->next()) {
+ const PropertyInterface &iprop = E->get();
- if (prop_doc.getter == imethod.name || prop_doc.setter == imethod.name) {
+ if (iprop.setter == imethod.name || iprop.getter == imethod.name) {
imethod.is_internal = true;
itype.methods.push_back(imethod);
break;
@@ -1679,7 +1912,84 @@ void BindingsGenerator::_populate_object_type_interfaces() {
}
}
- obj_types.insert(itype.name, itype);
+ // Populate enums and constants
+
+ List<String> constant_list;
+ ClassDB::get_integer_constant_list(type_cname, &constant_list, true);
+
+ const HashMap<StringName, List<StringName> > &enum_map = class_info->enum_map;
+ const StringName *k = NULL;
+
+ while ((k = enum_map.next(k))) {
+ StringName enum_proxy_cname = *k;
+ String enum_proxy_name = enum_proxy_cname.operator String();
+ if (itype.find_property_by_proxy_name(enum_proxy_cname)) {
+ // We have several conflicts between enums and PascalCase properties,
+ // so we append 'Enum' to the enum name in those cases.
+ enum_proxy_name += "Enum";
+ enum_proxy_cname = StringName(enum_proxy_name);
+ }
+ EnumInterface ienum(enum_proxy_cname);
+ const List<StringName> &constants = enum_map.get(*k);
+ for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) {
+ int *value = class_info->constant_map.getptr(E->get());
+ ERR_FAIL_NULL(value);
+ constant_list.erase(E->get().operator String());
+
+ ConstantInterface iconstant(snake_to_pascal_case(E->get(), true), *value);
+
+ iconstant.const_doc = NULL;
+ for (int i = 0; i < itype.class_doc->constants.size(); i++) {
+ const DocData::ConstantDoc &const_doc = itype.class_doc->constants[i];
+
+ if (const_doc.name == iconstant.name) {
+ iconstant.const_doc = &const_doc;
+ break;
+ }
+ }
+
+ ienum.constants.push_back(iconstant);
+ }
+
+ ienum.prefix = _determine_enum_prefix(ienum);
+
+ itype.enums.push_back(ienum);
+
+ TypeInterface enum_itype;
+ enum_itype.name = itype.name + "." + String(*k);
+ enum_itype.cname = StringName(enum_itype.name);
+ enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name;
+ enum_itype.c_arg_in = "&%s";
+ enum_itype.c_type = "int";
+ enum_itype.c_type_in = "int";
+ enum_itype.c_type_out = "int";
+ enum_itype.cs_type = enum_itype.proxy_name;
+ enum_itype.im_type_in = enum_itype.proxy_name;
+ enum_itype.im_type_out = enum_itype.proxy_name;
+ enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[enum_itype.proxy_name];
+ enum_types.insert(enum_itype.cname, enum_itype);
+ }
+
+ for (const List<String>::Element *E = constant_list.front(); E; E = E->next()) {
+ int *value = class_info->constant_map.getptr(E->get());
+ ERR_FAIL_NULL(value);
+
+ ConstantInterface iconstant(snake_to_pascal_case(E->get(), true), *value);
+
+ iconstant.const_doc = NULL;
+ for (int i = 0; i < itype.class_doc->constants.size(); i++) {
+ const DocData::ConstantDoc &const_doc = itype.class_doc->constants[i];
+
+ if (const_doc.name == iconstant.name) {
+ iconstant.const_doc = &const_doc;
+ break;
+ }
+ }
+
+ itype.constants.push_back(iconstant);
+ }
+
+ obj_types.insert(itype.cname, itype);
class_list.pop_front();
}
@@ -1704,7 +2014,10 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg
r_iarg.default_argument = bool(p_val) ? "true" : "false";
break;
case Variant::INT:
- break; // Keep it
+ if (r_iarg.type != name_cache.type_int) {
+ r_iarg.default_argument = "(%s)" + r_iarg.default_argument;
+ }
+ break;
case Variant::REAL:
#ifndef REAL_T_IS_DOUBLE
r_iarg.default_argument += "f";
@@ -1762,7 +2075,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg
default: {}
}
- if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type == "Variant" && r_iarg.default_argument != "null")
+ if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type == name_cache.type_Variant && r_iarg.default_argument != "null")
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
}
@@ -1774,7 +2087,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
#define INSERT_STRUCT_TYPE(m_type, m_type_in) \
{ \
- itype = TypeInterface::create_value_type(#m_type); \
+ itype = TypeInterface::create_value_type(String(#m_type)); \
itype.c_in = "\tMARSHALLED_IN(" #m_type ", %1, %1_in);\n"; \
itype.c_out = "\tMARSHALLED_OUT(" #m_type ", %1, ret_out)\n" \
"\treturn mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(%2), ret_out);\n"; \
@@ -1783,7 +2096,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cs_in = "ref %s"; \
itype.cs_out = "return (" #m_type ")%0;"; \
itype.im_type_out = "object"; \
- builtin_types.insert(#m_type, itype); \
+ builtin_types.insert(itype.cname, itype); \
}
INSERT_STRUCT_TYPE(Vector2, "real_t*")
@@ -1799,22 +2112,22 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
#undef INSERT_STRUCT_TYPE
-#define INSERT_PRIMITIVE_TYPE(m_type) \
- { \
- itype = TypeInterface::create_value_type(#m_type); \
- itype.c_arg_in = "&%s"; \
- itype.c_type_in = #m_type; \
- itype.c_type_out = #m_type; \
- itype.im_type_in = #m_type; \
- itype.im_type_out = #m_type; \
- builtin_types.insert(#m_type, itype); \
+#define INSERT_PRIMITIVE_TYPE(m_type) \
+ { \
+ itype = TypeInterface::create_value_type(String(#m_type)); \
+ itype.c_arg_in = "&%s"; \
+ itype.c_type_in = #m_type; \
+ itype.c_type_out = #m_type; \
+ itype.im_type_in = #m_type; \
+ itype.im_type_out = #m_type; \
+ builtin_types.insert(itype.cname, itype); \
}
INSERT_PRIMITIVE_TYPE(bool)
//INSERT_PRIMITIVE_TYPE(int)
// int
- itype = TypeInterface::create_value_type("int");
+ itype = TypeInterface::create_value_type(String("int"));
itype.c_arg_in = "&%s_in";
//* ptrcall only supports int64_t and uint64_t
itype.c_in = "\t%0 %1_in = (%0)%1;\n";
@@ -1825,7 +2138,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.name;
itype.im_type_in = itype.name;
itype.im_type_out = itype.name;
- builtin_types.insert(itype.name, itype);
+ builtin_types.insert(itype.cname, itype);
#undef INSERT_PRIMITIVE_TYPE
@@ -1836,6 +2149,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
#else
itype.name = "float";
#endif
+ itype.cname = itype.name;
itype.proxy_name = itype.name;
itype.c_arg_in = "&%s_in";
//* ptrcall only supports double
@@ -1848,11 +2162,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cs_type = itype.proxy_name;
itype.im_type_in = itype.proxy_name;
itype.im_type_out = itype.proxy_name;
- builtin_types.insert(itype.name, itype);
+ builtin_types.insert(itype.cname, itype);
// String
itype = TypeInterface();
itype.name = "String";
+ itype.cname = itype.name;
itype.proxy_name = "string";
itype.c_in = "\t%0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n";
itype.c_out = "\treturn " C_METHOD_MONOSTR_FROM_GODOT "(%1);\n";
@@ -1863,11 +2178,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cs_type = itype.proxy_name;
itype.im_type_in = itype.proxy_name;
itype.im_type_out = itype.proxy_name;
- builtin_types.insert(itype.name, itype);
+ builtin_types.insert(itype.cname, itype);
// NodePath
itype = TypeInterface();
itype.name = "NodePath";
+ itype.cname = itype.name;
itype.proxy_name = "NodePath";
itype.c_out = "\treturn memnew(NodePath(%1));\n";
itype.c_type = itype.name;
@@ -1879,16 +2195,17 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_in = "IntPtr";
itype.im_type_out = "IntPtr";
_populate_builtin_type(itype, Variant::NODE_PATH);
- extra_members.insert(itype.name, MEMBER_BEGIN "public NodePath() : this(string.Empty) {}\n" MEMBER_BEGIN "public NodePath(string path)\n" OPEN_BLOCK_L2
- "this." BINDINGS_PTR_FIELD " = NativeCalls.godot_icall_NodePath_Ctor(path);\n" CLOSE_BLOCK_L2
- MEMBER_BEGIN "public static implicit operator NodePath(string from)\n" OPEN_BLOCK_L2 "return new NodePath(from);\n" CLOSE_BLOCK_L2
- MEMBER_BEGIN "public static implicit operator string(NodePath from)\n" OPEN_BLOCK_L2
- "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2);
- builtin_types.insert(itype.name, itype);
+ extra_members.insert(itype.cname, MEMBER_BEGIN "public NodePath() : this(string.Empty) {}\n" MEMBER_BEGIN "public NodePath(string path)\n" OPEN_BLOCK_L2
+ "this." BINDINGS_PTR_FIELD " = NativeCalls.godot_icall_NodePath_Ctor(path);\n" CLOSE_BLOCK_L2
+ MEMBER_BEGIN "public static implicit operator NodePath(string from)\n" OPEN_BLOCK_L2 "return new NodePath(from);\n" CLOSE_BLOCK_L2
+ MEMBER_BEGIN "public static implicit operator string(NodePath from)\n" OPEN_BLOCK_L2
+ "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2);
+ builtin_types.insert(itype.cname, itype);
// RID
itype = TypeInterface();
itype.name = "RID";
+ itype.cname = itype.name;
itype.proxy_name = "RID";
itype.c_out = "\treturn memnew(RID(%1));\n";
itype.c_type = itype.name;
@@ -1900,13 +2217,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_in = "IntPtr";
itype.im_type_out = "IntPtr";
_populate_builtin_type(itype, Variant::_RID);
- extra_members.insert(itype.name, MEMBER_BEGIN "internal RID()\n" OPEN_BLOCK_L2
- "this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L2);
- builtin_types.insert(itype.name, itype);
+ extra_members.insert(itype.cname, MEMBER_BEGIN "internal RID()\n" OPEN_BLOCK_L2
+ "this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L2);
+ builtin_types.insert(itype.cname, itype);
// Variant
itype = TypeInterface();
itype.name = "Variant";
+ itype.cname = itype.name;
itype.proxy_name = "object";
itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_VARIANT "(%1);\n";
itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_VARIANT "(%1);\n";
@@ -1917,11 +2235,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cs_type = itype.proxy_name;
itype.im_type_in = "object";
itype.im_type_out = itype.proxy_name;
- builtin_types.insert(itype.name, itype);
+ builtin_types.insert(itype.cname, itype);
// VarArg (fictitious type to represent variable arguments)
itype = TypeInterface();
itype.name = "VarArg";
+ itype.cname = itype.name;
itype.proxy_name = "object[]";
itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(Array) "(%1);\n";
itype.c_arg_in = "&%s_in";
@@ -1929,12 +2248,13 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_in = "MonoArray*";
itype.cs_type = "params object[]";
itype.im_type_in = "object[]";
- builtin_types.insert(itype.name, itype);
+ builtin_types.insert(itype.cname, itype);
#define INSERT_ARRAY_FULL(m_name, m_type, m_proxy_t) \
{ \
itype = TypeInterface(); \
itype.name = #m_name; \
+ itype.cname = itype.name; \
itype.proxy_name = #m_proxy_t "[]"; \
itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \
itype.c_out = "\treturn " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
@@ -1971,6 +2291,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// Dictionary
itype = TypeInterface();
itype.name = "Dictionary";
+ itype.cname = itype.name;
itype.proxy_name = "Dictionary<object, object>";
itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_DICT "(%1);\n";
itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_DICT "(%1);\n";
@@ -1981,11 +2302,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cs_type = itype.proxy_name;
itype.im_type_in = itype.proxy_name;
itype.im_type_out = itype.proxy_name;
- builtin_types.insert(itype.name, itype);
+ builtin_types.insert(itype.cname, itype);
// void (fictitious type to represent the return type of methods that do not return anything)
itype = TypeInterface();
itype.name = "void";
+ itype.cname = itype.name;
itype.proxy_name = itype.name;
itype.c_type = itype.name;
itype.c_type_in = itype.c_type;
@@ -1993,21 +2315,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cs_type = itype.proxy_name;
itype.im_type_in = itype.proxy_name;
itype.im_type_out = itype.proxy_name;
- builtin_types.insert(itype.name, itype);
-
- // Error
- itype = TypeInterface();
- itype.name = "Error";
- itype.proxy_name = "Error";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type;
- itype.c_type_out = itype.c_type;
- itype.cs_type = itype.proxy_name;
- itype.cs_in = "(int)%0";
- itype.cs_out = "return (Error)%s;";
- itype.im_type_in = "int";
- itype.im_type_out = "int";
- builtin_types.insert(itype.name, itype);
+ builtin_types.insert(itype.cname, itype);
}
void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::Type vtype) {
@@ -2024,6 +2332,7 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::
MethodInterface imethod;
imethod.name = mi.name;
+ imethod.cname = imethod.name;
imethod.proxy_name = mi.name;
for (int i = 0; i < mi.arguments.size(); i++) {
@@ -2033,11 +2342,11 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::
iarg.name = pi.name;
if (pi.type == Variant::NIL)
- iarg.type = "Variant";
+ iarg.type = name_cache.type_Variant;
else
iarg.type = Variant::get_type_name(pi.type);
- if (!r_itype.requires_collections && iarg.type == "Dictionary")
+ if (!r_itype.requires_collections && iarg.type == name_cache.type_Dictionary)
r_itype.requires_collections = true;
if ((mi.default_arguments.size() - mi.arguments.size() + i) >= 0)
@@ -2048,12 +2357,12 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::
if (mi.return_val.type == Variant::NIL) {
if (mi.return_val.name != "")
- imethod.return_type = "Variant";
+ imethod.return_type = name_cache.type_Variant;
} else {
imethod.return_type = Variant::get_type_name(mi.return_val.type);
}
- if (!r_itype.requires_collections && imethod.return_type == "Dictionary")
+ if (!r_itype.requires_collections && imethod.return_type == name_cache.type_Dictionary)
r_itype.requires_collections = true;
if (r_itype.class_doc) {
@@ -2069,15 +2378,112 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::
}
}
-BindingsGenerator::BindingsGenerator() {
+void BindingsGenerator::_populate_global_constants() {
+
+ int global_constants_count = GlobalConstants::get_global_constant_count();
+
+ if (global_constants_count > 0) {
+ Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope");
+
+ ERR_EXPLAIN("Could not find `@GlobalScope` in DocData");
+ CRASH_COND(!match);
+
+ const DocData::ClassDoc &global_scope_doc = match->value();
+
+ for (int i = 0; i < global_constants_count; i++) {
+
+ String constant_name = GlobalConstants::get_global_constant_name(i);
+
+ const DocData::ConstantDoc *const_doc = NULL;
+ for (int i = 0; i < global_scope_doc.constants.size(); i++) {
+ const DocData::ConstantDoc &curr_const_doc = global_scope_doc.constants[i];
+
+ if (curr_const_doc.name == constant_name) {
+ const_doc = &curr_const_doc;
+ break;
+ }
+ }
+
+ int constant_value = GlobalConstants::get_global_constant_value(i);
+ StringName enum_name = GlobalConstants::get_global_constant_enum(i);
+
+ ConstantInterface iconstant(snake_to_pascal_case(constant_name, true), constant_value);
+ iconstant.const_doc = const_doc;
+
+ if (enum_name != StringName()) {
+ EnumInterface ienum(enum_name);
+ List<EnumInterface>::Element *match = global_enums.find(ienum);
+ if (match) {
+ match->get().constants.push_back(iconstant);
+ } else {
+ ienum.constants.push_back(iconstant);
+ global_enums.push_back(ienum);
+ }
+ } else {
+ global_constants.push_back(iconstant);
+ }
+ }
+
+ for (List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) {
+ EnumInterface &ienum = E->get();
+
+ TypeInterface enum_itype;
+ enum_itype = TypeInterface::create_value_type(ienum.cname);
+ enum_itype.c_arg_in = "&%s";
+ enum_itype.c_type = "int";
+ enum_itype.c_type_in = "int";
+ enum_itype.c_type_out = "int";
+ enum_itype.im_type_in = enum_itype.name;
+ enum_itype.im_type_out = enum_itype.name;
+ enum_types.insert(enum_itype.cname, enum_itype);
+
+ ienum.prefix = _determine_enum_prefix(ienum);
+
+ // HARDCODED
+ if (ienum.cname == name_cache.enum_Error) {
+ if (!ienum.prefix.empty()) { // Just in case it ever changes
+ ERR_PRINTS("Prefix for enum 'Error' is not empty");
+ }
+
+ ienum.prefix = "Err";
+ }
+ }
+ }
+
+ // HARDCODED
+ List<StringName> hardcoded_enums;
+ hardcoded_enums.push_back("Vector3.Axis");
+ for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) {
+ // These enums are not generated and must be written manually (e.g.: Vector3.Axis)
+ // Here, we are assuming core types do not begin with underscore
+ TypeInterface enum_itype;
+ enum_itype = TypeInterface::create_value_type(E->get());
+ enum_itype.c_arg_in = "&%s";
+ enum_itype.c_type = "int";
+ enum_itype.c_type_in = "int";
+ enum_itype.c_type_out = "int";
+ enum_itype.im_type_in = enum_itype.name;
+ enum_itype.im_type_out = enum_itype.name;
+ enum_types.insert(enum_itype.cname, enum_itype);
+ }
+}
+
+void BindingsGenerator::initialize() {
EditorHelp::generate_doc();
+ enum_types.clear();
+
_populate_object_type_interfaces();
_populate_builtin_type_interfaces();
+
+ _populate_global_constants();
+
+ // Populate internal calls (after populating type interfaces and global constants)
+
_generate_header_icalls();
- for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next())
+ for (Map<StringName, TypeInterface>::Element *E = obj_types.front(); E; E = E->next())
_generate_method_icalls(E->get());
_generate_method_icalls(builtin_types["NodePath"]);
@@ -2104,7 +2510,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)
+ if (get_singleton()->generate_glue(path_elem->get()) != OK)
ERR_PRINT("Mono glue generation failed");
elem = elem->next();
} else {
@@ -2118,7 +2524,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_core_project(path_elem->get()) != OK)
+ if (get_singleton()->generate_cs_core_project(path_elem->get()) != OK)
ERR_PRINT("Generation of solution and C# project for the Core API failed");
elem = elem->next();
} else {
@@ -2133,7 +2539,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
if (path_elem) {
if (path_elem->next()) {
- if (get_singleton().generate_cs_editor_project(path_elem->get(), path_elem->next()->get()) != OK)
+ if (get_singleton()->generate_cs_editor_project(path_elem->get(), path_elem->next()->get()) != OK)
ERR_PRINT("Generation of solution and C# project for the Editor API failed");
elem = path_elem->next();
} else {
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index dfa3aa9911..5934f3f27f 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -39,6 +39,47 @@
#include "ustring.h"
class BindingsGenerator {
+
+ struct ConstantInterface {
+ String name;
+ int value;
+ const DocData::ConstantDoc *const_doc;
+
+ ConstantInterface() {}
+
+ ConstantInterface(const String &p_name, int p_value) {
+ name = p_name;
+ value = p_value;
+ }
+ };
+
+ struct EnumInterface {
+ StringName cname;
+ String prefix;
+ List<ConstantInterface> constants;
+
+ _FORCE_INLINE_ bool operator==(const EnumInterface &p_ienum) const {
+ return p_ienum.cname == cname;
+ }
+
+ EnumInterface() {}
+
+ EnumInterface(const StringName &p_cname) {
+ cname = p_cname;
+ }
+ };
+
+ struct PropertyInterface {
+ StringName cname;
+ String proxy_name;
+ int index;
+
+ StringName setter;
+ StringName getter;
+
+ const DocData::PropertyDoc *prop_doc;
+ };
+
struct ArgumentInterface {
enum DefaultParamMode {
CONSTANT,
@@ -46,7 +87,7 @@ class BindingsGenerator {
NULLABLE_REF
};
- String type;
+ StringName type;
String name;
String default_argument;
DefaultParamMode def_param_mode;
@@ -58,6 +99,7 @@ class BindingsGenerator {
struct MethodInterface {
String name;
+ StringName cname;
/**
* Name of the C# method
@@ -67,7 +109,7 @@ class BindingsGenerator {
/**
* [TypeInterface::name] of the return type
*/
- String return_type;
+ StringName return_type;
/**
* Determines if the method has a variable number of arguments (VarArg)
@@ -103,7 +145,7 @@ class BindingsGenerator {
}
MethodInterface() {
- return_type = "void";
+ return_type = BindingsGenerator::get_singleton()->name_cache.type_void;
is_vararg = false;
is_virtual = false;
requires_object_call = false;
@@ -118,11 +160,12 @@ class BindingsGenerator {
* Also used to format [c_out].
*/
String name;
+ StringName cname;
/**
* Identifier name of the base class.
*/
- String base_name;
+ StringName base_name;
/**
* Name of the C# class
@@ -256,23 +299,32 @@ class BindingsGenerator {
const DocData::ClassDoc *class_doc;
+ List<ConstantInterface> constants;
+ List<EnumInterface> enums;
+ List<PropertyInterface> properties;
List<MethodInterface> methods;
- const MethodInterface *find_method_by_name(const String &p_name) const {
-
+ const MethodInterface *find_method_by_name(const StringName &p_cname) const {
for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) {
- if (E->get().name == p_name)
+ if (E->get().cname == p_cname)
return &E->get();
}
return NULL;
}
- static TypeInterface create_value_type(const String &p_name) {
- TypeInterface itype;
+ const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const {
+ for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) {
+ if (E->get().proxy_name == p_proxy_name)
+ return &E->get();
+ }
- itype.name = p_name;
- itype.proxy_name = p_name;
+ return NULL;
+ }
+
+ private:
+ static void _init_value_type(TypeInterface &itype) {
+ itype.proxy_name = itype.name;
itype.c_type = itype.name;
itype.c_type_in = "void*";
@@ -281,15 +333,31 @@ class BindingsGenerator {
itype.im_type_in = "ref " + itype.proxy_name;
itype.im_type_out = itype.proxy_name;
itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name];
+ }
+ public:
+ static TypeInterface create_value_type(const String &p_name) {
+ TypeInterface itype;
+ itype.name = p_name;
+ itype.cname = StringName(p_name);
+ _init_value_type(itype);
return itype;
}
- static TypeInterface create_object_type(const String &p_name, ClassDB::APIType p_api_type) {
+ static TypeInterface create_value_type(const StringName &p_name) {
TypeInterface itype;
+ itype.name = p_name.operator String();
+ itype.cname = p_name;
+ _init_value_type(itype);
+ return itype;
+ }
- itype.name = p_name;
- itype.proxy_name = p_name.begins_with("_") ? p_name.substr(1, p_name.length()) : p_name;
+ static TypeInterface create_object_type(const StringName &p_cname, ClassDB::APIType p_api_type) {
+ TypeInterface itype;
+
+ itype.name = p_cname;
+ itype.cname = p_cname;
+ itype.proxy_name = itype.name.begins_with("_") ? itype.name.substr(1, itype.name.length()) : itype.name;
itype.api_type = p_api_type;
itype.is_object_type = true;
itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name];
@@ -297,9 +365,10 @@ class BindingsGenerator {
return itype;
}
- static void create_placeholder_type(TypeInterface &r_itype, const String &p_name) {
- r_itype.name = p_name;
- r_itype.proxy_name = p_name;
+ static void create_placeholder_type(TypeInterface &r_itype, const StringName &p_cname) {
+ r_itype.name = p_cname;
+ r_itype.cname = p_cname;
+ r_itype.proxy_name = r_itype.name;
r_itype.c_type = r_itype.name;
r_itype.c_type_in = "MonoObject*";
@@ -359,11 +428,15 @@ class BindingsGenerator {
static bool verbose_output;
- Map<String, TypeInterface> placeholder_types;
- Map<String, TypeInterface> builtin_types;
- Map<String, TypeInterface> obj_types;
+ Map<StringName, TypeInterface> placeholder_types;
+ Map<StringName, TypeInterface> builtin_types;
+ Map<StringName, TypeInterface> enum_types;
+ Map<StringName, TypeInterface> obj_types;
+
+ List<EnumInterface> global_enums;
+ List<ConstantInterface> global_constants;
- Map<String, String> extra_members;
+ Map<StringName, String> extra_members;
List<InternalCall> method_icalls;
Map<const MethodInterface *, const InternalCall *> method_icalls_map;
@@ -373,8 +446,36 @@ class BindingsGenerator {
List<InternalCall> core_custom_icalls;
List<InternalCall> editor_custom_icalls;
- const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) {
+ struct NameCache {
+ StringName type_void;
+ StringName type_int;
+ StringName type_Array;
+ StringName type_Dictionary;
+ StringName type_Variant;
+ StringName type_VarArg;
+ StringName type_Object;
+ StringName type_Reference;
+ StringName enum_Error;
+
+ 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");
+ type_VarArg = StaticCString::create("VarArg");
+ type_Object = StaticCString::create("Object");
+ type_Reference = StaticCString::create("Reference");
+ enum_Error = StaticCString::create("Error");
+ }
+
+ NameCache(const NameCache &);
+ NameCache &operator=(const NameCache &);
+ };
+
+ NameCache name_cache;
+ const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) {
const List<InternalCall>::Element *it = p_list.front();
while (it) {
if (it->get().name == p_name) return it;
@@ -392,11 +493,13 @@ class BindingsGenerator {
return p_type.name;
}
+ String _determine_enum_prefix(const EnumInterface &p_ienum);
+
void _generate_header_icalls();
void _generate_method_icalls(const TypeInterface &p_itype);
- const TypeInterface *_get_type_by_name_or_null(const String &p_name);
- const TypeInterface *_get_type_by_name_or_placeholder(const String &p_name);
+ const TypeInterface *_get_type_by_name_or_null(const StringName &p_cname);
+ const TypeInterface *_get_type_by_name_or_placeholder(const StringName &p_cname);
void _default_argument_from_variant(const Variant &p_var, ArgumentInterface &r_iarg);
void _populate_builtin_type(TypeInterface &r_type, Variant::Type vtype);
@@ -404,27 +507,39 @@ class BindingsGenerator {
void _populate_object_type_interfaces();
void _populate_builtin_type_interfaces();
+ void _populate_global_constants();
+
Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file);
- Error _generate_cs_property(const TypeInterface &p_itype, const DocData::PropertyDoc &p_prop_doc, List<String> &p_output);
+ Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_prop_doc, List<String> &p_output);
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output);
+ void _generate_global_constants(List<String> &p_output);
+
Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, List<String> &p_output);
Error _save_file(const String &path, const List<String> &content);
- BindingsGenerator();
+ BindingsGenerator() {}
BindingsGenerator(const BindingsGenerator &);
BindingsGenerator &operator=(const BindingsGenerator &);
+ friend class CSharpLanguage;
+ static BindingsGenerator *singleton;
+
public:
Error generate_cs_core_project(const String &p_output_dir, bool p_verbose_output = true);
Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true);
Error generate_glue(const String &p_output_dir);
- static BindingsGenerator &get_singleton() {
- static BindingsGenerator singleton;
+ void initialize();
+
+ _FORCE_INLINE_ static BindingsGenerator *get_singleton() {
+ if (!singleton) {
+ singleton = memnew(BindingsGenerator);
+ singleton->initialize();
+ }
return singleton;
}
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
index 9a1efb4423..d5819a4ca3 100644
--- a/modules/mono/editor/csharp_project.cpp
+++ b/modules/mono/editor/csharp_project.cpp
@@ -54,7 +54,7 @@ String generate_core_api_project(const String &p_dir, const Vector<String> &p_fi
ERR_FAIL_V(String());
}
- return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
+ return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String();
}
String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files) {
@@ -75,7 +75,7 @@ String generate_editor_api_project(const String &p_dir, const String &p_core_dll
ERR_FAIL_V(String());
}
- return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
+ return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String();
}
String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files) {
@@ -96,7 +96,7 @@ String generate_game_project(const String &p_dir, const String &p_name, const Ve
ERR_FAIL_V(String());
}
- return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
+ return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String();
}
void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) {
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index b88d34fc33..3c06537816 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -238,12 +238,12 @@ bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {
#error "How am I supposed to generate the bindings?"
#endif
- BindingsGenerator &gen = BindingsGenerator::get_singleton();
+ BindingsGenerator *gen = BindingsGenerator::get_singleton();
bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
Error err = p_api_type == API_CORE ?
- gen.generate_cs_core_project(api_sln_dir, gen_verbose) :
- gen.generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose);
+ gen->generate_cs_core_project(api_sln_dir, gen_verbose) :
+ gen->generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose);
if (err != OK) {
show_build_error_dialog("Failed to generate " + api_name + " solution. Error: " + itos(err));
@@ -313,7 +313,7 @@ GodotSharpBuilds *GodotSharpBuilds::singleton = NULL;
void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) {
BuildProcess *match = builds.getptr(p_build_info);
- ERR_FAIL_COND(!match);
+ ERR_FAIL_NULL(match);
BuildProcess &bp = *match;
bp.on_exit(p_exit_code);
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index 1bc1e8a515..1e61646769 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -50,9 +50,9 @@ GodotSharpEditor *GodotSharpEditor::singleton = NULL;
bool GodotSharpEditor::_create_project_solution() {
- EditorProgress pr("create_csharp_solution", "Generating solution...", 2);
+ EditorProgress pr("create_csharp_solution", TTR("Generating solution..."), 2);
- pr.step("Generating C# project...");
+ pr.step(TTR("Generating C# project..."));
String path = OS::get_singleton()->get_resource_dir();
String name = ProjectSettings::get_singleton()->get("application/config/name");
@@ -67,7 +67,7 @@ bool GodotSharpEditor::_create_project_solution() {
NETSolution solution(name);
if (!solution.set_path(path)) {
- show_error_dialog("Failed to create solution.");
+ show_error_dialog(TTR("Failed to create solution."));
return false;
}
@@ -79,7 +79,7 @@ bool GodotSharpEditor::_create_project_solution() {
Error sln_error = solution.save();
if (sln_error != OK) {
- show_error_dialog("Failed to save solution.");
+ show_error_dialog(TTR("Failed to save solution."));
return false;
}
@@ -89,13 +89,13 @@ bool GodotSharpEditor::_create_project_solution() {
if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR))
return false;
- pr.step("Done");
+ pr.step(TTR("Done"));
// Here, after all calls to progress_task_step
call_deferred("_remove_create_sln_menu_option");
} else {
- show_error_dialog("Failed to create C# project.");
+ show_error_dialog(TTR("Failed to create C# project."));
}
return true;
@@ -194,14 +194,14 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
error_dialog = memnew(AcceptDialog);
editor->get_gui_base()->add_child(error_dialog);
- bottom_panel_btn = editor->add_bottom_panel_item("Mono", memnew(MonoBottomPanel(editor)));
+ bottom_panel_btn = editor->add_bottom_panel_item(TTR("Mono"), memnew(MonoBottomPanel(editor)));
godotsharp_builds = memnew(GodotSharpBuilds);
editor->add_child(memnew(MonoReloadNode));
menu_button = memnew(MenuButton);
- menu_button->set_text("Mono");
+ menu_button->set_text(TTR("Mono"));
menu_popup = menu_button->get_popup();
String sln_path = GodotSharpDirs::get_project_sln_path();
@@ -209,7 +209,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) {
bottom_panel_btn->hide();
- menu_popup->add_item("Create C# solution", MENU_CREATE_SLN);
+ menu_popup->add_item(TTR("Create C# solution"), MENU_CREATE_SLN);
}
menu_popup->connect("id_pressed", this, "_menu_option_pressed");
diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp
index 31dc09856a..be714026ad 100644
--- a/modules/mono/editor/mono_bottom_panel.cpp
+++ b/modules/mono/editor/mono_bottom_panel.cpp
@@ -197,7 +197,7 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
panel_builds_tab->add_child(toolbar_hbc);
ToolButton *build_project_btn = memnew(ToolButton);
- build_project_btn->set_text("Build Project");
+ build_project_btn->set_text(TTR("Build Project"));
build_project_btn->set_focus_mode(FOCUS_NONE);
build_project_btn->connect("pressed", this, "_build_project_pressed");
toolbar_hbc->add_child(build_project_btn);
@@ -205,7 +205,7 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
toolbar_hbc->add_spacer();
warnings_btn = memnew(ToolButton);
- warnings_btn->set_text("Warnings");
+ warnings_btn->set_text(TTR("Warnings"));
warnings_btn->set_toggle_mode(true);
warnings_btn->set_pressed(true);
warnings_btn->set_visible(false);
@@ -214,7 +214,7 @@ MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
toolbar_hbc->add_child(warnings_btn);
errors_btn = memnew(ToolButton);
- errors_btn->set_text("Errors");
+ errors_btn->set_text(TTR("Errors"));
errors_btn->set_toggle_mode(true);
errors_btn->set_pressed(true);
errors_btn->set_visible(false);
diff --git a/modules/mono/glue/cs_files/Error.cs b/modules/mono/glue/cs_files/Error.cs
deleted file mode 100644
index dee4b88f74..0000000000
--- a/modules/mono/glue/cs_files/Error.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-namespace Godot
-{
- public enum Error : int
- {
- OK = 0,
- FAILED = 1,
- ERR_UNAVAILABLE = 2,
- ERR_UNCONFIGURED = 3,
- ERR_UNAUTHORIZED = 4,
- ERR_PARAMETER_RANGE_ERROR = 5,
- ERR_OUT_OF_MEMORY = 6,
- ERR_FILE_NOT_FOUND = 7,
- ERR_FILE_BAD_DRIVE = 8,
- ERR_FILE_BAD_PATH = 9,
- ERR_FILE_NO_PERMISSION = 10,
- ERR_FILE_ALREADY_IN_USE = 11,
- ERR_FILE_CANT_OPEN = 12,
- ERR_FILE_CANT_WRITE = 13,
- ERR_FILE_CANT_READ = 14,
- ERR_FILE_UNRECOGNIZED = 15,
- ERR_FILE_CORRUPT = 16,
- ERR_FILE_MISSING_DEPENDENCIES = 17,
- ERR_FILE_EOF = 18,
- ERR_CANT_OPEN = 19,
- ERR_CANT_CREATE = 20,
- ERR_PARSE_ERROR = 43,
- ERROR_QUERY_FAILED = 21,
- ERR_ALREADY_IN_USE = 22,
- ERR_LOCKED = 23,
- ERR_TIMEOUT = 24,
- ERR_CANT_AQUIRE_RESOURCE = 28,
- ERR_INVALID_DATA = 30,
- ERR_INVALID_PARAMETER = 31,
- ERR_ALREADY_EXISTS = 32,
- ERR_DOES_NOT_EXIST = 33,
- ERR_DATABASE_CANT_READ = 34,
- ERR_DATABASE_CANT_WRITE = 35,
- ERR_COMPILATION_FAILED = 36,
- ERR_METHOD_NOT_FOUND = 37,
- ERR_LINK_FAILED = 38,
- ERR_SCRIPT_FAILED = 39,
- ERR_CYCLIC_LINK = 40,
- ERR_BUSY = 44,
- ERR_HELP = 46,
- ERR_BUG = 47
- }
-}
diff --git a/modules/mono/glue/cs_files/ExportAttribute.cs b/modules/mono/glue/cs_files/ExportAttribute.cs
index dce9cc59a0..e6f569e1bb 100644
--- a/modules/mono/glue/cs_files/ExportAttribute.cs
+++ b/modules/mono/glue/cs_files/ExportAttribute.cs
@@ -5,13 +5,13 @@ namespace Godot
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ExportAttribute : Attribute
{
- private int hint;
- private string hint_string;
+ private PropertyHint hint;
+ private string hintString;
- public ExportAttribute(int hint = GD.PROPERTY_HINT_NONE, string hint_string = "")
+ public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "")
{
this.hint = hint;
- this.hint_string = hint_string;
+ this.hintString = hintString;
}
}
}
diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs
index 99fc289161..b335ef55e4 100644
--- a/modules/mono/glue/cs_files/GD.cs
+++ b/modules/mono/glue/cs_files/GD.cs
@@ -2,10 +2,8 @@ using System;
namespace Godot
{
- public static class GD
+ public static partial class GD
{
- /*{GodotGlobalConstants}*/
-
public static object Bytes2Var(byte[] bytes)
{
return NativeCalls.godot_icall_Godot_bytes2var(bytes);
diff --git a/modules/mono/glue/cs_files/Rect2.cs b/modules/mono/glue/cs_files/Rect2.cs
index f2718d7b7a..e1fbb65da5 100644
--- a/modules/mono/glue/cs_files/Rect2.cs
+++ b/modules/mono/glue/cs_files/Rect2.cs
@@ -109,14 +109,14 @@ namespace Godot
return g;
}
- public Rect2 GrowMargin(int margin, float by)
+ public Rect2 GrowMargin(Margin margin, float by)
{
Rect2 g = this;
- g.GrowIndividual((GD.MARGIN_LEFT == margin) ? by : 0,
- (GD.MARGIN_TOP == margin) ? by : 0,
- (GD.MARGIN_RIGHT == margin) ? by : 0,
- (GD.MARGIN_BOTTOM == margin) ? by : 0);
+ g.GrowIndividual((Margin.Left == margin) ? by : 0,
+ (Margin.Top == margin) ? by : 0,
+ (Margin.Right == margin) ? by : 0,
+ (Margin.Bottom == margin) ? by : 0);
return g;
}
@@ -230,4 +230,4 @@ namespace Godot
});
}
}
-} \ No newline at end of file
+}
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
index 75a4eb2b40..5e41da299b 100644
--- a/modules/mono/glue/glue_header.h
+++ b/modules/mono/glue/glue_header.h
@@ -53,9 +53,11 @@
} \
Object *m_instance = ci->creation_func();
-void godot_icall_Object_Dtor(Object *ptr) {
- ERR_FAIL_NULL(ptr);
- _GodotSharp::get_singleton()->queue_dispose(ptr);
+void godot_icall_Object_Dtor(MonoObject *obj, Object *ptr) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(ptr == NULL);
+#endif
+ _GodotSharp::get_singleton()->queue_dispose(obj, ptr);
}
// -- ClassDB --
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index 121392b3f8..d407aa6981 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -41,10 +41,7 @@ uint32_t MonoGCHandle::make_strong_handle(MonoObject *p_object) {
uint32_t MonoGCHandle::make_weak_handle(MonoObject *p_object) {
- return mono_gchandle_new_weakref(
- p_object,
- true /* track_resurrection: allows us to invoke _notification(NOTIFICATION_PREDELETE) while disposing */
- );
+ return mono_gchandle_new_weakref(p_object, false);
}
Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) {
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index c997b0f000..08059c9ba9 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -703,7 +703,7 @@ bool _GodotSharp::is_domain_loaded() {
call_deferred("_dispose_callback"); \
}
-void _GodotSharp::queue_dispose(Object *p_object) {
+void _GodotSharp::queue_dispose(MonoObject *p_mono_object, Object *p_object) {
if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
_dispose_object(p_object);
@@ -712,6 +712,13 @@ void _GodotSharp::queue_dispose(Object *p_object) {
queue_mutex->lock();
#endif
+ // This is our last chance to invoke notification predelete (this is being called from the finalizer)
+ // We must use the MonoObject* passed by the finalizer, because the weak GC handle target returns NULL at this point
+ CSharpInstance *si = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
+ if (si) {
+ si->call_notification_no_check(p_mono_object, Object::NOTIFICATION_PREDELETE);
+ }
+
ENQUEUE_FOR_DISPOSAL(obj_delete_queue, p_object);
#ifndef NO_THREADS
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index b188c0730a..862f171dc9 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -215,7 +215,7 @@ public:
bool is_finalizing_domain();
bool is_domain_loaded();
- void queue_dispose(Object *p_object);
+ void queue_dispose(MonoObject *p_mono_object, Object *p_object);
void queue_dispose(NodePath *p_node_path);
void queue_dispose(RID *p_rid);
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index eb34f9dd3f..63b24f3ee6 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -290,7 +290,7 @@ int GDMonoField::get_int_value(MonoObject *p_object) {
String GDMonoField::get_string_value(MonoObject *p_object) {
MonoObject *val = get_value(p_object);
- return val ? GDMonoMarshal::mono_string_to_godot((MonoString *)val) : String();
+ return GDMonoMarshal::mono_string_to_godot((MonoString *)val);
}
bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) {
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 8bc2bb5096..d744d24f24 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -490,8 +490,9 @@ Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
return unbox<double>(p_obj);
case MONO_TYPE_STRING: {
- String str = mono_string_to_godot((MonoString *)p_obj);
- return str;
+ if (p_obj == NULL)
+ return Variant(); // NIL
+ return mono_string_to_godot_not_null((MonoString *)p_obj);
} break;
case MONO_TYPE_VALUETYPE: {
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 443e947fb5..1be4be1a1c 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -62,13 +62,20 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type);
String mono_to_utf8_string(MonoString *p_mono_string);
String mono_to_utf16_string(MonoString *p_mono_string);
-_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) {
+_FORCE_INLINE_ String mono_string_to_godot_not_null(MonoString *p_mono_string) {
if (sizeof(CharType) == 2)
return mono_to_utf16_string(p_mono_string);
return mono_to_utf8_string(p_mono_string);
}
+_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) {
+ if (p_mono_string == NULL)
+ return String();
+
+ return mono_string_to_godot_not_null(p_mono_string);
+}
+
_FORCE_INLINE_ MonoString *mono_from_utf8_string(const String &p_string) {
return mono_string_new(mono_domain_get(), p_string.utf8().get_data());
}
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 1cccd0ad9d..638636e985 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -95,7 +95,7 @@ void MonoCache::clear_members() {
class_ExportAttribute = NULL;
field_ExportAttribute_hint = NULL;
- field_ExportAttribute_hint_string = NULL;
+ field_ExportAttribute_hintString = NULL;
class_ToolAttribute = NULL;
class_RemoteAttribute = NULL;
class_SyncAttribute = NULL;
@@ -163,7 +163,7 @@ void update_godot_api_cache() {
// Attributes
CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
- CACHE_FIELD_AND_CHECK(ExportAttribute, hint_string, CACHED_CLASS(ExportAttribute)->get_field("hint_string"));
+ CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute));
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index c38f8c5af5..4308b357ba 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -97,7 +97,7 @@ struct MonoCache {
GDMonoClass *class_ExportAttribute;
GDMonoField *field_ExportAttribute_hint;
- GDMonoField *field_ExportAttribute_hint_string;
+ GDMonoField *field_ExportAttribute_hintString;
GDMonoClass *class_ToolAttribute;
GDMonoClass *class_RemoteAttribute;
GDMonoClass *class_SyncAttribute;
diff --git a/modules/opus/register_types.cpp b/modules/opus/register_types.cpp
index a69c8bf9f3..6d7a3575ed 100644
--- a/modules/opus/register_types.cpp
+++ b/modules/opus/register_types.cpp
@@ -34,13 +34,18 @@
static ResourceFormatLoaderAudioStreamOpus *opus_stream_loader = NULL;
void register_opus_types() {
-
- opus_stream_loader = memnew(ResourceFormatLoaderAudioStreamOpus);
- ResourceLoader::add_resource_format_loader(opus_stream_loader);
- ClassDB::register_class<AudioStreamOpus>();
+ // Sorry guys, do not enable this unless you can figure out a way
+ // to get Opus to not do any memory allocation or system calls
+ // in the audio thread.
+ // Currently the implementation even reads files from the audio thread,
+ // and this is not how audio programming works.
+
+ //opus_stream_loader = memnew(ResourceFormatLoaderAudioStreamOpus);
+ //ResourceLoader::add_resource_format_loader(opus_stream_loader);
+ //ClassDB::register_class<AudioStreamOpus>();
}
void unregister_opus_types() {
- memdelete(opus_stream_loader);
+ //memdelete(opus_stream_loader);
}
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index e8a8319431..2e686fbee4 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -82,9 +82,6 @@ def configure(env):
env['RANLIB'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib"
env['AS'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as"
env.Append(CCFLAGS=['-D__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define
- if (env["openmp"]):
- env.Append(CPPFLAGS=['-fopenmp'])
- env.Append(LINKFLAGS=['-fopenmp'])
else: # osxcross build
root = os.environ.get("OSXCROSS_ROOT", 0)
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 45ca097de5..9fbbca0716 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -1041,6 +1041,10 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/product_guid"), "00000000-0000-0000-0000-000000000000"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/publisher_guid"), "00000000-0000-0000-0000-000000000000"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "signing/algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256"), 2));
+
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/major"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/minor"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/build"), 0));
@@ -1370,6 +1374,58 @@ public:
packager.finish();
+#ifdef WINDOWS_ENABLED
+ // Sign with signtool
+ String signtool_path = EditorSettings::get_singleton()->get("export/uwp/signtool");
+ if (signtool_path == String()) {
+ return OK;
+ }
+
+ if (!FileAccess::exists(signtool_path)) {
+ ERR_PRINTS("Could not find signtool executable at " + signtool_path + ", aborting.");
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ static String algs[] = { "MD5", "SHA1", "SHA256" };
+
+ String cert_path = EditorSettings::get_singleton()->get("export/uwp/debug_certificate");
+ String cert_pass = EditorSettings::get_singleton()->get("export/uwp/debug_password");
+ int cert_alg = EditorSettings::get_singleton()->get("export/uwp/debug_algorithm");
+
+ if (!p_debug) {
+ cert_path = p_preset->get("signing/certificate");
+ cert_pass = p_preset->get("signing/password");
+ cert_alg = p_preset->get("signing/algorithm");
+ }
+
+ if (cert_path == String()) {
+ return OK; // Certificate missing, don't try to sign
+ }
+
+ if (!FileAccess::exists(cert_path)) {
+ ERR_PRINTS("Could not find certificate file at " + cert_path + ", aborting.");
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ if (cert_alg < 0 || cert_alg > 2) {
+ ERR_PRINTS("Invalid certificate algorithm " + itos(cert_alg) + ", aborting.");
+ return ERR_INVALID_DATA;
+ }
+
+ List<String> args;
+ args.push_back("sign");
+ args.push_back("/fd");
+ args.push_back(algs[cert_alg]);
+ args.push_back("/a");
+ args.push_back("/f");
+ args.push_back(cert_path);
+ args.push_back("/p");
+ args.push_back(cert_pass);
+ args.push_back(p_path);
+
+ OS::get_singleton()->execute(signtool_path, args, true);
+#endif // WINDOWS_ENABLED
+
return OK;
}
@@ -1387,6 +1443,18 @@ public:
};
void register_uwp_exporter() {
- Ref<EditorExportUWP> exporter = Ref<EditorExportUWP>(memnew(EditorExportUWP));
+
+#ifdef WINDOWS_ENABLED
+ EDITOR_DEF("export/uwp/signtool", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/uwp/signtool", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
+ EDITOR_DEF("export/uwp/debug_certificate", "");
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/uwp/debug_certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx"));
+ EDITOR_DEF("export/uwp/debug_password", "");
+ EDITOR_DEF("export/uwp/debug_algorithm", 2); // SHA256 is the default
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "export/uwp/debug_algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256"));
+#endif // WINDOWS_ENABLED
+
+ Ref<EditorExportUWP> exporter;
+ exporter.instance();
EditorExport::get_singleton()->add_export_platform(exporter);
}
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 564359d743..489bac50f5 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -190,9 +190,11 @@ def configure(env):
if (env["use_lto"]):
env.Append(CCFLAGS=['/GL'])
- env.Append(LINKFLAGS=['/LTCG'])
- if (env["openmp"]):
- env.Append(CPPFLAGS=['/openmp'])
+ env.Append(ARFLAGS=['/LTCG'])
+ if env["progress"]:
+ env.Append(LINKFLAGS=['/LTCG:STATUS'])
+ else:
+ env.Append(LINKFLAGS=['/LTCG'])
env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")])
env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
@@ -270,9 +272,6 @@ def configure(env):
env.Append(CCFLAGS=['-flto'])
env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
- if (env["openmp"]):
- env.Append(CPPFLAGS=['-fopenmp'])
- env.Append(LINKFLAGS=['-fopenmp'])
## Compile flags
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 09bf57c5f1..cb45fed1be 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -265,9 +265,5 @@ def configure(env):
env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu'])
- if env["openmp"]:
- env.Append(CPPFLAGS=['-fopenmp'])
- env.Append(LINKFLAGS=['-fopenmp'])
-
if env['use_static_cpp']:
env.Append(LINKFLAGS=['-static-libstdc++'])
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 6616e47317..f3f4b1f217 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -1050,6 +1050,10 @@ void OS_X11::set_window_maximized(bool p_enabled) {
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ while (p_enabled && !is_window_maximized()) {
+ // Wait for effective resizing (so the GLX context is too).
+ }
+
maximized = p_enabled;
}
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index 7d53557216..cc3829ad07 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -35,8 +35,7 @@
void Particles2D::set_emitting(bool p_emitting) {
- emitting = p_emitting;
- VS::get_singleton()->particles_set_emitting(particles, emitting);
+ VS::get_singleton()->particles_set_emitting(particles, p_emitting);
}
void Particles2D::set_amount(int p_amount) {
@@ -56,7 +55,7 @@ void Particles2D::set_one_shot(bool p_enable) {
one_shot = p_enable;
VS::get_singleton()->particles_set_one_shot(particles, one_shot);
- if (!one_shot && emitting)
+ if (!one_shot && is_emitting())
VisualServer::get_singleton()->particles_restart(particles);
}
void Particles2D::set_pre_process_time(float p_time) {
@@ -134,7 +133,7 @@ void Particles2D::set_speed_scale(float p_scale) {
bool Particles2D::is_emitting() const {
- return emitting;
+ return VS::get_singleton()->particles_get_emitting(particles);
}
int Particles2D::get_amount() const {
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
index 6946f2a799..455a663693 100644
--- a/scene/2d/particles_2d.h
+++ b/scene/2d/particles_2d.h
@@ -47,7 +47,6 @@ public:
private:
RID particles;
- bool emitting;
bool one_shot;
int amount;
float lifetime;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 7b30ddaa56..a83c1c1cad 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1527,7 +1527,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("_recreate_quadrants"), &TileMap::_recreate_quadrants);
ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants);
- ClassDB::bind_method(D_METHOD("update_bitmask_area"), &TileMap::update_bitmask_area);
+ ClassDB::bind_method(D_METHOD("update_bitmask_area", "position"), &TileMap::update_bitmask_area);
ClassDB::bind_method(D_METHOD("update_bitmask_region", "start", "end"), &TileMap::update_bitmask_region, DEFVAL(Vector2()), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("_set_tile_data"), &TileMap::_set_tile_data);
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index e1e0b9b1ce..2bb41bf49e 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -231,7 +231,7 @@ void ARVRController::_notification(int p_what) {
void ARVRController::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &ARVRController::set_controller_id);
ClassDB::bind_method(D_METHOD("get_controller_id"), &ARVRController::get_controller_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "1,32,1"), "set_controller_id", "get_controller_id");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_controller_id", "get_controller_id");
ClassDB::bind_method(D_METHOD("get_controller_name"), &ARVRController::get_controller_name);
// passthroughs to information about our related joystick
@@ -251,7 +251,8 @@ void ARVRController::_bind_methods() {
};
void ARVRController::set_controller_id(int p_controller_id) {
- // we don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
+ // We don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
+ // Note that setting this to 0 means this node is not bound to a controller yet.
controller_id = p_controller_id;
};
@@ -420,7 +421,7 @@ void ARVRAnchor::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &ARVRAnchor::set_anchor_id);
ClassDB::bind_method(D_METHOD("get_anchor_id"), &ARVRAnchor::get_anchor_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id"), "set_anchor_id", "get_anchor_id");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_anchor_id", "get_anchor_id");
ClassDB::bind_method(D_METHOD("get_anchor_name"), &ARVRAnchor::get_anchor_name);
ClassDB::bind_method(D_METHOD("get_is_active"), &ARVRAnchor::get_is_active);
@@ -430,7 +431,8 @@ void ARVRAnchor::_bind_methods() {
};
void ARVRAnchor::set_anchor_id(int p_anchor_id) {
- // we don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
+ // We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
+ // Note that setting this to 0 means this node is not bound to an anchor yet.
anchor_id = p_anchor_id;
};
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 9a77626296..8c282a31b8 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -772,8 +772,8 @@ void BakedLightmap::_bind_methods() {
BakedLightmap::BakedLightmap() {
extents = Vector3(10, 10, 10);
- bake_cell_size = 0.1;
- capture_cell_size = 0.25;
+ bake_cell_size = 0.25;
+ capture_cell_size = 0.5;
bake_quality = BAKE_QUALITY_MEDIUM;
bake_mode = BAKE_MODE_CONE_TRACE;
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 72c0b979af..7143310036 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -70,6 +70,9 @@ void Camera::_validate_property(PropertyInfo &p_property) const {
void Camera::_update_camera() {
+ if (!is_inside_tree())
+ return;
+
Transform tr = get_camera_transform();
tr.origin += tr.basis.get_axis(1) * v_offset;
tr.origin += tr.basis.get_axis(0) * h_offset;
@@ -81,7 +84,7 @@ void Camera::_update_camera() {
get_viewport()->_camera_transform_changed_notify();
*/
- if (!is_inside_tree() || get_tree()->is_node_being_edited(this) || !is_current())
+ if (get_tree()->is_node_being_edited(this) || !is_current())
return;
get_viewport()->_camera_transform_changed_notify();
@@ -407,15 +410,6 @@ Camera::KeepAspect Camera::get_keep_aspect_mode() const {
return keep_aspect;
}
-void Camera::set_vaspect(bool p_vaspect) {
- set_keep_aspect_mode(p_vaspect ? KEEP_WIDTH : KEEP_HEIGHT);
- _update_camera_mode();
-}
-
-bool Camera::get_vaspect() const {
- return keep_aspect == KEEP_HEIGHT;
-}
-
void Camera::set_doppler_tracking(DopplerTracking p_tracking) {
if (doppler_tracking == p_tracking)
@@ -468,14 +462,11 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &Camera::get_environment);
ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera::set_keep_aspect_mode);
ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode);
- ClassDB::bind_method(D_METHOD("set_vaspect"), &Camera::set_vaspect);
- ClassDB::bind_method(D_METHOD("get_vaspect"), &Camera::get_vaspect);
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
//ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current );
ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vaspect"), "set_vaspect", "get_vaspect");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index 520afb962b..d69a02afeb 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -148,8 +148,6 @@ public:
void set_keep_aspect_mode(KeepAspect p_aspect);
KeepAspect get_keep_aspect_mode() const;
- void set_vaspect(bool p_vaspect);
- bool get_vaspect() const;
void set_v_offset(float p_offset);
float get_v_offset() const;
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index b445ccc5a9..9108973cbf 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -42,8 +42,7 @@ PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const {
void Particles::set_emitting(bool p_emitting) {
- emitting = p_emitting;
- VS::get_singleton()->particles_set_emitting(particles, emitting);
+ VS::get_singleton()->particles_set_emitting(particles, p_emitting);
}
void Particles::set_amount(int p_amount) {
@@ -63,7 +62,7 @@ void Particles::set_one_shot(bool p_one_shot) {
one_shot = p_one_shot;
VS::get_singleton()->particles_set_one_shot(particles, one_shot);
- if (!one_shot && emitting)
+ if (!one_shot && is_emitting())
VisualServer::get_singleton()->particles_restart(particles);
}
@@ -113,7 +112,7 @@ void Particles::set_speed_scale(float p_scale) {
bool Particles::is_emitting() const {
- return emitting;
+ return VS::get_singleton()->particles_get_emitting(particles);
}
int Particles::get_amount() const {
diff --git a/scene/3d/particles.h b/scene/3d/particles.h
index 5b8121e937..24154b5607 100644
--- a/scene/3d/particles.h
+++ b/scene/3d/particles.h
@@ -57,7 +57,6 @@ public:
private:
RID particles;
- bool emitting;
bool one_shot;
int amount;
float lifetime;
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index d0e0937eca..417fe90d7c 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -153,6 +153,24 @@ void Skeleton::_notification(int p_what) {
case NOTIFICATION_EXIT_WORLD: {
} break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ if (dirty)
+ break; //will be eventually updated
+
+ //if moved, just update transforms
+ VisualServer *vs = VisualServer::get_singleton();
+ Bone *bonesptr = &bones[0];
+ int len = bones.size();
+ Transform global_transform = get_global_transform();
+ Transform global_transform_inverse = global_transform.affine_inverse();
+
+ for (int i = 0; i < len; i++) {
+
+ Bone &b = bonesptr[i];
+ vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse));
+ }
+ } break;
case NOTIFICATION_UPDATE_SKELETON: {
VisualServer *vs = VisualServer::get_singleton();
@@ -180,6 +198,9 @@ void Skeleton::_notification(int p_what) {
rest_global_inverse_dirty = false;
}
+ Transform global_transform = get_global_transform();
+ Transform global_transform_inverse = global_transform.affine_inverse();
+
for (int i = 0; i < len; i++) {
Bone &b = bonesptr[i];
@@ -239,7 +260,8 @@ void Skeleton::_notification(int p_what) {
}
}
- vs->skeleton_bone_set_transform(skeleton, i, b.pose_global * b.rest_global_inverse);
+ b.transform_final = b.pose_global * b.rest_global_inverse;
+ vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse));
for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
@@ -543,6 +565,7 @@ Skeleton::Skeleton() {
rest_global_inverse_dirty = true;
dirty = false;
skeleton = VisualServer::get_singleton()->skeleton_create();
+ set_notify_transform(true);
}
Skeleton::~Skeleton() {
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index fdc1100472..11ff728474 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -57,6 +57,8 @@ class Skeleton : public Spatial {
bool custom_pose_enable;
Transform custom_pose;
+ Transform transform_final;
+
List<uint32_t> nodes_bound;
Bone() {
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index d9f88ac693..e890533ab7 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -558,27 +558,27 @@ bool Spatial::is_visible() const {
void Spatial::rotate(const Vector3 &p_normal, float p_radians) {
Transform t = get_transform();
- t.basis.rotate(p_normal, p_radians);
+ t.basis.rotate_local(p_normal, p_radians); //use local rotation here, as it makes more sense here in tree hierarchy
set_transform(t);
}
void Spatial::rotate_x(float p_radians) {
Transform t = get_transform();
- t.basis.rotate(Vector3(1, 0, 0), p_radians);
+ t.basis.rotate_local(Vector3(1, 0, 0), p_radians);
set_transform(t);
}
void Spatial::rotate_y(float p_radians) {
Transform t = get_transform();
- t.basis.rotate(Vector3(0, 1, 0), p_radians);
+ t.basis.rotate_local(Vector3(0, 1, 0), p_radians);
set_transform(t);
}
void Spatial::rotate_z(float p_radians) {
Transform t = get_transform();
- t.basis.rotate(Vector3(0, 0, 1), p_radians);
+ t.basis.rotate_local(Vector3(0, 0, 1), p_radians);
set_transform(t);
}
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index bf0f801e32..bd7e52d947 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -30,11 +30,9 @@
#include "voxel_light_baker.h"
#include "os/os.h"
+#include "os/threaded_array_processor.h"
#include <stdlib.h>
-#ifdef _OPENMP
-#include <omp.h>
-#endif
#define FINDMINMAX(x0, x1, x2, min, max) \
min = max = x0; \
@@ -1689,7 +1687,7 @@ _ALWAYS_INLINE_ uint32_t xorshift32(uint32_t *state) {
return x;
}
-Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal, uint32_t *rng_state) {
+Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) {
int samples_per_quality[3] = { 48, 128, 512 };
@@ -1711,8 +1709,7 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
const Light *light = bake_light.ptr();
const Cell *cells = bake_cells.ptr();
- // Prevent false sharing when running on OpenMP
- uint32_t local_rng_state = *rng_state;
+ uint32_t local_rng_state = rand(); //needs to be fixed again
for (int i = 0; i < samples; i++) {
@@ -1796,10 +1793,28 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
}
// Make sure we don't reset this thread's RNG state
- *rng_state = local_rng_state;
+
return accum / samples;
}
+void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) {
+
+ LightMap *pixel = &p_line[p_x];
+ if (pixel->pos == Vector3())
+ return;
+ //print_line("pos: " + pixel->pos + " normal " + pixel->normal);
+ switch (bake_mode) {
+ case BAKE_MODE_CONE_TRACE: {
+ pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy;
+ } break;
+ case BAKE_MODE_RAY_TRACE: {
+ pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy;
+ } break;
+ // pixel->light = Vector3(1, 1, 1);
+ //}
+ }
+}
+
Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) {
//transfer light information to a lightmap
@@ -1862,53 +1877,10 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
volatile int lines = 0;
// make sure our OS-level rng is seeded
- srand(OS::get_singleton()->get_ticks_usec());
-
- // setup an RNG state for each OpenMP thread
- uint32_t threadcount = 1;
- uint32_t threadnum = 0;
-#ifdef _OPENMP
- threadcount = omp_get_max_threads();
-#endif
- Vector<uint32_t> rng_states;
- rng_states.resize(threadcount);
- for (uint32_t i = 0; i < threadcount; i++) {
- do {
- rng_states[i] = rand();
- } while (rng_states[i] == 0);
- }
- uint32_t *rng_states_p = rng_states.ptrw();
for (int i = 0; i < height; i++) {
- //print_line("bake line " + itos(i) + " / " + itos(height));
-#ifdef _OPENMP
-#pragma omp parallel for schedule(dynamic, 1) private(threadnum)
-#endif
- for (int j = 0; j < width; j++) {
-
-#ifdef _OPENMP
- threadnum = omp_get_thread_num();
-#endif
-
- //if (i == 125 && j == 280) {
-
- LightMap *pixel = &lightmap_ptr[i * width + j];
- if (pixel->pos == Vector3())
- continue; //unused, skipe
-
- //print_line("pos: " + pixel->pos + " normal " + pixel->normal);
- switch (bake_mode) {
- case BAKE_MODE_CONE_TRACE: {
- pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy;
- } break;
- case BAKE_MODE_RAY_TRACE: {
- pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal, &rng_states_p[threadnum]) * energy;
- } break;
- // pixel->light = Vector3(1, 1, 1);
- //}
- }
- }
+ thread_process_array(width, this, &VoxelLightBaker::_lightmap_bake_point, &lightmap_ptr[i * width]);
lines = MAX(lines, i); //for multithread
if (p_bake_time_func) {
diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h
index 7db31f8a67..68e11c356b 100644
--- a/scene/3d/voxel_light_baker.h
+++ b/scene/3d/voxel_light_baker.h
@@ -148,9 +148,12 @@ private:
_FORCE_INLINE_ void _sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha);
_FORCE_INLINE_ Vector3 _voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture);
_FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal);
- _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal, uint32_t *rng_state);
+ _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal);
+
+ void _lightmap_bake_point(uint32_t p_x, LightMap *p_line);
public:
+
void begin_bake(int p_subdiv, const AABB &p_bounds);
void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material);
void begin_bake_light(BakeQuality p_quality = BAKE_QUALITY_MEDIUM, BakeMode p_bake_mode = BAKE_MODE_CONE_TRACE, float p_propagation = 0.85, float p_energy = 1);
diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp
index 32f82fe6b8..d110984bbc 100644
--- a/scene/animation/animation_tree_player.cpp
+++ b/scene/animation/animation_tree_player.cpp
@@ -386,8 +386,6 @@ bool AnimationTreePlayer::_get(const StringName &p_name, Variant &r_ret) const {
void AnimationTreePlayer::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "base_path"));
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "master_player"));
p_list->push_back(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK));
}
@@ -558,7 +556,7 @@ float AnimationTreePlayer::_process_node(const StringName &p_node, AnimationNode
return _process_node(osn->inputs[0].node, r_prev_anim, p_time, p_seek, p_fallback_weight, p_weights);
}
- float os_seek = p_seek;
+ bool os_seek = p_seek;
if (p_seek)
osn->time = p_time;
@@ -1140,6 +1138,9 @@ void AnimationTreePlayer::transition_node_set_input_count(const StringName &p_no
n->inputs.resize(p_inputs);
n->input_data.resize(p_inputs);
+
+ _clear_cycle_test();
+
last_error = _cycle_test(out_name);
}
void AnimationTreePlayer::transition_node_set_input_auto_advance(const StringName &p_node, int p_input, bool p_auto_advance) {
@@ -1360,6 +1361,8 @@ void AnimationTreePlayer::remove_node(const StringName &p_node) {
node_map.erase(p_node);
+ _clear_cycle_test();
+
// compute last error again, just in case
last_error = _cycle_test(out_name);
dirty_caches = true;
@@ -1387,6 +1390,14 @@ AnimationTreePlayer::ConnectError AnimationTreePlayer::_cycle_test(const StringN
return CONNECT_OK;
}
+// Use this function to not alter next complete _cycle_test().
+void AnimationTreePlayer::_clear_cycle_test() {
+ for (Map<StringName, NodeBase *>::Element *E = node_map.front(); E; E = E->next()) {
+ NodeBase *nb = E->get();
+ nb->cycletest = false;
+ }
+}
+
Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const StringName &p_dst_node, int p_dst_input) {
ERR_FAIL_COND_V(!node_map.has(p_src_node), ERR_INVALID_PARAMETER);
@@ -1411,11 +1422,7 @@ Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const Str
dst->inputs[p_dst_input].node = p_src_node;
- for (Map<StringName, NodeBase *>::Element *E = node_map.front(); E; E = E->next()) {
-
- NodeBase *nb = E->get();
- nb->cycletest = false;
- }
+ _clear_cycle_test();
last_error = _cycle_test(out_name);
if (last_error) {
diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h
index c49b0c4d1b..7213441d6e 100644
--- a/scene/animation/animation_tree_player.h
+++ b/scene/animation/animation_tree_player.h
@@ -317,6 +317,7 @@ private:
bool reset_request;
ConnectError _cycle_test(const StringName &p_at_node);
+ void _clear_cycle_test();
Track *_find_track(const NodePath &p_path);
void _recompute_caches();
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 148277f2dd..a67fe2aeeb 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -450,11 +450,11 @@ String BaseButton::get_tooltip(const Point2 &p_pos) const {
String tooltip = Control::get_tooltip(p_pos);
if (shortcut.is_valid() && shortcut->is_valid()) {
- if (tooltip.find("$sc") != -1) {
- tooltip = tooltip.replace_first("$sc", "(" + shortcut->get_as_text() + ")");
- } else {
- tooltip += " (" + shortcut->get_as_text() + ")";
+ String text = shortcut->get_name() + " (" + shortcut->get_as_text() + ")";
+ if (shortcut->get_name().nocasecmp_to(tooltip) != 0) {
+ text += "\n" + tooltip;
}
+ tooltip = text;
}
return tooltip;
}
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 35488582de..5c5a73bae3 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -56,7 +56,6 @@ private:
float _internal_margin[4];
protected:
- virtual Size2 get_minimum_size() const;
void _set_internal_margin(Margin p_margin, float p_value);
void _notification(int p_what);
static void _bind_methods();
@@ -64,6 +63,8 @@ protected:
public:
//
+ virtual Size2 get_minimum_size() const;
+
void set_text(const String &p_text);
String get_text() const;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index cb6283507e..446676e80d 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -39,33 +39,32 @@ void ColorPicker::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- //sample->set_texture(get_icon("color_sample"));
+
btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
bt_add_preset->set_icon(get_icon("add_preset"));
_update_controls();
} break;
-
case NOTIFICATION_ENTER_TREE: {
+
btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
bt_add_preset->set_icon(get_icon("add_preset"));
_update_color();
} break;
-
case NOTIFICATION_PARENTED: {
+
for (int i = 0; i < 4; i++)
set_margin((Margin)i, get_constant("margin"));
} break;
-
case NOTIFICATION_VISIBILITY_CHANGED: {
Popup *p = Object::cast_to<Popup>(get_parent());
if (p)
p->set_size(Size2(get_combined_minimum_size().width + get_constant("margin") * 2, get_combined_minimum_size().height + get_constant("margin") * 2));
} break;
-
case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
+
if (screen != NULL) {
if (screen->is_visible()) {
screen->hide();
@@ -523,7 +522,6 @@ ColorPicker::ColorPicker() :
add_child(hb_edit);
w_edit = memnew(Control);
- //w_edit->set_ignore_mouse(false);
w_edit->set_custom_minimum_size(Size2(get_constant("h_width"), 0));
w_edit->set_h_size_flags(SIZE_FILL);
w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -589,7 +587,6 @@ ColorPicker::ColorPicker() :
c_text->set_h_size_flags(SIZE_EXPAND_FILL);
_update_controls();
- //_update_color();
updating = false;
set_pick_color(Color(1, 1, 1));
@@ -599,7 +596,6 @@ ColorPicker::ColorPicker() :
preset = memnew(TextureRect);
bbc->add_child(preset);
- //preset->set_ignore_mouse(false);
preset->connect("gui_input", this, "_preset_input");
preset->connect("draw", this, "_update_presets");
@@ -660,11 +656,13 @@ bool ColorPickerButton::is_editing_alpha() const {
return picker->is_editing_alpha();
}
-ColorPicker *ColorPickerButton::get_picker() {
+ColorPicker *ColorPickerButton::get_picker() const {
+
return picker;
}
-PopupPanel *ColorPickerButton::get_popup() {
+PopupPanel *ColorPickerButton::get_popup() const {
+
return popup;
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index c02cdc8608..2bae279ed5 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -129,8 +129,8 @@ public:
void set_edit_alpha(bool p_show);
bool is_editing_alpha() const;
- ColorPicker *get_picker();
- PopupPanel *get_popup();
+ ColorPicker *get_picker() const;
+ PopupPanel *get_popup() const;
ColorPickerButton();
};
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index d850553957..c235797bef 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -33,6 +33,9 @@
void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
+ if (disable_shortcuts)
+ return;
+
if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event))) {
if (!get_parent() || !is_visible_in_tree() || is_disabled())
@@ -60,25 +63,10 @@ void MenuButton::pressed() {
void MenuButton::_gui_input(Ref<InputEvent> p_event) {
- /*if (p_event.type==InputEvent::MOUSE_BUTTON && p_event->get_button_index()==BUTTON_LEFT) {
- clicked=p_event->is_pressed();
- }
- if (clicked && p_event.type==InputEvent::MOUSE_MOTION && popup->is_visible_in_tree()) {
-
- Point2 gt = Point2(p_event.mouse_motion.x,p_event.mouse_motion.y);
- gt = get_global_transform().xform(gt);
- Point2 lt = popup->get_transform().affine_inverse().xform(gt);
- if (popup->has_point(lt)) {
- //print_line("HAS POINT!!!");
- popup->call_deferred("grab_click_focus");
- }
-
- }*/
-
BaseButton::_gui_input(p_event);
}
-PopupMenu *MenuButton::get_popup() {
+PopupMenu *MenuButton::get_popup() const {
return popup;
}
@@ -98,14 +86,22 @@ void MenuButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &MenuButton::_unhandled_key_input);
ClassDB::bind_method(D_METHOD("_set_items"), &MenuButton::_set_items);
ClassDB::bind_method(D_METHOD("_get_items"), &MenuButton::_get_items);
+ ClassDB::bind_method(D_METHOD("set_disable_shortcuts", "disabled"), &MenuButton::set_disable_shortcuts);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items");
ADD_SIGNAL(MethodInfo("about_to_show"));
}
+
+void MenuButton::set_disable_shortcuts(bool p_disabled) {
+
+ disable_shortcuts = p_disabled;
+}
+
MenuButton::MenuButton() {
set_flat(true);
+ set_disable_shortcuts(false);
set_enabled_focus_mode(FOCUS_NONE);
popup = memnew(PopupMenu);
popup->hide();
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index c7f1d976ff..1bd9b155b2 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -40,6 +40,7 @@ class MenuButton : public Button {
GDCLASS(MenuButton, Button);
bool clicked;
+ bool disable_shortcuts;
PopupMenu *popup;
virtual void pressed();
@@ -53,7 +54,9 @@ protected:
static void _bind_methods();
public:
- PopupMenu *get_popup();
+ PopupMenu *get_popup() const;
+ void set_disable_shortcuts(bool p_disabled);
+
MenuButton();
~MenuButton();
};
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 70f3d9ca83..6f784b56de 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -42,38 +42,35 @@ Size2 OptionButton::get_minimum_size() const {
void OptionButton::_notification(int p_what) {
- switch (p_what) {
-
- case NOTIFICATION_DRAW: {
-
- if (!has_icon("arrow"))
- return;
-
- RID ci = get_canvas_item();
- Ref<Texture> arrow = Control::get_icon("arrow");
- Ref<StyleBox> normal = get_stylebox("normal");
- Color clr = Color(1, 1, 1);
- if (get_constant("modulate_arrow"))
- switch (get_draw_mode()) {
- case DRAW_PRESSED:
- clr = get_color("font_color_pressed");
- break;
- case DRAW_HOVER:
- clr = get_color("font_color_hover");
- break;
- case DRAW_DISABLED:
- clr = get_color("font_color_disabled");
- break;
- default:
- clr = get_color("font_color");
- }
-
- Size2 size = get_size();
-
- 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);
-
- } break;
+ if (p_what == NOTIFICATION_DRAW) {
+
+ if (!has_icon("arrow"))
+ return;
+
+ RID ci = get_canvas_item();
+ Ref<Texture> arrow = Control::get_icon("arrow");
+ Ref<StyleBox> normal = get_stylebox("normal");
+ Color clr = Color(1, 1, 1);
+ if (get_constant("modulate_arrow")) {
+ switch (get_draw_mode()) {
+ case DRAW_PRESSED:
+ clr = get_color("font_color_pressed");
+ break;
+ case DRAW_HOVER:
+ clr = get_color("font_color_hover");
+ break;
+ case DRAW_DISABLED:
+ clr = get_color("font_color_disabled");
+ break;
+ default:
+ clr = get_color("font_color");
+ }
+ }
+
+ Size2 size = get_size();
+
+ 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);
}
}
@@ -244,6 +241,11 @@ void OptionButton::remove_item(int p_idx) {
popup->remove_item(p_idx);
}
+PopupMenu *OptionButton::get_popup() const {
+
+ return popup;
+}
+
Array OptionButton::_get_items() const {
Array items;
@@ -310,6 +312,8 @@ void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_item", "idx"), &OptionButton::remove_item);
ClassDB::bind_method(D_METHOD("_select_int"), &OptionButton::_select_int);
+ ClassDB::bind_method(D_METHOD("get_popup"), &OptionButton::get_popup);
+
ClassDB::bind_method(D_METHOD("_set_items"), &OptionButton::_set_items);
ClassDB::bind_method(D_METHOD("_get_items"), &OptionButton::_get_items);
@@ -320,15 +324,16 @@ void OptionButton::_bind_methods() {
OptionButton::OptionButton() {
+ current = -1;
+ set_text_align(ALIGN_LEFT);
+ set_action_mode(ACTION_MODE_BUTTON_PRESS);
+
popup = memnew(PopupMenu);
popup->hide();
+ add_child(popup);
popup->set_as_toplevel(true);
popup->set_pass_on_modal_close_click(false);
- add_child(popup);
popup->connect("id_pressed", this, "_selected");
-
- current = -1;
- set_text_align(ALIGN_LEFT);
}
OptionButton::~OptionButton() {
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index a06c540678..b09942b072 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -85,6 +85,8 @@ public:
void remove_item(int p_idx);
+ PopupMenu *get_popup() const;
+
virtual void get_translatable_strings(List<String> *p_strings) const;
OptionButton();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 6fbc58a38a..7fe8a01cda 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -815,7 +815,35 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
}
}
+ } else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) {
+ //doubleclick: select word
+ int line = 0;
+ Item *item = NULL;
+ bool outside;
+
+ _find_click(main, b->get_position(), &item, &line, &outside);
+
+ while (item && item->type != ITEM_TEXT) {
+
+ item = _get_next_item(item, true);
+ }
+
+ if (item && item->type == ITEM_TEXT) {
+
+ String itext = static_cast<ItemText *>(item)->text;
+
+ int beg, end;
+ if (select_word(itext, line, beg, end)) {
+
+ selection.from = item;
+ selection.to = item;
+ selection.from_char = beg;
+ selection.to_char = end - 1;
+ selection.active = true;
+ update();
+ }
+ }
} else if (!b->is_pressed()) {
selection.click = NULL;
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 4420a936d2..1c15953517 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -61,7 +61,7 @@ Control *SplitContainer::_getch(int p_idx) const {
void SplitContainer::_resort() {
- /** First pass, determine minimum size AND amount of stretchable elements */
+ /* First pass, determine minimum size AND amount of stretchable elements */
int axis = vertical ? 1 : 0;
@@ -114,10 +114,8 @@ void SplitContainer::_resort() {
Size2 ms_second = second->get_combined_minimum_size();
if (vertical) {
-
minimum = ms_first.height + ms_second.height;
} else {
-
minimum = ms_first.width + ms_second.width;
}
@@ -141,12 +139,10 @@ void SplitContainer::_resort() {
} else if (expand_first_mode) {
middle_sep = get_size()[axis] - ms_second[axis] - sep;
-
} else {
middle_sep = ms_first[axis];
}
-
} else if (ratiomode) {
int first_ratio = first->get_stretch_ratio();
@@ -160,23 +156,19 @@ void SplitContainer::_resort() {
expand_ofs = (available * (1.0 - ratio));
middle_sep = ms_first[axis] + available * ratio + expand_ofs;
-
} else if (expand_first_mode) {
if (expand_ofs > 0)
expand_ofs = 0;
-
- if (expand_ofs < -available)
+ else if (expand_ofs < -available)
expand_ofs = -available;
middle_sep = get_size()[axis] - ms_second[axis] - sep + expand_ofs;
-
} else {
if (expand_ofs < 0)
expand_ofs = 0;
-
- if (expand_ofs > available)
+ else if (expand_ofs > available)
expand_ofs = available;
middle_sep = ms_first[axis] + expand_ofs;
@@ -187,7 +179,6 @@ void SplitContainer::_resort() {
fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep)));
int sofs = middle_sep + sep;
fit_child_in_rect(second, Rect2(Point2(0, sofs), Size2(get_size().width, get_size().height - sofs)));
-
} else {
fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(middle_sep, get_size().height)));
@@ -246,10 +237,12 @@ void SplitContainer::_notification(int p_what) {
_resort();
} break;
case NOTIFICATION_MOUSE_ENTER: {
+
mouse_inside = true;
update();
} break;
case NOTIFICATION_MOUSE_EXIT: {
+
mouse_inside = false;
update();
} break;
@@ -260,22 +253,17 @@ void SplitContainer::_notification(int p_what) {
if (collapsed || (!mouse_inside && get_constant("autohide")))
return;
+
int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_constant("separation") : 0;
Ref<Texture> tex = get_icon("grabber");
Size2 size = get_size();
- if (vertical) {
+ if (dragger_visibility == DRAGGER_VISIBLE) {
- //draw_style_box( get_stylebox("bg"), Rect2(0,middle_sep,get_size().width,sep));
- if (dragger_visibility == DRAGGER_VISIBLE)
+ if (vertical)
draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2));
-
- } else {
-
- //draw_style_box( get_stylebox("bg"), Rect2(middle_sep,0,sep,get_size().height));
- if (dragger_visibility == DRAGGER_VISIBLE)
+ else
draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2));
}
-
} break;
}
}
@@ -292,11 +280,13 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
if (mb->get_button_index() == BUTTON_LEFT) {
if (mb->is_pressed()) {
+
int sep = get_constant("separation");
if (vertical) {
if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + sep) {
+
dragging = true;
drag_from = mb->get_position().y;
drag_ofs = expand_ofs;
@@ -304,6 +294,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
} else {
if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + sep) {
+
dragging = true;
drag_from = mb->get_position().x;
drag_ofs = expand_ofs;
@@ -318,36 +309,31 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid()) {
-
- if (dragging) {
+ if (mm.is_valid() && dragging) {
- expand_ofs = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
- queue_sort();
- emit_signal("dragged", get_split_offset());
- }
+ expand_ofs = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
+ queue_sort();
+ emit_signal("dragged", get_split_offset());
}
}
Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const {
- if (collapsed)
- return Control::get_cursor_shape(p_pos);
-
if (dragging)
return (vertical ? CURSOR_VSIZE : CURSOR_HSIZE);
- int sep = get_constant("separation");
+ if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) {
- if (vertical) {
+ int sep = get_constant("separation");
- if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) {
- return CURSOR_VSIZE;
- }
- } else {
+ if (vertical) {
- if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) {
- return CURSOR_HSIZE;
+ if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep)
+ return CURSOR_VSIZE;
+ } else {
+
+ if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep)
+ return CURSOR_HSIZE;
}
}
@@ -358,6 +344,7 @@ void SplitContainer::set_split_offset(int p_offset) {
if (expand_ofs == p_offset)
return;
+
expand_ofs = p_offset;
queue_sort();
}
@@ -371,6 +358,7 @@ void SplitContainer::set_collapsed(bool p_collapsed) {
if (collapsed == p_collapsed)
return;
+
collapsed = p_collapsed;
queue_sort();
}
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index c7a484c4c5..40a58d4b32 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -88,7 +88,7 @@ class HSplitContainer : public SplitContainer {
public:
HSplitContainer() :
- SplitContainer(false) { set_default_cursor_shape(CURSOR_HSPLIT); }
+ SplitContainer(false) {}
};
class VSplitContainer : public SplitContainer {
@@ -97,7 +97,7 @@ class VSplitContainer : public SplitContainer {
public:
VSplitContainer() :
- SplitContainer(true) { set_default_cursor_shape(CURSOR_VSPLIT); }
+ SplitContainer(true) {}
};
#endif // SPLIT_CONTAINER_H
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 07f1bdf8e5..158f425f2a 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -42,14 +42,14 @@
#define TAB_PIXELS
-static bool _is_text_char(CharType c) {
+inline bool _is_symbol(CharType c) {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
+ return is_symbol(c);
}
-static bool _is_symbol(CharType c) {
+static bool _is_text_char(CharType c) {
- return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
static bool _is_whitespace(CharType c) {
@@ -1695,10 +1695,9 @@ void TextEdit::indent_right() {
// fix selection and cursor being off by one on the last line
if (is_selection_active()) {
- selection.to_column++;
- selection.from_column++;
+ select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1);
}
- cursor.column++;
+ cursor_set_column(cursor.column + 1, false);
end_complex_operation();
update();
}
@@ -1737,14 +1736,9 @@ void TextEdit::indent_left() {
// fix selection and cursor being off by one on the last line
if (is_selection_active() && last_line_text != get_line(end_line)) {
- if (selection.to_column > 0)
- selection.to_column--;
- if (selection.from_column > 0)
- selection.from_column--;
- }
- if (cursor.column > 0) {
- cursor.column--;
+ select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1);
}
+ cursor_set_column(cursor.column - 1, false);
end_complex_operation();
update();
}
@@ -1962,7 +1956,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} else if (mb->is_doubleclick() && text[cursor.line].length()) {
- //doubleclick select world
+ //doubleclick select word
selection.selecting_mode = Selection::MODE_WORD;
_update_selection_mode_word();
last_dblclk = OS::get_singleton()->get_ticks_msec();
@@ -1973,6 +1967,31 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
+ _reset_caret_blink_timer();
+
+ int row, col;
+ update_line_scroll_pos();
+ _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
+
+ if (is_right_click_moving_caret()) {
+ if (is_selection_active()) {
+
+ int from_line = get_selection_from_line();
+ int to_line = get_selection_to_line();
+ int from_column = get_selection_from_column();
+ int to_column = get_selection_to_column();
+
+ if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) {
+ // Right click is outside the seleted text
+ deselect();
+ }
+ }
+ if (!is_selection_active()) {
+ cursor_set_line(row, true, false);
+ cursor_set_column(col);
+ }
+ }
+
menu->set_position(get_global_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
menu->popup();
@@ -2420,26 +2439,44 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
//simple unindent
int cc = cursor.column;
+
+ const int len = text[cursor.line].length();
+ const String &line = text[cursor.line];
+
+ int left = 0; // number of whitespace chars at beginning of line
+ while (left < len && (line[left] == '\t' || line[left] == ' '))
+ left++;
+ cc = MIN(cc, left);
+
+ while (cc < indent_size && cc < left && line[cc] == ' ')
+ cc++;
+
if (cc > 0 && cc <= text[cursor.line].length()) {
- if (text[cursor.line][cursor.column - 1] == '\t') {
- backspace_at_cursor();
+ if (text[cursor.line][cc - 1] == '\t') {
+ _remove_text(cursor.line, cc - 1, cursor.line, cc);
+ if (cursor.column >= left)
+ cursor_set_column(MAX(0, cursor.column - 1));
+ update();
} else {
- if (cursor.column - indent_size >= 0) {
+ int n = 0;
- bool unindent = true;
- for (int i = 1; i <= indent_size; i++) {
- if (text[cursor.line][cursor.column - i] != ' ') {
- unindent = false;
- break;
- }
+ for (int i = 1; i <= MIN(cc, indent_size); i++) {
+ if (line[cc - i] != ' ') {
+ break;
}
+ n++;
+ }
- if (unindent) {
- _remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column);
- cursor_set_column(cursor.column - indent_size);
- }
+ if (n > 0) {
+ _remove_text(cursor.line, cc - n, cursor.line, cc);
+ if (cursor.column > left - n) // inside text?
+ cursor_set_column(MAX(0, cursor.column - n));
+ update();
}
}
+ } else if (cc == 0 && line.length() > 0 && line[0] == '\t') {
+ _remove_text(cursor.line, 0, cursor.line, 1);
+ update();
}
} else {
//simple indent
@@ -3708,6 +3745,14 @@ bool TextEdit::cursor_is_block_mode() const {
return block_caret;
}
+void TextEdit::set_right_click_moves_caret(bool p_enable) {
+ right_click_moves_caret = p_enable;
+}
+
+bool TextEdit::is_right_click_moving_caret() const {
+ return right_click_moves_caret;
+}
+
void TextEdit::_v_scroll_input() {
scrolling = false;
}
@@ -4168,11 +4213,15 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t
p_from_line = text.size() - 1;
if (p_from_column >= text[p_from_line].length())
p_from_column = text[p_from_line].length();
+ if (p_from_column < 0)
+ p_from_column = 0;
if (p_to_line >= text.size())
p_to_line = text.size() - 1;
if (p_to_column >= text[p_to_line].length())
p_to_column = text[p_to_line].length();
+ if (p_to_column < 0)
+ p_to_column = 0;
selection.from_line = p_from_line;
selection.from_column = p_from_column;
@@ -5181,12 +5230,8 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
String s = text[row];
if (s.length() == 0)
return "";
- int beg = CLAMP(col, 0, s.length());
- int end = beg;
-
- if (s[beg] > 32 || beg == s.length()) {
-
- bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this
+ int beg, end;
+ if (select_word(s, col, beg, end)) {
bool inside_quotes = false;
int qbegin = 0, qend = 0;
@@ -5205,16 +5250,6 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
}
}
- while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) {
- beg--;
- }
- while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) {
- end++;
- }
-
- if (end < s.length())
- end += 1;
-
return s.substr(beg, end - beg);
}
@@ -5231,22 +5266,8 @@ String TextEdit::get_tooltip(const Point2 &p_pos) const {
String s = text[row];
if (s.length() == 0)
return Control::get_tooltip(p_pos);
- int beg = CLAMP(col, 0, s.length());
- int end = beg;
-
- if (s[beg] > 32 || beg == s.length()) {
-
- bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this
-
- while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) {
- beg--;
- }
- while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) {
- end++;
- }
-
- if (end < s.length())
- end += 1;
+ int beg, end;
+ if (select_word(s, col, beg, end)) {
String tt = tooltip_obj->call(tooltip_func, s.substr(beg, end - beg), tooltip_ud);
@@ -5457,6 +5478,9 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("cursor_set_block_mode", "enable"), &TextEdit::cursor_set_block_mode);
ClassDB::bind_method(D_METHOD("cursor_is_block_mode"), &TextEdit::cursor_is_block_mode);
+ ClassDB::bind_method(D_METHOD("set_right_click_moves_caret", "enable"), &TextEdit::set_right_click_moves_caret);
+ ClassDB::bind_method(D_METHOD("is_right_click_moving_caret"), &TextEdit::is_right_click_moving_caret);
+
ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly);
ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly);
@@ -5492,7 +5516,7 @@ void TextEdit::_bind_methods() {
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);
ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden);
- ClassDB::bind_method(D_METHOD("is_line_hidden"), &TextEdit::is_line_hidden);
+ ClassDB::bind_method(D_METHOD("is_line_hidden", "line"), &TextEdit::is_line_hidden);
ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines);
ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines);
ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line);
@@ -5540,6 +5564,7 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled");
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "cursor_set_blink_speed", "cursor_get_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_moving_by_right_click"), "set_right_click_moves_caret", "is_right_click_moving_caret");
ADD_SIGNAL(MethodInfo("cursor_changed"));
ADD_SIGNAL(MethodInfo("text_changed"));
@@ -5617,6 +5642,7 @@ TextEdit::TextEdit() {
caret_blink_timer->set_wait_time(0.65);
caret_blink_timer->connect("timeout", this, "_toggle_draw_caret");
cursor_set_blink_enabled(false);
+ right_click_moves_caret = true;
idle_detect = memnew(Timer);
add_child(idle_detect);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 836d5c7388..f18eaa85cb 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -246,6 +246,7 @@ class TextEdit : public Control {
bool draw_caret;
bool window_has_focus;
bool block_caret;
+ bool right_click_moves_caret;
bool setting_row;
bool wrap;
@@ -481,6 +482,9 @@ public:
void cursor_set_block_mode(const bool p_enable);
bool cursor_is_block_mode() const;
+ void set_right_click_moves_caret(bool p_enable);
+ bool is_right_click_moving_caret() const;
+
void set_readonly(bool p_readonly);
bool is_readonly() const;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index b5b42e8f29..f4547d400d 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1009,10 +1009,10 @@ void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, co
case TreeItem::ALIGN_LEFT:
break; //do none
case TreeItem::ALIGN_CENTER:
- rect.position.x = MAX(0, (rect.size.width - w) / 2);
+ rect.position.x += MAX(0, (rect.size.width - w) / 2);
break; //do none
case TreeItem::ALIGN_RIGHT:
- rect.position.x = MAX(0, (rect.size.width - w));
+ rect.position.x += MAX(0, (rect.size.width - w));
break; //do none
}
@@ -1775,7 +1775,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
case TreeItem::CELL_MODE_STRING: {
//nothing in particular
- if (select_mode == SELECT_MULTI && (get_tree()->get_last_event_id() == focus_in_id || !already_cursor)) {
+ if (select_mode == SELECT_MULTI && (get_tree()->get_event_count() == focus_in_id || !already_cursor)) {
bring_up_editor = false;
}
@@ -1863,7 +1863,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
} else {
editor_text = String::num(p_item->cells[col].val, Math::step_decimals(p_item->cells[col].step));
- if (select_mode == SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id)
+ if (select_mode == SELECT_MULTI && get_tree()->get_event_count() == focus_in_id)
bring_up_editor = false;
}
}
@@ -2786,7 +2786,7 @@ void Tree::_notification(int p_what) {
if (p_what == NOTIFICATION_FOCUS_ENTER) {
- focus_in_id = get_tree()->get_last_event_id();
+ focus_in_id = get_tree()->get_event_count();
}
if (p_what == NOTIFICATION_MOUSE_EXIT) {
@@ -2950,43 +2950,51 @@ Size2 Tree::get_minimum_size() const {
return Size2(1, 1);
}
-TreeItem *Tree::create_item(TreeItem *p_parent) {
+TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
ERR_FAIL_COND_V(blocked > 0, NULL);
- TreeItem *ti = memnew(TreeItem(this));
-
- ERR_FAIL_COND_V(!ti, NULL);
- ti->cells.resize(columns.size());
+ TreeItem *ti = NULL;
if (p_parent) {
- /* Always append at the end */
+ // Append or insert a new item to the given parent.
+ ti = memnew(TreeItem(this));
+ ERR_FAIL_COND_V(!ti, NULL);
+ ti->cells.resize(columns.size());
- TreeItem *last = 0;
+ TreeItem *prev = NULL;
TreeItem *c = p_parent->childs;
+ int idx = 0;
while (c) {
-
- last = c;
+ if (idx++ == p_idx) {
+ ti->next = c;
+ break;
+ }
+ prev = c;
c = c->next;
}
- if (last) {
-
- last->next = ti;
- } else {
-
+ if (prev)
+ prev->next = ti;
+ else
p_parent->childs = ti;
- }
ti->parent = p_parent;
} else {
- if (root)
- ti->childs = root;
+ if (!root) {
+ // No root exists, make the given item the new root.
+ ti = memnew(TreeItem(this));
+ ERR_FAIL_COND_V(!ti, NULL);
+ ti->cells.resize(columns.size());
- root = ti;
+ root = ti;
+ } else {
+ // Root exists, append or insert to root.
+ ti = create_item(root, p_idx);
+ }
}
return ti;
@@ -3723,7 +3731,7 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("_scroll_moved"), &Tree::_scroll_moved);
ClassDB::bind_method(D_METHOD("clear"), &Tree::clear);
- ClassDB::bind_method(D_METHOD("create_item", "parent"), &Tree::_create_item, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::_create_item, DEFVAL(Variant()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root);
ClassDB::bind_method(D_METHOD("set_column_min_width", "column", "min_width"), &Tree::set_column_min_width);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 112de3165f..b8d94bcffb 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -359,7 +359,7 @@ private:
LineEdit *text_editor;
HSlider *value_editor;
bool updating_value_editor;
- uint32_t focus_in_id;
+ int64_t focus_in_id;
PopupMenu *popup_menu;
Vector<ColumnInfo> columns;
@@ -511,8 +511,8 @@ protected:
static void _bind_methods();
//bind helpers
- Object *_create_item(Object *p_parent) {
- return create_item(Object::cast_to<TreeItem>(p_parent));
+ Object *_create_item(Object *p_parent, int p_idx = -1) {
+ return create_item(Object::cast_to<TreeItem>(p_parent), p_idx);
}
TreeItem *_get_next_selected(Object *p_item) {
@@ -532,7 +532,7 @@ public:
void clear();
- TreeItem *create_item(TreeItem *p_parent = 0);
+ TreeItem *create_item(TreeItem *p_parent = 0, int p_idx = -1);
TreeItem *get_root();
TreeItem *get_last_item();
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index de1ab9959a..942a6d5428 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -340,7 +340,8 @@ void Node::move_child(Node *p_child, int p_pos) {
data.children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
for (const Map<StringName, GroupData>::Element *E = p_child->data.grouped.front(); E; E = E->next()) {
- E->get().group->changed = true;
+ if (E->get().group)
+ E->get().group->changed = true;
}
data.blocked--;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 7c31b72bb5..db39b37bd5 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -391,13 +391,12 @@ void SceneTree::input_event(const Ref<InputEvent> &p_event) {
if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_event)))
return; //avoid joy input on editor
+ current_event++;
root_lock++;
- //last_id=p_event.ID;
input_handled = false;
Ref<InputEvent> ev = p_event;
- ev->set_id(++last_id); //this should work better
MainLoop::input_event(ev);
@@ -941,11 +940,6 @@ void SceneMainLoop::_update_listener_2d() {
}
*/
-uint32_t SceneTree::get_last_event_id() const {
-
- return last_id;
-}
-
Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
r_error.error = Variant::CallError::CALL_OK;
@@ -994,6 +988,10 @@ int64_t SceneTree::get_frame() const {
return current_frame;
}
+int64_t SceneTree::get_event_count() const {
+
+ return current_event;
+}
Array SceneTree::_get_nodes_in_group(const StringName &p_group) {
@@ -2287,9 +2285,10 @@ SceneTree::SceneTree() {
tree_version = 1;
physics_process_time = 1;
idle_process_time = 1;
- last_id = 1;
+
root = NULL;
current_frame = 0;
+ current_event = 0;
tree_changed_name = "tree_changed";
node_added_name = "node_added";
node_removed_name = "node_removed";
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 9c5b0f69cb..3e2e74b553 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -109,7 +109,6 @@ private:
float idle_process_time;
bool accept_quit;
bool quit_on_go_back;
- uint32_t last_id;
#ifdef DEBUG_ENABLED
bool debug_collisions_hint;
@@ -130,6 +129,7 @@ private:
bool use_font_oversampling;
int64_t current_frame;
+ int64_t current_event;
int node_count;
#ifdef TOOLS_ENABLED
@@ -325,7 +325,7 @@ public:
NOTIFICATION_TRANSFORM_CHANGED = 29
};
- enum CallGroupFlags {
+ enum GroupCallFlags {
GROUP_CALL_DEFAULT = 0,
GROUP_CALL_REVERSE = 1,
GROUP_CALL_REALTIME = 2,
@@ -335,8 +335,6 @@ public:
_FORCE_INLINE_ Viewport *get_root() const { return root; }
- uint32_t get_last_event_id() const;
-
void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST);
void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification);
void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value);
@@ -412,6 +410,7 @@ public:
int get_collision_debug_contact_count() { return collision_debug_contacts; }
int64_t get_frame() const;
+ int64_t get_event_count() const;
int get_node_count() const;
@@ -467,6 +466,6 @@ public:
VARIANT_ENUM_CAST(SceneTree::StretchMode);
VARIANT_ENUM_CAST(SceneTree::StretchAspect);
-VARIANT_ENUM_CAST(SceneTree::CallGroupFlags);
+VARIANT_ENUM_CAST(SceneTree::GroupCallFlags);
#endif
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 8f431389d8..fa6a7832f5 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -184,7 +184,6 @@ Viewport::GUI::GUI() {
key_focus = NULL;
mouse_over = NULL;
- cancelled_input_ID = 0;
tooltip = NULL;
tooltip_popup = NULL;
tooltip_label = NULL;
@@ -1620,9 +1619,6 @@ bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_che
void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
- if (p_event->get_id() == gui.cancelled_input_ID) {
- return;
- }
//?
/*
if (!is_visible()) {
@@ -1640,7 +1636,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (mb->is_pressed()) {
Size2 pos = mpos;
- if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button) {
+ if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button && mb->get_button_index() == BUTTON_LEFT) {
//do not steal mouse focus and stuff
@@ -1752,7 +1748,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
_gui_call_input(gui.mouse_focus, mb);
}
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "windows", "_cancel_input_ID", mb->get_id());
get_tree()->set_input_as_handled();
if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
@@ -1825,7 +1820,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_data=Variant(); //always clear
}*/
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "windows", "_cancel_input_ID", mb->get_id());
get_tree()->set_input_as_handled();
}
}
@@ -2904,7 +2898,7 @@ Viewport::Viewport() {
gui.canvas_sort_index = 0;
msaa = MSAA_DISABLED;
- hdr = false;
+ hdr = true;
usage = USAGE_3D;
debug_draw = DEBUG_DRAW_DISABLED;
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 0835e3f69a..c084e348b5 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -269,7 +269,6 @@ private:
float tooltip_timer;
float tooltip_delay;
List<Control *> modal_stack;
- unsigned int cancelled_input_ID;
Transform2D focus_inv_xform;
bool subwindow_order_dirty;
List<Control *> subwindows;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 39e6698725..0c8837ee1a 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -200,6 +200,9 @@ static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL;
static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL;
+static ResourceFormatSaverShader *resource_saver_shader = NULL;
+static ResourceFormatLoaderShader *resource_loader_shader = NULL;
+
void register_scene_types() {
SceneStringNames::create();
@@ -607,6 +610,12 @@ void register_scene_types() {
resource_loader_text = memnew(ResourceFormatLoaderText);
ResourceLoader::add_resource_format_loader(resource_loader_text, true);
+ resource_saver_shader = memnew(ResourceFormatSaverShader);
+ ResourceSaver::add_resource_format_saver(resource_saver_shader, true);
+
+ resource_loader_shader = memnew(ResourceFormatLoaderShader);
+ ResourceLoader::add_resource_format_loader(resource_loader_shader, true);
+
for (int i = 0; i < 20; i++) {
GLOBAL_DEF("layer_names/2d_render/layer_" + itos(i + 1), "");
GLOBAL_DEF("layer_names/2d_physics/layer_" + itos(i + 1), "");
@@ -632,6 +641,13 @@ void unregister_scene_types() {
memdelete(resource_loader_text);
}
+ if (resource_saver_shader) {
+ memdelete(resource_saver_shader);
+ }
+ if (resource_loader_shader) {
+ memdelete(resource_loader_shader);
+ }
+
SpatialMaterial::finish_shaders();
ParticlesMaterial::finish_shaders();
CanvasItemMaterial::finish_shaders();
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 326320c60f..cc9fde58e2 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -753,7 +753,7 @@ void SpatialMaterial::_update_shader() {
if (features[FEATURE_REFRACTION] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //refraction not supported with triplanar
if (features[FEATURE_NORMAL_MAPPING]) {
- code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) ) * SIDE;\n";
+ code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) );\n";
} else {
code += "\tvec3 ref_normal = NORMAL;\n";
}
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 66df7dfda8..207c50f673 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -151,3 +151,80 @@ Shader::~Shader() {
VisualServer::get_singleton()->free(shader);
}
+////////////
+
+RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error = ERR_FILE_CANT_OPEN;
+
+ Ref<Shader> shader;
+ shader.instance();
+
+ Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path);
+
+ String str;
+ str.parse_utf8((const char *)buffer.ptr(), buffer.size());
+
+ shader->set_code(str);
+
+ if (r_error)
+ *r_error = OK;
+
+ return shader;
+}
+
+void ResourceFormatLoaderShader::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("shader");
+}
+
+bool ResourceFormatLoaderShader::handles_type(const String &p_type) const {
+
+ return (p_type == "Shader");
+}
+
+String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const {
+
+ String el = p_path.get_extension().to_lower();
+ if (el == "shader")
+ return "Shader";
+ return "";
+}
+
+Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+
+ Ref<Shader> shader = p_resource;
+ ERR_FAIL_COND_V(shader.is_null(), ERR_INVALID_PARAMETER);
+
+ String source = shader->get_code();
+
+ Error err;
+ FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+
+ if (err) {
+
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ memdelete(file);
+ return ERR_CANT_CREATE;
+ }
+ file->close();
+ memdelete(file);
+
+ return OK;
+}
+
+void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+
+ if (Object::cast_to<Shader>(*p_resource)) {
+ p_extensions->push_back("shader");
+ }
+}
+bool ResourceFormatSaverShader::recognize(const RES &p_resource) const {
+
+ return Object::cast_to<Shader>(*p_resource) != NULL;
+}
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 5cc70629c7..78d73a33e2 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -31,6 +31,7 @@
#define SHADER_H
#include "io/resource_loader.h"
+#include "io/resource_saver.h"
#include "resource.h"
#include "scene/resources/texture.h"
@@ -38,7 +39,6 @@ class Shader : public Resource {
GDCLASS(Shader, Resource);
OBJ_SAVE_TYPE(Shader);
- RES_BASE_EXTENSION("shd");
public:
enum Mode {
@@ -95,4 +95,19 @@ public:
VARIANT_ENUM_CAST(Shader::Mode);
+class ResourceFormatLoaderShader : public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class ResourceFormatSaverShader : public ResourceFormatSaver {
+public:
+ virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const RES &p_resource) const;
+};
+
#endif // SHADER_H
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 987d6c5f6a..35d0d55d85 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -707,6 +707,8 @@ Ref<Image> StreamTexture::get_data() const {
}
void StreamTexture::set_flags(uint32_t p_flags) {
+ flags = p_flags;
+ VS::get_singleton()->texture_set_flags(texture, flags);
}
void StreamTexture::reload_from_file() {
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index bd6b917d4e..144c208c07 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -893,8 +893,8 @@ void TileSet::clear() {
void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_tile", "id"), &TileSet::create_tile);
- ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "mode"), &TileSet::autotile_set_bitmask_mode);
- ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode"), &TileSet::autotile_get_bitmask_mode);
+ ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "id", "mode"), &TileSet::autotile_set_bitmask_mode);
+ ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode", "id"), &TileSet::autotile_get_bitmask_mode);
ClassDB::bind_method(D_METHOD("tile_set_name", "id", "name"), &TileSet::tile_set_name);
ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name);
ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture"), &TileSet::tile_set_texture);
diff --git a/servers/arvr/arvr_positional_tracker.cpp b/servers/arvr/arvr_positional_tracker.cpp
index fc0270615c..fb97d5b86b 100644
--- a/servers/arvr/arvr_positional_tracker.cpp
+++ b/servers/arvr/arvr_positional_tracker.cpp
@@ -62,13 +62,15 @@ void ARVRPositionalTracker::_bind_methods() {
void ARVRPositionalTracker::set_type(ARVRServer::TrackerType p_type) {
if (type != p_type) {
type = p_type;
+ hand = ARVRPositionalTracker::TRACKER_HAND_UNKNOWN;
ARVRServer *arvr_server = ARVRServer::get_singleton();
ERR_FAIL_NULL(arvr_server);
// get a tracker id for our type
+ // note if this is a controller this will be 3 or higher but we may change it later.
tracker_id = arvr_server->get_free_tracker_id_for_type(p_type);
- }
+ };
};
ARVRServer::TrackerType ARVRPositionalTracker::get_type() const {
@@ -156,7 +158,24 @@ ARVRPositionalTracker::TrackerHand ARVRPositionalTracker::get_hand() const {
};
void ARVRPositionalTracker::set_hand(const ARVRPositionalTracker::TrackerHand p_hand) {
- hand = p_hand;
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+
+ if (hand != p_hand) {
+ // we can only set this if we've previously set this to be a controller!!
+ ERR_FAIL_COND((type != ARVRServer::TRACKER_CONTROLLER) && (p_hand != ARVRPositionalTracker::TRACKER_HAND_UNKNOWN));
+
+ hand = p_hand;
+ if (hand == ARVRPositionalTracker::TRACKER_LEFT_HAND) {
+ if (!arvr_server->is_tracker_id_in_use_for_type(type, 1)) {
+ tracker_id = 1;
+ };
+ } else if (hand == ARVRPositionalTracker::TRACKER_RIGHT_HAND) {
+ if (!arvr_server->is_tracker_id_in_use_for_type(type, 2)) {
+ tracker_id = 2;
+ };
+ };
+ };
};
Transform ARVRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const {
diff --git a/servers/arvr_server.cpp b/servers/arvr_server.cpp
index 1e73d6753c..df73040e1e 100644
--- a/servers/arvr_server.cpp
+++ b/servers/arvr_server.cpp
@@ -43,7 +43,7 @@ void ARVRServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_world_scale"), &ARVRServer::get_world_scale);
ClassDB::bind_method(D_METHOD("set_world_scale"), &ARVRServer::set_world_scale);
ClassDB::bind_method(D_METHOD("get_reference_frame"), &ARVRServer::get_reference_frame);
- ClassDB::bind_method(D_METHOD("center_on_hmd", "ignore_tilt", "keep_height"), &ARVRServer::center_on_hmd);
+ ClassDB::bind_method(D_METHOD("center_on_hmd", "rotation_mode", "keep_height"), &ARVRServer::center_on_hmd);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "world_scale"), "set_world_scale", "get_world_scale");
@@ -63,6 +63,10 @@ void ARVRServer::_bind_methods() {
BIND_ENUM_CONSTANT(TRACKER_UNKNOWN);
BIND_ENUM_CONSTANT(TRACKER_ANY);
+ BIND_ENUM_CONSTANT(RESET_FULL_ROTATION);
+ BIND_ENUM_CONSTANT(RESET_BUT_KEEP_TILT);
+ BIND_ENUM_CONSTANT(DONT_RESET_ROTATION);
+
ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING, "name")));
ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING, "name")));
@@ -96,7 +100,7 @@ Transform ARVRServer::get_reference_frame() const {
return reference_frame;
};
-void ARVRServer::center_on_hmd(bool p_ignore_tilt, bool p_keep_height) {
+void ARVRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) {
if (primary_interface != NULL) {
// clear our current reference frame or we'll end up double adjusting it
reference_frame = Transform();
@@ -105,7 +109,7 @@ void ARVRServer::center_on_hmd(bool p_ignore_tilt, bool p_keep_height) {
Transform new_reference_frame = primary_interface->get_transform_for_eye(ARVRInterface::EYE_MONO, Transform());
// remove our tilt
- if (p_ignore_tilt) {
+ if (p_rotation_mode == 1) {
// take the Y out of our Z
new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized());
@@ -114,6 +118,9 @@ void ARVRServer::center_on_hmd(bool p_ignore_tilt, bool p_keep_height) {
// and X is our cross reference
new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized());
+ } else if (p_rotation_mode == 2) {
+ // remove our rotation, we're only interesting in centering on position
+ new_reference_frame.basis = Basis();
};
// don't negate our height
@@ -229,8 +236,12 @@ bool ARVRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p
};
int ARVRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) {
- // we start checking at 1, 0 means that it's not a controller..
- int tracker_id = 1;
+ // We start checking at 1, 0 means that it's not a controller..
+ // Note that for controller we reserve:
+ // - 1 for the left hand controller and
+ // - 2 for the right hand controller
+ // so we start at 3 :)
+ int tracker_id = p_tracker_type == ARVRServer::TRACKER_CONTROLLER ? 3 : 1;
while (is_tracker_id_in_use_for_type(p_tracker_type, tracker_id)) {
// try the next one
diff --git a/servers/arvr_server.h b/servers/arvr_server.h
index 9b84ee2e99..0381e6e533 100644
--- a/servers/arvr_server.h
+++ b/servers/arvr_server.h
@@ -68,6 +68,12 @@ public:
TRACKER_ANY = 0xff /* used by get_connected_trackers to return all types */
};
+ enum RotationMode {
+ RESET_FULL_ROTATION = 0, /* we reset the full rotation, regardless of how the HMD is oriented, we're looking dead ahead */
+ RESET_BUT_KEEP_TILT = 1, /* reset rotation but keep tilt. */
+ DONT_RESET_ROTATION = 2, /* don't reset the rotation, we will only center on position */
+ };
+
private:
Vector<Ref<ARVRInterface> > interfaces;
Vector<ARVRPositionalTracker *> trackers;
@@ -78,8 +84,6 @@ private:
Transform world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */
Transform reference_frame; /* our reference frame */
- bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const;
-
protected:
static ARVRServer *singleton;
@@ -127,7 +131,7 @@ public:
and in the virtual world out of sync
*/
Transform get_reference_frame() const;
- void center_on_hmd(bool p_ignore_tilt, bool p_keep_height);
+ void center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height);
/*
Interfaces are objects that 'glue' Godot to an AR or VR SDK such as the Oculus SDK, OpenVR, OpenHMD, etc.
@@ -150,9 +154,8 @@ public:
/*
Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc.
They are created and managed by our active AR/VR interfaces.
-
- Note that for trackers that
*/
+ bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const;
int get_free_tracker_id_for_type(TrackerType p_tracker_type);
void add_tracker(ARVRPositionalTracker *p_tracker);
void remove_tracker(ARVRPositionalTracker *p_tracker);
@@ -167,5 +170,6 @@ public:
#define ARVR ARVRServer
VARIANT_ENUM_CAST(ARVRServer::TrackerType);
+VARIANT_ENUM_CAST(ARVRServer::RotationMode);
#endif
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index a08733de87..8b14a5a8a7 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -892,15 +892,15 @@ void AudioServer::load_default_bus_layout() {
void AudioServer::finish() {
+ for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
+ AudioDriverManager::get_driver(i)->finish();
+ }
+
for (int i = 0; i < buses.size(); i++) {
memdelete(buses[i]);
}
buses.clear();
-
- for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
- AudioDriverManager::get_driver(i)->finish();
- }
}
void AudioServer::update() {
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
index dc58cd36dd..dad4711c07 100644
--- a/servers/physics_2d_server.cpp
+++ b/servers/physics_2d_server.cpp
@@ -654,6 +654,10 @@ void Physics2DServer::_bind_methods() {
BIND_ENUM_CONSTANT(JOINT_GROOVE);
BIND_ENUM_CONSTANT(JOINT_DAMPED_SPRING);
+ BIND_ENUM_CONSTANT(JOINT_PARAM_BIAS);
+ BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_BIAS);
+ BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_FORCE);
+
BIND_ENUM_CONSTANT(DAMPED_STRING_REST_LENGTH);
BIND_ENUM_CONSTANT(DAMPED_STRING_STIFFNESS);
BIND_ENUM_CONSTANT(DAMPED_STRING_DAMPING);
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index c5c225a40a..667a0f5742 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -473,6 +473,8 @@ public:
virtual RID particles_create() = 0;
virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
+ virtual bool particles_get_emitting(RID p_particles) = 0;
+
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index 834505df9a..076f337635 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -334,6 +334,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
while (true) {
if (GETCHAR(0) == '\n') {
+ tk_line++;
char_idx++;
break;
}
diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp
index a25c5ca65e..96f981ab5e 100644
--- a/servers/visual/shader_types.cpp
+++ b/servers/visual/shader_types.cpp
@@ -109,7 +109,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SIDE"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index 716c1754e1..9b19aa0eff 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -384,6 +384,7 @@ public:
BIND0R(RID, particles_create)
BIND2(particles_set_emitting, RID, bool)
+ BIND1R(bool, particles_get_emitting, RID)
BIND2(particles_set_amount, RID, int)
BIND2(particles_set_lifetime, RID, float)
BIND2(particles_set_one_shot, RID, bool)
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index 0f24521f5d..a350cc1809 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -317,6 +317,7 @@ public:
FUNCRID(particles)
FUNC2(particles_set_emitting, RID, bool)
+ FUNC1R(bool, particles_get_emitting, RID)
FUNC2(particles_set_amount, RID, int)
FUNC2(particles_set_lifetime, RID, float)
FUNC2(particles_set_one_shot, RID, bool)
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 23354c3d37..e45b18b066 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -504,6 +504,7 @@ public:
virtual RID particles_create() = 0;
virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
+ virtual bool particles_get_emitting(RID p_particles) = 0;
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;