summaryrefslogtreecommitdiffstats
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/camera_2d.cpp4
-rw-r--r--scene/2d/mesh_instance_2d.cpp13
-rw-r--r--scene/2d/navigation_obstacle_2d.h4
-rw-r--r--scene/2d/path_2d.cpp9
-rw-r--r--scene/2d/tile_map_layer.cpp2
-rw-r--r--scene/3d/camera_3d.cpp8
-rw-r--r--scene/3d/cpu_particles_3d.cpp1
-rw-r--r--scene/3d/light_3d.cpp15
-rw-r--r--scene/3d/light_3d.h4
-rw-r--r--scene/3d/lightmap_gi.cpp179
-rw-r--r--scene/3d/lightmap_gi.h10
-rw-r--r--scene/3d/mesh_instance_3d.cpp4
-rw-r--r--scene/3d/navigation_obstacle_3d.h4
-rw-r--r--scene/3d/node_3d.h4
-rw-r--r--scene/3d/skeleton_3d.cpp143
-rw-r--r--scene/3d/skeleton_3d.h14
-rw-r--r--scene/3d/xr_nodes.cpp14
-rw-r--r--scene/animation/animation_mixer.cpp66
-rw-r--r--scene/animation/animation_mixer.h21
-rw-r--r--scene/animation/animation_node_state_machine.cpp2
-rw-r--r--scene/animation/animation_player.cpp4
-rw-r--r--scene/animation/animation_player.h4
-rw-r--r--scene/animation/animation_tree.cpp32
-rw-r--r--scene/animation/animation_tree.h47
-rw-r--r--scene/debugger/scene_debugger.cpp16
-rw-r--r--scene/debugger/scene_debugger.h2
-rw-r--r--scene/gui/button.cpp25
-rw-r--r--scene/gui/button.h4
-rw-r--r--scene/gui/code_edit.cpp6
-rw-r--r--scene/gui/color_mode.h4
-rw-r--r--scene/gui/color_picker.cpp56
-rw-r--r--scene/gui/color_picker.h1
-rw-r--r--scene/gui/control.cpp24
-rw-r--r--scene/gui/control.h9
-rw-r--r--scene/gui/file_dialog.cpp18
-rw-r--r--scene/gui/graph_edit.cpp16
-rw-r--r--scene/gui/item_list.cpp2
-rw-r--r--scene/gui/menu_bar.cpp1
-rw-r--r--scene/gui/option_button.cpp6
-rw-r--r--scene/gui/range.h2
-rw-r--r--scene/gui/rich_text_effect.h20
-rw-r--r--scene/gui/scroll_container.cpp6
-rw-r--r--scene/gui/text_edit.h6
-rw-r--r--scene/gui/texture_button.cpp4
-rw-r--r--scene/gui/tree.cpp421
-rw-r--r--scene/gui/tree.h18
-rw-r--r--scene/main/canvas_item.cpp2
-rw-r--r--scene/main/canvas_item.h16
-rw-r--r--scene/main/instance_placeholder.cpp2
-rw-r--r--scene/main/viewport.cpp14
-rw-r--r--scene/main/window.cpp20
-rw-r--r--scene/main/window.h12
-rw-r--r--scene/property_utils.cpp10
-rw-r--r--scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp2
-rw-r--r--scene/resources/2d/tile_set.cpp20
-rw-r--r--scene/resources/2d/tile_set.h6
-rw-r--r--scene/resources/3d/importer_mesh.cpp1
-rw-r--r--scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp2
-rw-r--r--scene/resources/3d/primitive_meshes.h2
-rw-r--r--scene/resources/animation.cpp2
-rw-r--r--scene/resources/camera_attributes.cpp2
-rw-r--r--scene/resources/external_texture.cpp23
-rw-r--r--scene/resources/external_texture.h5
-rw-r--r--scene/resources/immediate_mesh.cpp2
-rw-r--r--scene/resources/mesh.cpp10
-rw-r--r--scene/resources/resource_format_text.cpp4
-rw-r--r--scene/resources/shader.cpp12
-rw-r--r--scene/resources/shader.h2
-rw-r--r--scene/resources/style_box_flat.cpp24
-rw-r--r--scene/resources/surface_tool.h10
-rw-r--r--scene/resources/text_paragraph.h2
-rw-r--r--scene/scene_string_names.cpp2
-rw-r--r--scene/scene_string_names.h2
-rw-r--r--scene/theme/default_theme.cpp6
74 files changed, 1025 insertions, 467 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 7020d162fe..ebed1e84e6 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -115,11 +115,11 @@ void Camera2D::set_zoom(const Vector2 &p_zoom) {
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
_update_scroll();
smoothed_camera_pos = old_smoothed_camera_pos;
-};
+}
Vector2 Camera2D::get_zoom() const {
return zoom;
-};
+}
Transform2D Camera2D::get_camera_transform() {
if (!get_tree()) {
diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp
index ae45d431fe..1031a67343 100644
--- a/scene/2d/mesh_instance_2d.cpp
+++ b/scene/2d/mesh_instance_2d.cpp
@@ -54,7 +54,20 @@ void MeshInstance2D::_bind_methods() {
}
void MeshInstance2D::set_mesh(const Ref<Mesh> &p_mesh) {
+ if (mesh == p_mesh) {
+ return;
+ }
+
+ if (mesh.is_valid()) {
+ mesh->disconnect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ }
+
mesh = p_mesh;
+
+ if (mesh.is_valid()) {
+ mesh->connect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
+ }
+
queue_redraw();
}
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index 30328f7086..28c5f902e6 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -84,7 +84,7 @@ public:
real_t get_radius() const { return radius; }
void set_vertices(const Vector<Vector2> &p_vertices);
- const Vector<Vector2> &get_vertices() const { return vertices; };
+ const Vector<Vector2> &get_vertices() const { return vertices; }
void set_avoidance_layers(uint32_t p_layers);
uint32_t get_avoidance_layers() const;
@@ -96,7 +96,7 @@ public:
bool get_avoidance_layer_value(int p_layer_number) const;
void set_velocity(const Vector2 p_velocity);
- Vector2 get_velocity() const { return velocity; };
+ Vector2 get_velocity() const { return velocity; }
void _avoidance_done(Vector3 p_new_velocity); // Dummy
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 5813ab02e3..7d645ba448 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -167,17 +167,16 @@ void Path2D::_curve_changed() {
return;
}
- if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_paths_hint()) {
- return;
- }
-
- queue_redraw();
for (int i = 0; i < get_child_count(); i++) {
PathFollow2D *follow = Object::cast_to<PathFollow2D>(get_child(i));
if (follow) {
follow->path_changed();
}
}
+
+ if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_paths_hint()) {
+ queue_redraw();
+ }
}
void Path2D::set_curve(const Ref<Curve2D> &p_curve) {
diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp
index ebb03e4e73..f737e23126 100644
--- a/scene/2d/tile_map_layer.cpp
+++ b/scene/2d/tile_map_layer.cpp
@@ -946,7 +946,7 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect
rs->canvas_item_add_set_transform(p_canvas_item, Transform2D());
}
}
-};
+}
#endif // DEBUG_ENABLED
/////////////////////////////// Navigation //////////////////////////////////////
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index c70fa3ca2e..aafc2141af 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -377,7 +377,7 @@ void Camera3D::set_projection(ProjectionType p_mode) {
RID Camera3D::get_camera() const {
return camera;
-};
+}
void Camera3D::make_current() {
current = true;
@@ -423,7 +423,7 @@ bool Camera3D::is_current() const {
Vector3 Camera3D::project_ray_normal(const Point2 &p_pos) const {
Vector3 ray = project_local_ray_normal(p_pos);
return get_camera_transform().basis.xform(ray).normalized();
-};
+}
Vector3 Camera3D::project_local_ray_normal(const Point2 &p_pos) const {
ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
@@ -441,7 +441,7 @@ Vector3 Camera3D::project_local_ray_normal(const Point2 &p_pos) const {
}
return ray;
-};
+}
Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const {
ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
@@ -470,7 +470,7 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const {
} else {
return get_camera_transform().origin;
};
-};
+}
bool Camera3D::is_position_behind(const Vector3 &p_pos) const {
Transform3D t = get_global_transform();
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index acbc443a93..5b84bf903f 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -1479,6 +1479,7 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh"), &CPUParticles3D::get_mesh);
ClassDB::bind_method(D_METHOD("restart"), &CPUParticles3D::restart);
+ ClassDB::bind_method(D_METHOD("capture_aabb"), &CPUParticles3D::capture_aabb);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index 7b70986adc..2d18e62b10 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -146,6 +146,15 @@ bool Light3D::get_shadow_reverse_cull_face() const {
return reverse_cull;
}
+void Light3D::set_shadow_caster_mask(uint32_t p_caster_mask) {
+ shadow_caster_mask = p_caster_mask;
+ RS::get_singleton()->light_set_shadow_caster_mask(light, shadow_caster_mask);
+}
+
+uint32_t Light3D::get_shadow_caster_mask() const {
+ return shadow_caster_mask;
+}
+
AABB Light3D::get_aabb() const {
if (type == RenderingServer::LIGHT_DIRECTIONAL) {
return AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
@@ -300,7 +309,7 @@ bool Light3D::is_editor_only() const {
}
void Light3D::_validate_property(PropertyInfo &p_property) const {
- if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow")) {
+ if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow" || p_property.name == "shadow_caster_mask")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
@@ -354,6 +363,9 @@ void Light3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shadow_reverse_cull_face", "enable"), &Light3D::set_shadow_reverse_cull_face);
ClassDB::bind_method(D_METHOD("get_shadow_reverse_cull_face"), &Light3D::get_shadow_reverse_cull_face);
+ ClassDB::bind_method(D_METHOD("set_shadow_caster_mask", "caster_mask"), &Light3D::set_shadow_caster_mask);
+ ClassDB::bind_method(D_METHOD("get_shadow_caster_mask"), &Light3D::get_shadow_caster_mask);
+
ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light3D::set_bake_mode);
ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light3D::get_bake_mode);
@@ -388,6 +400,7 @@ void Light3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_OPACITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BLUR);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_caster_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_shadow_caster_mask", "get_shadow_caster_mask");
ADD_GROUP("Distance Fade", "distance_fade_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled");
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index d6eca8d8b6..5f549469c6 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -75,6 +75,7 @@ private:
bool negative = false;
bool reverse_cull = false;
uint32_t cull_mask = 0;
+ uint32_t shadow_caster_mask = 0xFFFFFFFF;
bool distance_fade_enabled = false;
real_t distance_fade_begin = 40.0;
real_t distance_fade_shadow = 50.0;
@@ -136,6 +137,9 @@ public:
void set_shadow_reverse_cull_face(bool p_enable);
bool get_shadow_reverse_cull_face() const;
+ void set_shadow_caster_mask(uint32_t p_caster_mask);
+ uint32_t get_shadow_caster_mask() const;
+
void set_bake_mode(BakeMode p_mode);
BakeMode get_bake_mode() const;
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index a1f32fccbe..c658bfd799 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -98,15 +98,15 @@ Array LightmapGIData::_get_user_data() const {
}
void LightmapGIData::set_lightmap_textures(const TypedArray<TextureLayered> &p_data) {
- light_textures = p_data;
+ storage_light_textures = p_data;
if (p_data.is_empty()) {
- light_texture = Ref<TextureLayered>();
+ combined_light_texture = Ref<TextureLayered>();
_reset_lightmap_textures();
return;
}
if (p_data.size() == 1) {
- light_texture = p_data[0];
+ combined_light_texture = p_data[0];
} else {
Vector<Ref<Image>> images;
for (int i = 0; i < p_data.size(); i++) {
@@ -121,13 +121,13 @@ void LightmapGIData::set_lightmap_textures(const TypedArray<TextureLayered> &p_d
combined_texture.instantiate();
combined_texture->create_from_images(images);
- light_texture = combined_texture;
+ combined_light_texture = combined_texture;
}
_reset_lightmap_textures();
}
TypedArray<TextureLayered> LightmapGIData::get_lightmap_textures() const {
- return light_textures;
+ return storage_light_textures;
}
RID LightmapGIData::get_rid() const {
@@ -139,7 +139,7 @@ void LightmapGIData::clear() {
}
void LightmapGIData::_reset_lightmap_textures() {
- RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
+ RS::get_singleton()->lightmap_set_textures(lightmap, combined_light_texture.is_valid() ? combined_light_texture->get_rid() : RID(), uses_spherical_harmonics);
}
void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) {
@@ -238,10 +238,10 @@ void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_textur
}
Ref<TextureLayered> LightmapGIData::get_light_texture() const {
- if (light_textures.is_empty()) {
+ if (storage_light_textures.is_empty()) {
return Ref<TextureLayered>();
}
- return light_textures.get(0);
+ return storage_light_textures.get(0);
}
void LightmapGIData::_set_light_textures_data(const Array &p_data) {
@@ -249,7 +249,7 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) {
}
Array LightmapGIData::_get_light_textures_data() const {
- return Array(light_textures);
+ return Array(storage_light_textures);
}
#endif
@@ -274,7 +274,7 @@ void LightmapGIData::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data);
ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lightmap_textures", PROPERTY_HINT_ARRAY_TYPE, "TextureLayered", PROPERTY_USAGE_NO_EDITOR), "set_lightmap_textures", "get_lightmap_textures");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lightmap_textures", PROPERTY_HINT_ARRAY_TYPE, "TextureLayered", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY), "set_lightmap_textures", "get_lightmap_textures");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
@@ -287,8 +287,8 @@ void LightmapGIData::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_light_textures_data", "data"), &LightmapGIData::_set_light_textures_data);
ClassDB::bind_method(D_METHOD("_get_light_textures_data"), &LightmapGIData::_get_light_textures_data);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_EDITOR), "set_light_texture", "get_light_texture");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered", PROPERTY_USAGE_NONE), "set_light_texture", "get_light_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "light_textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "_set_light_textures_data", "_get_light_textures_data");
#endif
}
@@ -740,6 +740,74 @@ void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, f
}
}
+LightmapGI::BakeError LightmapGI::_save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_compress) const {
+ Vector<Ref<Image>> images;
+ images.resize(p_lightmapper->get_bake_texture_count());
+
+ for (int i = 0; i < images.size(); i++) {
+ images.set(i, p_lightmapper->get_bake_texture(i));
+ }
+
+ const int slice_count = images.size();
+ const int slice_width = images[0]->get_width();
+ const int slice_height = images[0]->get_height();
+
+ const int slices_per_texture = Image::MAX_HEIGHT / slice_height;
+ const int texture_count = Math::ceil(slice_count / (float)slices_per_texture);
+ const int last_count = slice_count % slices_per_texture;
+
+ r_textures.resize(texture_count);
+
+ for (int i = 0; i < texture_count; i++) {
+ const int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture;
+
+ Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
+
+ for (int j = 0; j < texture_slice_count; j++) {
+ texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
+ }
+
+ const String atlas_path = (texture_count > 1 ? p_base_name + "_" + itos(i) : p_base_name) + ".exr";
+ const String config_path = atlas_path + ".import";
+
+ Ref<ConfigFile> config;
+ config.instantiate();
+
+ // Load an import configuration if present.
+ if (FileAccess::exists(config_path)) {
+ config->load(config_path);
+ }
+
+ config->set_value("remap", "importer", "2d_array_texture");
+ config->set_value("remap", "type", "CompressedTexture2DArray");
+ if (!config->has_section_key("params", "compress/mode")) {
+ // Do not override an existing compression mode.
+ config->set_value("params", "compress/mode", p_compress ? 2 : 3);
+ }
+ config->set_value("params", "compress/channel_pack", 1);
+ config->set_value("params", "mipmaps/generate", false);
+ config->set_value("params", "slices/horizontal", 1);
+ config->set_value("params", "slices/vertical", texture_slice_count);
+
+ config->save(config_path);
+
+ // Save the file.
+ Error save_err = texture_image->save_exr(atlas_path, false);
+
+ ERR_FAIL_COND_V(save_err, LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE);
+
+ // Reimport the file.
+ ResourceLoader::import(atlas_path);
+ Ref<TextureLayered> t = ResourceLoader::load(atlas_path); // If already loaded, it will be updated on refocus?
+ ERR_FAIL_COND_V(t.is_null(), LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE);
+
+ // Store the atlas in the array.
+ r_textures[i] = t;
+ }
+
+ return LightmapGI::BAKE_ERROR_OK;
+}
+
LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) {
if (p_image_data_path.is_empty()) {
if (get_light_data().is_null()) {
@@ -1127,80 +1195,30 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
// POSTBAKE: Save Textures.
- TypedArray<TextureLayered> textures;
- {
- Vector<Ref<Image>> images;
- images.resize(lightmapper->get_bake_texture_count());
- for (int i = 0; i < images.size(); i++) {
- images.set(i, lightmapper->get_bake_texture(i));
- }
-
- int slice_count = images.size();
- int slice_width = images[0]->get_width();
- int slice_height = images[0]->get_height();
+ TypedArray<TextureLayered> lightmap_textures;
- int slices_per_texture = Image::MAX_HEIGHT / slice_height;
- int texture_count = Math::ceil(slice_count / (float)slices_per_texture);
+ const String texture_filename = p_image_data_path.get_basename();
- textures.resize(texture_count);
+ // Save the lightmap atlases.
+ BakeError save_err = _save_and_reimport_atlas_textures(lightmapper, texture_filename, lightmap_textures, false);
+ ERR_FAIL_COND_V(save_err != BAKE_ERROR_OK, save_err);
- String base_path = p_image_data_path.get_basename();
-
- int last_count = slice_count % slices_per_texture;
- for (int i = 0; i < texture_count; i++) {
- int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture;
-
- Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
-
- for (int j = 0; j < texture_slice_count; j++) {
- texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
- }
-
- String texture_path = texture_count > 1 ? base_path + "_" + itos(i) + ".exr" : base_path + ".exr";
-
- Ref<ConfigFile> config;
- config.instantiate();
-
- if (FileAccess::exists(texture_path + ".import")) {
- config->load(texture_path + ".import");
- }
-
- config->set_value("remap", "importer", "2d_array_texture");
- config->set_value("remap", "type", "CompressedTexture2DArray");
- if (!config->has_section_key("params", "compress/mode")) {
- // User may want another compression, so leave it be, but default to VRAM uncompressed.
- config->set_value("params", "compress/mode", 3);
- }
- config->set_value("params", "compress/channel_pack", 1);
- config->set_value("params", "mipmaps/generate", false);
- config->set_value("params", "slices/horizontal", 1);
- config->set_value("params", "slices/vertical", texture_slice_count);
-
- config->save(texture_path + ".import");
-
- Error err = texture_image->save_exr(texture_path, false);
- ERR_FAIL_COND_V(err, BAKE_ERROR_CANT_CREATE_IMAGE);
- ResourceLoader::import(texture_path);
- Ref<TextureLayered> t = ResourceLoader::load(texture_path); // If already loaded, it will be updated on refocus?
- ERR_FAIL_COND_V(t.is_null(), BAKE_ERROR_CANT_CREATE_IMAGE);
- textures[i] = t;
- }
- }
-
- /* POSTBAKE: Save Light Data */
+ // POSTBAKE: Save Light Data.
Ref<LightmapGIData> gi_data;
+
if (get_light_data().is_valid()) {
gi_data = get_light_data();
- set_light_data(Ref<LightmapGIData>()); //clear
+ set_light_data(Ref<LightmapGIData>()); // Clear.
gi_data->clear();
+
} else {
gi_data.instantiate();
}
- gi_data->set_lightmap_textures(textures);
- gi_data->_set_uses_packed_directional(directional); // New SH lightmaps are packed automatically.
+ gi_data->set_lightmap_textures(lightmap_textures);
gi_data->set_uses_spherical_harmonics(directional);
+ gi_data->_set_uses_packed_directional(directional); // New SH lightmaps are packed automatically.
for (int i = 0; i < lightmapper->get_bake_mesh_count(); i++) {
Dictionary d = lightmapper->get_bake_mesh_userdata(i);
@@ -1602,19 +1620,16 @@ Ref<CameraAttributes> LightmapGI::get_camera_attributes() const {
PackedStringArray LightmapGI::get_configuration_warnings() const {
PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
-#ifndef MODULE_LIGHTMAPPER_RD_ENABLED
-#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
- warnings.push_back(vformat(RTR("Lightmaps cannot be baked on %s. Rendering existing baked lightmaps will still work."), OS::get_singleton()->get_name()));
-#else
- warnings.push_back(RTR("Lightmaps cannot be baked, as the `lightmapper_rd` module was disabled at compile-time. Rendering existing baked lightmaps will still work."));
-#endif
- return warnings;
-#endif
-
+#ifdef MODULE_LIGHTMAPPER_RD_ENABLED
if (!DisplayServer::get_singleton()->can_create_rendering_device()) {
warnings.push_back(vformat(RTR("Lightmaps can only be baked from a GPU that supports the RenderingDevice backends.\nYour GPU (%s) does not support RenderingDevice, as it does not support Vulkan, Direct3D 12, or Metal.\nLightmap baking will not be available on this device, although rendering existing baked lightmaps will work."), RenderingServer::get_singleton()->get_video_adapter_name()));
return warnings;
}
+#elif defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
+ warnings.push_back(vformat(RTR("Lightmaps cannot be baked on %s. Rendering existing baked lightmaps will still work."), OS::get_singleton()->get_name()));
+#else
+ warnings.push_back(RTR("Lightmaps cannot be baked, as the `lightmapper_rd` module was disabled at compile-time. Rendering existing baked lightmaps will still work."));
+#endif
return warnings;
}
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 6377c420d1..0476061c60 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -43,8 +43,12 @@ class LightmapGIData : public Resource {
GDCLASS(LightmapGIData, Resource);
RES_BASE_EXTENSION("lmbake")
- Ref<TextureLayered> light_texture;
- TypedArray<TextureLayered> light_textures;
+ // The 'merged' texture atlases actually used by the renderer.
+ Ref<TextureLayered> combined_light_texture;
+
+ // The temporary texture atlas arrays which are used for storage.
+ // If a single atlas is too large, it's split and recombined during loading.
+ TypedArray<TextureLayered> storage_light_textures;
bool uses_spherical_harmonics = false;
bool interior = false;
@@ -245,6 +249,8 @@ private:
void _plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle);
void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds);
+ BakeError _save_and_reimport_atlas_textures(const Ref<Lightmapper> p_lightmapper, const String &p_base_name, TypedArray<TextureLayered> &r_textures, bool p_compress = false) const;
+
protected:
void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index e8166802f8..f551cb401c 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -332,8 +332,8 @@ void MeshInstance3D::create_multiple_convex_collisions(const Ref<MeshConvexDecom
void MeshInstance3D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- callable_mp(this, &MeshInstance3D::_resolve_skeleton_path).call_deferred();
+ case NOTIFICATION_ENTER_TREE: {
+ _resolve_skeleton_path();
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
if (mesh.is_valid()) {
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index e9a4669fa2..99288fc59e 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -95,7 +95,7 @@ public:
real_t get_height() const { return height; }
void set_vertices(const Vector<Vector3> &p_vertices);
- const Vector<Vector3> &get_vertices() const { return vertices; };
+ const Vector<Vector3> &get_vertices() const { return vertices; }
void set_avoidance_layers(uint32_t p_layers);
uint32_t get_avoidance_layers() const;
@@ -107,7 +107,7 @@ public:
bool get_use_3d_avoidance() const { return use_3d_avoidance; }
void set_velocity(const Vector3 p_velocity);
- Vector3 get_velocity() const { return velocity; };
+ Vector3 get_velocity() const { return velocity; }
void _avoidance_done(Vector3 p_new_velocity); // Dummy
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 217ee28cf1..20288fad3a 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -233,8 +233,8 @@ public:
#ifdef TOOLS_ENABLED
virtual Transform3D get_global_gizmo_transform() const;
virtual Transform3D get_local_gizmo_transform() const;
- virtual void set_transform_gizmo_visible(bool p_enabled) { data.transform_gizmo_visible = p_enabled; };
- virtual bool is_transform_gizmo_visible() const { return data.transform_gizmo_visible; };
+ virtual void set_transform_gizmo_visible(bool p_enabled) { data.transform_gizmo_visible = p_enabled; }
+ virtual bool is_transform_gizmo_visible() const { return data.transform_gizmo_visible; }
#endif
virtual void reparent(Node *p_parent, bool p_keep_global_transform = true) override;
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index f778fccf09..c1c992588b 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -276,6 +276,8 @@ void Skeleton3D::_update_process_order() {
concatenated_bone_names = StringName();
+ _update_bones_nested_set();
+
process_order_dirty = false;
emit_signal("bone_list_changed");
@@ -324,6 +326,8 @@ void Skeleton3D::_notification(int p_what) {
#ifndef DISABLE_DEPRECATED
setup_simulator();
#endif // _DISABLE_DEPRECATED
+ update_flags = UPDATE_FLAG_POSE;
+ _notification(NOTIFICATION_UPDATE_SKELETON);
} break;
case NOTIFICATION_UPDATE_SKELETON: {
// Update bone transforms to apply unprocessed poses.
@@ -334,6 +338,8 @@ void Skeleton3D::_notification(int p_what) {
Bone *bonesptr = bones.ptr();
int len = bones.size();
+ thread_local LocalVector<bool> bone_global_pose_dirty_backup;
+
// Process modifiers.
_find_modifiers();
if (!modifiers.is_empty()) {
@@ -341,6 +347,9 @@ void Skeleton3D::_notification(int p_what) {
for (uint32_t i = 0; i < bones.size(); i++) {
bones_backup[i].save(bones[i]);
}
+ // Store dirty flags for global bone poses.
+ bone_global_pose_dirty_backup = bone_global_pose_dirty;
+
_process_modifiers();
}
@@ -415,6 +424,8 @@ void Skeleton3D::_notification(int p_what) {
for (uint32_t i = 0; i < bones.size(); i++) {
bones_backup[i].restore(bones[i]);
}
+ // Restore dirty flags for global bone poses.
+ bone_global_pose_dirty = bone_global_pose_dirty_backup;
}
updating = false;
@@ -457,10 +468,111 @@ void Skeleton3D::_make_modifiers_dirty() {
_update_deferred(UPDATE_FLAG_MODIFIER);
}
+void Skeleton3D::_update_bones_nested_set() {
+ nested_set_offset_to_bone_index.resize(bones.size());
+ bone_global_pose_dirty.resize(bones.size());
+ _make_bone_global_poses_dirty();
+
+ int offset = 0;
+ for (int bone : parentless_bones) {
+ offset += _update_bone_nested_set(bone, offset);
+ }
+}
+
+int Skeleton3D::_update_bone_nested_set(int p_bone, int p_offset) {
+ Bone &bone = bones[p_bone];
+ int offset = p_offset + 1;
+ int span = 1;
+
+ for (int child_bone : bone.child_bones) {
+ int subspan = _update_bone_nested_set(child_bone, offset);
+ offset += subspan;
+ span += subspan;
+ }
+
+ nested_set_offset_to_bone_index[p_offset] = p_bone;
+ bone.nested_set_offset = p_offset;
+ bone.nested_set_span = span;
+
+ return span;
+}
+
+void Skeleton3D::_make_bone_global_poses_dirty() {
+ for (uint32_t i = 0; i < bone_global_pose_dirty.size(); i++) {
+ bone_global_pose_dirty[i] = true;
+ }
+}
+
+void Skeleton3D::_make_bone_global_pose_subtree_dirty(int p_bone) {
+ if (process_order_dirty) {
+ return;
+ }
+
+ const Bone &bone = bones[p_bone];
+ int span_offset = bone.nested_set_offset;
+ // No need to make subtree dirty when bone is already dirty.
+ if (bone_global_pose_dirty[span_offset]) {
+ return;
+ }
+
+ // Make global poses of subtree dirty.
+ int span_end = span_offset + bone.nested_set_span;
+ for (int i = span_offset; i < span_end; i++) {
+ bone_global_pose_dirty[i] = true;
+ }
+}
+
+void Skeleton3D::_update_bone_global_pose(int p_bone) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+
+ _update_process_order();
+
+ // Global pose is already calculated.
+ int nested_set_offset = bones[p_bone].nested_set_offset;
+ if (!bone_global_pose_dirty[nested_set_offset]) {
+ return;
+ }
+
+ thread_local LocalVector<int> bone_list;
+ bone_list.clear();
+ Transform3D global_pose;
+
+ // Create list of parent bones for which the global pose needs to be recalculated.
+ for (int bone = p_bone; bone >= 0; bone = bones[bone].parent) {
+ int offset = bones[bone].nested_set_offset;
+ // Stop searching when global pose is not dirty.
+ if (!bone_global_pose_dirty[offset]) {
+ global_pose = bones[bone].global_pose;
+ break;
+ }
+
+ bone_list.push_back(bone);
+ }
+
+ // Calculate global poses for all parent bones and the current bone.
+ for (int i = bone_list.size() - 1; i >= 0; i--) {
+ int bone_idx = bone_list[i];
+ Bone &bone = bones[bone_idx];
+ bool bone_enabled = bone.enabled && !show_rest_only;
+ Transform3D bone_pose = bone_enabled ? get_bone_pose(bone_idx) : get_bone_rest(bone_idx);
+
+ global_pose *= bone_pose;
+#ifndef DISABLE_DEPRECATED
+ if (bone.global_pose_override_amount >= CMP_EPSILON) {
+ global_pose = global_pose.interpolate_with(bone.global_pose_override, bone.global_pose_override_amount);
+ }
+#endif // _DISABLE_DEPRECATED
+
+ bone.global_pose = global_pose;
+ bone_global_pose_dirty[bone.nested_set_offset] = false;
+ }
+}
+
Transform3D Skeleton3D::get_bone_global_pose(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
- const_cast<Skeleton3D *>(this)->force_update_all_dirty_bones();
+ const_cast<Skeleton3D *>(this)->_update_bone_global_pose(p_bone);
return bones[p_bone].global_pose;
}
@@ -672,6 +784,7 @@ void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &p_rest) {
bones[p_bone].rest = p_rest;
rest_dirty = true;
_make_dirty();
+ _make_bone_global_pose_subtree_dirty(p_bone);
}
Transform3D Skeleton3D::get_bone_rest(int p_bone) const {
const int bone_size = bones.size();
@@ -695,6 +808,7 @@ void Skeleton3D::set_bone_enabled(int p_bone, bool p_enabled) {
bones[p_bone].enabled = p_enabled;
emit_signal(SceneStringName(bone_enabled_changed), p_bone);
_make_dirty();
+ _make_bone_global_pose_subtree_dirty(p_bone);
}
bool Skeleton3D::is_bone_enabled(int p_bone) const {
@@ -707,6 +821,7 @@ void Skeleton3D::set_show_rest_only(bool p_enabled) {
show_rest_only = p_enabled;
emit_signal(SceneStringName(show_rest_only_changed));
_make_dirty();
+ _make_bone_global_poses_dirty();
}
bool Skeleton3D::is_show_rest_only() const {
@@ -733,6 +848,7 @@ void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) {
bones[p_bone].pose_cache_dirty = true;
if (is_inside_tree()) {
_make_dirty();
+ _make_bone_global_pose_subtree_dirty(p_bone);
}
}
@@ -744,6 +860,7 @@ void Skeleton3D::set_bone_pose_position(int p_bone, const Vector3 &p_position) {
bones[p_bone].pose_cache_dirty = true;
if (is_inside_tree()) {
_make_dirty();
+ _make_bone_global_pose_subtree_dirty(p_bone);
}
}
void Skeleton3D::set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation) {
@@ -754,6 +871,7 @@ void Skeleton3D::set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation
bones[p_bone].pose_cache_dirty = true;
if (is_inside_tree()) {
_make_dirty();
+ _make_bone_global_pose_subtree_dirty(p_bone);
}
}
void Skeleton3D::set_bone_pose_scale(int p_bone, const Vector3 &p_scale) {
@@ -764,6 +882,7 @@ void Skeleton3D::set_bone_pose_scale(int p_bone, const Vector3 &p_scale) {
bones[p_bone].pose_cache_dirty = true;
if (is_inside_tree()) {
_make_dirty();
+ _make_bone_global_pose_subtree_dirty(p_bone);
}
}
@@ -938,14 +1057,14 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
ERR_FAIL_INDEX(p_bone_idx, bone_size);
Bone *bonesptr = bones.ptr();
- thread_local LocalVector<int> bones_to_process;
- bones_to_process.clear();
- bones_to_process.push_back(p_bone_idx);
- uint32_t index = 0;
- while (index < bones_to_process.size()) {
- int current_bone_idx = bones_to_process[index];
+ // Loop through nested set.
+ for (int offset = 0; offset < bone_size; offset++) {
+ if (!bone_global_pose_dirty[offset]) {
+ continue;
+ }
+ int current_bone_idx = nested_set_offset_to_bone_index[offset];
Bone &b = bonesptr[current_bone_idx];
bool bone_enabled = b.enabled && !show_rest_only;
@@ -992,13 +1111,7 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
}
#endif // _DISABLE_DEPRECATED
- // Add the bone's children to the list of bones to be processed.
- int child_bone_size = b.child_bones.size();
- for (int i = 0; i < child_bone_size; i++) {
- bones_to_process.push_back(b.child_bones[i]);
- }
-
- index++;
+ bone_global_pose_dirty[offset] = false;
}
}
@@ -1176,6 +1289,7 @@ void Skeleton3D::clear_bones_global_pose_override() {
bones[i].global_pose_override_reset = true;
}
_make_dirty();
+ _make_bone_global_poses_dirty();
}
void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) {
@@ -1185,6 +1299,7 @@ void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_
bones[p_bone].global_pose_override = p_pose;
bones[p_bone].global_pose_override_reset = !p_persistent;
_make_dirty();
+ _make_bone_global_pose_subtree_dirty(p_bone);
}
Transform3D Skeleton3D::get_bone_global_pose_override(int p_bone) const {
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 7213dc580c..ecfe095f1d 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -31,6 +31,7 @@
#ifndef SKELETON_3D_H
#define SKELETON_3D_H
+#include "core/templates/a_hash_map.h"
#include "scene/3d/node_3d.h"
#include "scene/resources/3d/skin.h"
@@ -107,6 +108,8 @@ private:
Quaternion pose_rotation;
Vector3 pose_scale = Vector3(1, 1, 1);
Transform3D global_pose;
+ int nested_set_offset = 0; // Offset in nested set of bone hierarchy.
+ int nested_set_span = 0; // Subtree span in nested set of bone hierarchy.
void update_pose_cache() {
if (pose_cache_dirty) {
@@ -157,7 +160,7 @@ private:
bool process_order_dirty = false;
Vector<int> parentless_bones;
- HashMap<String, int> name_to_bone_index;
+ AHashMap<String, int> name_to_bone_index;
mutable StringName concatenated_bone_names = StringName();
void _update_bone_names() const;
@@ -183,6 +186,15 @@ private:
void _make_modifiers_dirty();
LocalVector<BonePoseBackup> bones_backup;
+ // Global bone pose calculation.
+ LocalVector<int> nested_set_offset_to_bone_index; // Map from Bone::nested_set_offset to bone index.
+ LocalVector<bool> bone_global_pose_dirty; // Indexable with Bone::nested_set_offset.
+ void _update_bones_nested_set();
+ int _update_bone_nested_set(int p_bone, int p_offset);
+ void _make_bone_global_poses_dirty();
+ void _make_bone_global_pose_subtree_dirty(int p_bone);
+ void _update_bone_global_pose(int p_bone);
+
#ifndef DISABLE_DEPRECATED
void _add_bone_bind_compat_88791(const String &p_name);
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 214c1f77ca..9869b241d3 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -89,7 +89,7 @@ PackedStringArray XRCamera3D::get_configuration_warnings() const {
}
return warnings;
-};
+}
Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
// get our XRServer
@@ -114,7 +114,7 @@ Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -get_near()).normalized();
return ray;
-};
+}
Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const {
// get our XRServer
@@ -144,7 +144,7 @@ Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const {
res.y = (-p.normal.y * 0.5 + 0.5) * viewport_size.y;
return res;
-};
+}
Vector3 XRCamera3D::project_position(const Point2 &p_point, real_t p_z_depth) const {
// get our XRServer
@@ -174,7 +174,7 @@ Vector3 XRCamera3D::project_position(const Point2 &p_point, real_t p_z_depth) co
Vector3 p(point.x, point.y, -p_z_depth);
return get_camera_transform().xform(p);
-};
+}
Vector<Plane> XRCamera3D::get_frustum() const {
// get our XRServer
@@ -193,7 +193,7 @@ Vector<Plane> XRCamera3D::get_frustum() const {
// TODO Just use the first view for now, this is mostly for debugging so we may look into using our combined projection here.
Projection cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
return cm.get_projection_planes(get_camera_transform());
-};
+}
XRCamera3D::XRCamera3D() {
XRServer *xr_server = XRServer::get_singleton();
@@ -240,7 +240,7 @@ void XRNode3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("trigger_haptic_pulse", "action_name", "frequency", "amplitude", "duration_sec", "delay_sec"), &XRNode3D::trigger_haptic_pulse);
ADD_SIGNAL(MethodInfo("tracking_changed", PropertyInfo(Variant::BOOL, "tracking")));
-};
+}
void XRNode3D::_validate_property(PropertyInfo &p_property) const {
XRServer *xr_server = XRServer::get_singleton();
@@ -499,7 +499,7 @@ void XRController3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("input_float_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value")));
ADD_SIGNAL(MethodInfo("input_vector2_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "value")));
ADD_SIGNAL(MethodInfo("profile_changed", PropertyInfo(Variant::STRING, "role")));
-};
+}
void XRController3D::_bind_tracker() {
XRNode3D::_bind_tracker();
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index eb8bc8c382..0fa6810d23 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -563,6 +563,7 @@ void AnimationMixer::_clear_caches() {
memdelete(K.value);
}
track_cache.clear();
+ animation_track_num_to_track_cashe.clear();
cache_valid = false;
capture_cache.clear();
@@ -922,6 +923,27 @@ bool AnimationMixer::_update_caches() {
idx++;
}
+ for (KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
+ K.value->blend_idx = track_map[K.value->path];
+ }
+
+ animation_track_num_to_track_cashe.clear();
+ LocalVector<TrackCache *> track_num_to_track_cashe;
+ for (const StringName &E : sname_list) {
+ Ref<Animation> anim = get_animation(E);
+ const Vector<Animation::Track *> tracks = anim->get_tracks();
+ track_num_to_track_cashe.resize(tracks.size());
+ for (int i = 0; i < tracks.size(); i++) {
+ TrackCache **track_ptr = track_cache.getptr(tracks[i]->thash);
+ if (track_ptr == nullptr) {
+ track_num_to_track_cashe[i] = nullptr;
+ } else {
+ track_num_to_track_cashe[i] = *track_ptr;
+ }
+ }
+ animation_track_num_to_track_cashe.insert(anim, track_num_to_track_cashe);
+ }
+
track_count = idx;
cache_valid = true;
@@ -946,7 +968,7 @@ void AnimationMixer::_process_animation(double p_delta, bool p_update_only) {
clear_animation_instances();
}
-Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
+Variant AnimationMixer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant &p_value, ObjectID p_object_id, int p_object_sub_idx) {
#ifndef _3D_DISABLED
switch (p_anim->track_get_type(p_track)) {
case Animation::TYPE_POSITION_3D: {
@@ -1033,7 +1055,7 @@ void AnimationMixer::_blend_init() {
}
}
-bool AnimationMixer::_blend_pre_process(double p_delta, int p_track_count, const HashMap<NodePath, int> &p_track_map) {
+bool AnimationMixer::_blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) {
return true;
}
@@ -1084,26 +1106,30 @@ void AnimationMixer::_blend_calc_total_weight() {
real_t weight = ai.playback_info.weight;
const real_t *track_weights_ptr = ai.playback_info.track_weights.ptr();
int track_weights_count = ai.playback_info.track_weights.size();
- static LocalVector<Animation::TypeHash> processed_hashes;
+ ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cashe.has(a), "No animation in cache.");
+ LocalVector<TrackCache *> &track_num_to_track_cashe = animation_track_num_to_track_cashe[a];
+ thread_local HashSet<Animation::TypeHash, HashHasher> processed_hashes;
processed_hashes.clear();
const Vector<Animation::Track *> tracks = a->get_tracks();
- for (const Animation::Track *animation_track : tracks) {
+ Animation::Track *const *tracks_ptr = tracks.ptr();
+ int count = tracks.size();
+ for (int i = 0; i < count; i++) {
+ Animation::Track *animation_track = tracks_ptr[i];
if (!animation_track->enabled) {
continue;
}
Animation::TypeHash thash = animation_track->thash;
- TrackCache **track_ptr = track_cache.getptr(thash);
- if (track_ptr == nullptr || processed_hashes.has(thash)) {
+ TrackCache *track = track_num_to_track_cashe[i];
+ if (track == nullptr || processed_hashes.has(thash)) {
// No path, but avoid error spamming.
// Or, there is the case different track type with same path; These can be distinguished by hash. So don't add the weight doubly.
continue;
}
- TrackCache *track = *track_ptr;
- int blend_idx = track_map[track->path];
+ int blend_idx = track->blend_idx;
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;
track->total_weight += blend;
- processed_hashes.push_back(thash);
+ processed_hashes.insert(thash);
}
}
}
@@ -1130,6 +1156,8 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
#ifndef _3D_DISABLED
bool calc_root = !seeked || is_external_seeking;
#endif // _3D_DISABLED
+ ERR_CONTINUE_EDMSG(!animation_track_num_to_track_cashe.has(a), "No animation in cache.");
+ LocalVector<TrackCache *> &track_num_to_track_cashe = animation_track_num_to_track_cashe[a];
const Vector<Animation::Track *> tracks = a->get_tracks();
Animation::Track *const *tracks_ptr = tracks.ptr();
real_t a_length = a->get_length();
@@ -1139,15 +1167,11 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
if (!animation_track->enabled) {
continue;
}
- Animation::TypeHash thash = animation_track->thash;
- TrackCache **track_ptr = track_cache.getptr(thash);
- if (track_ptr == nullptr) {
+ TrackCache *track = track_num_to_track_cashe[i];
+ if (track == nullptr) {
continue; // No path, but avoid error spamming.
}
- TrackCache *track = *track_ptr;
- int *blend_idx_ptr = track_map.getptr(track->path);
- ERR_CONTINUE(blend_idx_ptr == nullptr);
- int blend_idx = *blend_idx_ptr;
+ int blend_idx = track->blend_idx;
ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count);
real_t blend = blend_idx < track_weights_count ? track_weights_ptr[blend_idx] * weight : weight;
if (!deterministic) {
@@ -1581,7 +1605,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
track_info.loop = a->get_loop_mode() != Animation::LOOP_NONE;
track_info.backward = backward;
track_info.use_blend = a->audio_track_is_use_blend(i);
- HashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;
+ AHashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;
// Main process to fire key is started from here.
if (p_update_only) {
@@ -1850,7 +1874,7 @@ void AnimationMixer::_blend_apply() {
PlayingAudioTrackInfo &track_info = L.value;
float db = Math::linear_to_db(track_info.use_blend ? track_info.volume : 1.0);
LocalVector<int> erase_streams;
- HashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;
+ AHashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;
for (const KeyValue<int, PlayingAudioStreamInfo> &M : map) {
PlayingAudioStreamInfo pasi = M.value;
@@ -2134,7 +2158,7 @@ void AnimationMixer::restore(const Ref<AnimatedValuesBackup> &p_backup) {
ERR_FAIL_COND(p_backup.is_null());
track_cache = p_backup->get_data();
_blend_apply();
- track_cache = HashMap<Animation::TypeHash, AnimationMixer::TrackCache *>();
+ track_cache = AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher>();
cache_valid = false;
}
@@ -2370,7 +2394,7 @@ AnimationMixer::AnimationMixer() {
AnimationMixer::~AnimationMixer() {
}
-void AnimatedValuesBackup::set_data(const HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> p_data) {
+void AnimatedValuesBackup::set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> p_data) {
clear_data();
for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : p_data) {
@@ -2383,7 +2407,7 @@ void AnimatedValuesBackup::set_data(const HashMap<Animation::TypeHash, Animation
}
}
-HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> AnimatedValuesBackup::get_data() const {
+AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> AnimatedValuesBackup::get_data() const {
HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> ret;
for (const KeyValue<Animation::TypeHash, AnimationMixer::TrackCache *> &E : data) {
AnimationMixer::TrackCache *track = get_cache_copy(E.value);
diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h
index 27c9a00a9c..1906146c56 100644
--- a/scene/animation/animation_mixer.h
+++ b/scene/animation/animation_mixer.h
@@ -31,6 +31,7 @@
#ifndef ANIMATION_MIXER_H
#define ANIMATION_MIXER_H
+#include "core/templates/a_hash_map.h"
#include "scene/animation/tween.h"
#include "scene/main/node.h"
#include "scene/resources/animation.h"
@@ -102,7 +103,7 @@ public:
protected:
/* ---- Data lists ---- */
LocalVector<AnimationLibraryData> animation_libraries;
- HashMap<StringName, AnimationData> animation_set; // HashMap<Library name + Animation name, AnimationData>
+ AHashMap<StringName, AnimationData> animation_set; // HashMap<Library name + Animation name, AnimationData>
TypedArray<StringName> _get_animation_library_list() const;
Vector<String> _get_animation_list() const {
@@ -148,6 +149,7 @@ protected:
uint64_t setup_pass = 0;
Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION;
NodePath path;
+ int blend_idx = -1;
ObjectID object_id;
real_t total_weight = 0.0;
@@ -269,7 +271,7 @@ protected:
// Audio track information for mixng and ending.
struct PlayingAudioTrackInfo {
- HashMap<int, PlayingAudioStreamInfo> stream_info;
+ AHashMap<int, PlayingAudioStreamInfo> stream_info;
double length = 0.0;
double time = 0.0;
real_t volume = 0.0;
@@ -308,7 +310,8 @@ protected:
};
RootMotionCache root_motion_cache;
- HashMap<Animation::TypeHash, TrackCache *> track_cache;
+ AHashMap<Animation::TypeHash, TrackCache *, HashHasher> track_cache;
+ AHashMap<Ref<Animation>, LocalVector<TrackCache *>> animation_track_num_to_track_cashe;
HashSet<TrackCache *> playing_caches;
Vector<Node *> playing_audio_stream_players;
@@ -324,7 +327,7 @@ protected:
/* ---- Blending processor ---- */
LocalVector<AnimationInstance> animation_instances;
- HashMap<NodePath, int> track_map;
+ AHashMap<NodePath, int> track_map;
int track_count = 0;
bool deterministic = false;
@@ -359,12 +362,12 @@ protected:
virtual void _process_animation(double p_delta, bool p_update_only = false);
// For post process with retrieved key value during blending.
- virtual Variant _post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1);
+ virtual Variant _post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant &p_value, ObjectID p_object_id, int p_object_sub_idx = -1);
Variant post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1);
GDVIRTUAL5RC(Variant, _post_process_key_value, Ref<Animation>, int, Variant, ObjectID, int);
void _blend_init();
- virtual bool _blend_pre_process(double p_delta, int p_track_count, const HashMap<NodePath, int> &p_track_map);
+ virtual bool _blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map);
virtual void _blend_capture(double p_delta);
void _blend_calc_total_weight(); // For undeterministic blending.
void _blend_process(double p_delta, bool p_update_only = false);
@@ -485,11 +488,11 @@ public:
class AnimatedValuesBackup : public RefCounted {
GDCLASS(AnimatedValuesBackup, RefCounted);
- HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> data;
+ AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> data;
public:
- void set_data(const HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> p_data);
- HashMap<Animation::TypeHash, AnimationMixer::TrackCache *> get_data() const;
+ void set_data(const AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> p_data);
+ AHashMap<Animation::TypeHash, AnimationMixer::TrackCache *, HashHasher> get_data() const;
void clear_data();
AnimationMixer::TrackCache *get_cache_copy(AnimationMixer::TrackCache *p_cache) const;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index c3c5399a6b..5cc204100c 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -1619,7 +1619,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachine::_process(const AnimationM
playback_new = playback_new->duplicate(); // Don't process original when testing.
}
- return playback_new->process(node_state.base_path, this, p_playback_info, p_test_only);
+ return playback_new->process(node_state.get_base_path(), this, p_playback_info, p_test_only);
}
String AnimationNodeStateMachine::get_caption() const {
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 8a2ca47920..b3a75a75a0 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -133,7 +133,7 @@ void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> anim_names;
for (const KeyValue<StringName, AnimationData> &E : animation_set) {
- HashMap<StringName, StringName>::ConstIterator F = animation_next_set.find(E.key);
+ AHashMap<StringName, StringName>::ConstIterator F = animation_next_set.find(E.key);
if (F && F->value != StringName()) {
anim_names.push_back(PropertyInfo(Variant::STRING, "next/" + String(E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
}
@@ -299,7 +299,7 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) {
}
}
-bool AnimationPlayer::_blend_pre_process(double p_delta, int p_track_count, const HashMap<NodePath, int> &p_track_map) {
+bool AnimationPlayer::_blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) {
if (!playback.current.from) {
_set_process(false);
return false;
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 3223e2522d..06b3eecb89 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -52,7 +52,7 @@ public:
#endif // DISABLE_DEPRECATED
private:
- HashMap<StringName, StringName> animation_next_set; // For auto advance.
+ AHashMap<StringName, StringName> animation_next_set; // For auto advance.
float speed_scale = 1.0;
double default_blend_time = 0.0;
@@ -138,7 +138,7 @@ protected:
static void _bind_methods();
// Make animation instances.
- virtual bool _blend_pre_process(double p_delta, int p_track_count, const HashMap<NodePath, int> &p_track_map) override;
+ virtual bool _blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) override;
virtual void _blend_capture(double p_delta) override;
virtual void _blend_post_process() override;
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 19080e61de..d676e2acf4 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -75,20 +75,34 @@ void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_val
if (process_state->is_testing) {
return;
}
+
+ const AHashMap<StringName, int>::Iterator it = property_cache.find(p_name);
+ if (it) {
+ process_state->tree->property_map.get_by_index(it->value).value.first = p_value;
+ return;
+ }
+
ERR_FAIL_COND(!process_state->tree->property_parent_map.has(node_state.base_path));
ERR_FAIL_COND(!process_state->tree->property_parent_map[node_state.base_path].has(p_name));
StringName path = process_state->tree->property_parent_map[node_state.base_path][p_name];
-
- process_state->tree->property_map[path].first = p_value;
+ int idx = process_state->tree->property_map.get_index(path);
+ property_cache.insert_new(p_name, idx);
+ process_state->tree->property_map.get_by_index(idx).value.first = p_value;
}
Variant AnimationNode::get_parameter(const StringName &p_name) const {
ERR_FAIL_NULL_V(process_state, Variant());
+ const AHashMap<StringName, int>::ConstIterator it = property_cache.find(p_name);
+ if (it) {
+ return process_state->tree->property_map.get_by_index(it->value).value.first;
+ }
ERR_FAIL_COND_V(!process_state->tree->property_parent_map.has(node_state.base_path), Variant());
ERR_FAIL_COND_V(!process_state->tree->property_parent_map[node_state.base_path].has(p_name), Variant());
StringName path = process_state->tree->property_parent_map[node_state.base_path][p_name];
- return process_state->tree->property_map[path].first;
+ int idx = process_state->tree->property_map.get_index(path);
+ property_cache.insert_new(p_name, idx);
+ return process_state->tree->property_map.get_by_index(idx).value.first;
}
void AnimationNode::set_node_time_info(const NodeTimeInfo &p_node_time_info) {
@@ -203,7 +217,7 @@ AnimationNode::NodeTimeInfo AnimationNode::_blend_node(Ref<AnimationNode> p_node
}
for (const KeyValue<NodePath, bool> &E : filter) {
- const HashMap<NodePath, int> &map = *process_state->track_map;
+ const AHashMap<NodePath, int> &map = *process_state->track_map;
if (!map.has(E.key)) {
continue;
}
@@ -292,7 +306,7 @@ AnimationNode::NodeTimeInfo AnimationNode::_blend_node(Ref<AnimationNode> p_node
// This process, which depends on p_sync is needed to process sync correctly in the case of
// that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync.
- p_node->node_state.base_path = new_path;
+ p_node->set_node_state_base_path(new_path);
p_node->node_state.parent = new_parent;
if (!p_playback_info.seeked && !p_sync && !any_valid) {
p_playback_info.delta = 0.0;
@@ -603,7 +617,7 @@ Ref<AnimationRootNode> AnimationTree::get_root_animation_node() const {
return root_animation_node;
}
-bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const HashMap<NodePath, int> &p_track_map) {
+bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) {
_update_properties(); // If properties need updating, update them.
if (!root_animation_node.is_valid()) {
@@ -627,7 +641,7 @@ bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const
for (int i = 0; i < p_track_count; i++) {
src_blendsw[i] = 1.0; // By default all go to 1 for the root input.
}
- root_animation_node->node_state.base_path = SNAME(Animation::PARAMETERS_BASE_PATH.ascii().get_data());
+ root_animation_node->set_node_state_base_path(SNAME(Animation::PARAMETERS_BASE_PATH.ascii().get_data()));
root_animation_node->node_state.parent = nullptr;
}
@@ -732,7 +746,7 @@ void AnimationTree::_animation_node_removed(const ObjectID &p_oid, const StringN
void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> p_node) {
ERR_FAIL_COND(p_node.is_null());
if (!property_parent_map.has(p_base_path)) {
- property_parent_map[p_base_path] = HashMap<StringName, StringName>();
+ property_parent_map[p_base_path] = AHashMap<StringName, StringName>();
}
if (!property_reference_map.has(p_node->get_instance_id())) {
property_reference_map[p_node->get_instance_id()] = p_base_path;
@@ -767,7 +781,7 @@ void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<A
pinfo.name = p_base_path + key;
properties.push_back(pinfo);
}
-
+ p_node->make_cache_dirty();
List<AnimationNode::ChildNode> children;
p_node->get_child_nodes(&children);
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index ec5e88b776..eb25a8db1b 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -60,7 +60,7 @@ public:
bool closable = false;
Vector<Input> inputs;
- HashMap<NodePath, bool> filter;
+ AHashMap<NodePath, bool> filter;
bool filter_enabled = false;
// To propagate information from upstream for use in estimation of playback progress.
@@ -97,22 +97,57 @@ public:
// Temporary state for blending process which needs to be stored in each AnimationNodes.
struct NodeState {
+ friend AnimationNode;
+
+ private:
StringName base_path;
+
+ public:
AnimationNode *parent = nullptr;
Vector<StringName> connections;
Vector<real_t> track_weights;
+
+ const StringName get_base_path() const {
+ return base_path;
+ }
+
} node_state;
// Temporary state for blending process which needs to be started in the AnimationTree, pass through the AnimationNodes, and then return to the AnimationTree.
struct ProcessState {
AnimationTree *tree = nullptr;
- const HashMap<NodePath, int> *track_map; // TODO: Is there a better way to manage filter/tracks?
+ const AHashMap<NodePath, int> *track_map; // TODO: Is there a better way to manage filter/tracks?
bool is_testing = false;
bool valid = false;
String invalid_reasons;
uint64_t last_pass = 0;
} *process_state = nullptr;
+private:
+ mutable AHashMap<StringName, int> property_cache;
+
+public:
+ void set_node_state_base_path(const StringName p_base_path) {
+ if (p_base_path != node_state.base_path) {
+ node_state.base_path = p_base_path;
+ make_cache_dirty();
+ }
+ }
+
+ void set_node_state_base_path(const String p_base_path) {
+ if (p_base_path != node_state.base_path) {
+ node_state.base_path = p_base_path;
+ make_cache_dirty();
+ }
+ }
+
+ const StringName get_node_state_base_path() const {
+ return node_state.get_base_path();
+ }
+
+ void make_cache_dirty() {
+ property_cache.clear();
+ }
Array _get_filters() const;
void _set_filters(const Array &p_filters);
friend class AnimationNodeBlendTree;
@@ -250,9 +285,9 @@ private:
friend class AnimationNode;
List<PropertyInfo> properties;
- HashMap<StringName, HashMap<StringName, StringName>> property_parent_map;
- HashMap<ObjectID, StringName> property_reference_map;
- HashMap<StringName, Pair<Variant, bool>> property_map; // Property value and read-only flag.
+ AHashMap<StringName, AHashMap<StringName, StringName>> property_parent_map;
+ AHashMap<ObjectID, StringName> property_reference_map;
+ AHashMap<StringName, Pair<Variant, bool>> property_map; // Property value and read-only flag.
bool properties_dirty = true;
@@ -286,7 +321,7 @@ private:
virtual void _set_active(bool p_active) override;
// Make animation instances.
- virtual bool _blend_pre_process(double p_delta, int p_track_count, const HashMap<NodePath, int> &p_track_map) override;
+ virtual bool _blend_pre_process(double p_delta, int p_track_count, const AHashMap<NodePath, int> &p_track_map) override;
#ifndef DISABLE_DEPRECATED
void _set_process_callback_bind_compat_80813(AnimationProcessCallback p_mode);
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 07c32eef13..22e5238fae 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -535,7 +535,21 @@ SceneDebuggerTree::SceneDebuggerTree(Node *p_root) {
}
}
}
- nodes.push_back(RemoteNode(count, n->get_name(), n->get_class(), n->get_instance_id(), n->get_scene_file_path(), view_flags));
+
+ String class_name;
+ ScriptInstance *script_instance = n->get_script_instance();
+ if (script_instance) {
+ Ref<Script> script = script_instance->get_script();
+ if (script.is_valid()) {
+ class_name = script->get_global_name();
+
+ if (class_name.is_empty()) {
+ // If there is no class_name in this script we just take the script path.
+ class_name = script->get_path();
+ }
+ }
+ }
+ nodes.push_back(RemoteNode(count, n->get_name(), class_name.is_empty() ? n->get_class() : class_name, n->get_instance_id(), n->get_scene_file_path(), view_flags));
}
}
diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h
index 0c28ca2a0c..be2642a2ae 100644
--- a/scene/debugger/scene_debugger.h
+++ b/scene/debugger/scene_debugger.h
@@ -158,7 +158,7 @@ private:
LiveEditor() {
singleton = this;
live_edit_root = NodePath("/root");
- };
+ }
static LiveEditor *singleton;
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 0a5f2ec6c7..4bd85cbde9 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -296,19 +296,12 @@ void Button::_notification(int p_what) {
}
} break;
case DRAW_HOVER_PRESSED: {
- // Edge case for CheckButton and CheckBox.
- if (has_theme_stylebox("hover_pressed")) {
- if (has_theme_color(SNAME("font_hover_pressed_color"))) {
- font_color = theme_cache.font_hover_pressed_color;
- }
- if (has_theme_color(SNAME("icon_hover_pressed_color"))) {
- icon_modulate_color = theme_cache.icon_hover_pressed_color;
- }
-
- break;
+ font_color = theme_cache.font_hover_pressed_color;
+ if (has_theme_color(SNAME("icon_hover_pressed_color"))) {
+ icon_modulate_color = theme_cache.icon_hover_pressed_color;
}
- }
- [[fallthrough]];
+
+ } break;
case DRAW_PRESSED: {
if (has_theme_color(SNAME("font_pressed_color"))) {
font_color = theme_cache.font_pressed_color;
@@ -649,7 +642,7 @@ String Button::get_language() const {
return language;
}
-void Button::set_icon(const Ref<Texture2D> &p_icon) {
+void Button::set_button_icon(const Ref<Texture2D> &p_icon) {
if (icon == p_icon) {
return;
}
@@ -673,7 +666,7 @@ void Button::_texture_changed() {
update_minimum_size();
}
-Ref<Texture2D> Button::get_icon() const {
+Ref<Texture2D> Button::get_button_icon() const {
return icon;
}
@@ -769,8 +762,8 @@ void Button::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_text_direction"), &Button::get_text_direction);
ClassDB::bind_method(D_METHOD("set_language", "language"), &Button::set_language);
ClassDB::bind_method(D_METHOD("get_language"), &Button::get_language);
- ClassDB::bind_method(D_METHOD("set_button_icon", "texture"), &Button::set_icon);
- ClassDB::bind_method(D_METHOD("get_button_icon"), &Button::get_icon);
+ ClassDB::bind_method(D_METHOD("set_button_icon", "texture"), &Button::set_button_icon);
+ ClassDB::bind_method(D_METHOD("get_button_icon"), &Button::get_button_icon);
ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &Button::set_flat);
ClassDB::bind_method(D_METHOD("is_flat"), &Button::is_flat);
ClassDB::bind_method(D_METHOD("set_clip_text", "enabled"), &Button::set_clip_text);
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 5f4429bc1d..b86d6a6c1f 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -137,8 +137,8 @@ public:
void set_language(const String &p_language);
String get_language() const;
- void set_icon(const Ref<Texture2D> &p_icon);
- Ref<Texture2D> get_icon() const;
+ void set_button_icon(const Ref<Texture2D> &p_icon);
+ Ref<Texture2D> get_button_icon() const;
void set_expand_icon(bool p_enabled);
bool is_expand_icon() const;
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 635228670d..7346c9dcd3 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -277,15 +277,17 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
code_completion_force_item_center = -1;
queue_redraw();
}
- code_completion_pan_offset += 1.0f;
+ code_completion_pan_offset = 0;
} else if (code_completion_pan_offset >= +1.0) {
if (code_completion_current_selected < code_completion_options.size() - 1) {
code_completion_current_selected++;
code_completion_force_item_center = -1;
queue_redraw();
}
- code_completion_pan_offset -= 1.0f;
+ code_completion_pan_offset = 0;
}
+ accept_event();
+ return;
}
Ref<InputEventMouseButton> mb = p_gui_input;
diff --git a/scene/gui/color_mode.h b/scene/gui/color_mode.h
index 94193ccf74..0abc90bb44 100644
--- a/scene/gui/color_mode.h
+++ b/scene/gui/color_mode.h
@@ -41,9 +41,9 @@ public:
virtual String get_name() const = 0;
- virtual int get_slider_count() const { return 3; };
+ virtual int get_slider_count() const { return 3; }
virtual float get_slider_step() const = 0;
- virtual float get_spinbox_arrow_step() const { return get_slider_step(); };
+ virtual float get_spinbox_arrow_step() const { return get_slider_step(); }
virtual String get_slider_label(int idx) const = 0;
virtual float get_slider_max(int idx) const = 0;
virtual float get_slider_value(int idx) const = 0;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index fe4c91cb56..997120ff25 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -80,10 +80,10 @@ void ColorPicker::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- btn_pick->set_icon(theme_cache.screen_picker);
+ btn_pick->set_button_icon(theme_cache.screen_picker);
_update_drop_down_arrow(btn_preset->is_pressed(), btn_preset);
_update_drop_down_arrow(btn_recent_preset->is_pressed(), btn_recent_preset);
- btn_add_preset->set_icon(theme_cache.add_preset);
+ btn_add_preset->set_button_icon(theme_cache.add_preset);
btn_pick->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0));
btn_shape->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0));
@@ -116,7 +116,7 @@ void ColorPicker::_notification(int p_what) {
shape_popup->set_item_icon(shape_popup->get_item_index(SHAPE_OKHSL_CIRCLE), theme_cache.shape_circle);
if (current_shape != SHAPE_NONE) {
- btn_shape->set_icon(shape_popup->get_item_icon(current_shape));
+ btn_shape->set_button_icon(shape_popup->get_item_icon(current_shape));
}
internal_margin->begin_bulk_theme_override();
@@ -245,21 +245,7 @@ void ColorPicker::finish_shaders() {
}
void ColorPicker::set_focus_on_line_edit() {
- bool has_hardware_keyboard = true;
-#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
- has_hardware_keyboard = DisplayServer::get_singleton()->has_hardware_keyboard();
-#endif // ANDROID_ENABLED || IOS_ENABLED
- if (has_hardware_keyboard) {
- callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
- } else {
- // A hack to avoid showing the virtual keyboard when the ColorPicker window popups and
- // no hardware keyboard is detected on Android and IOS.
- // This will only focus the LineEdit without editing, the virtual keyboard will only be visible when
- // we touch the LineEdit to enter edit mode.
- callable_mp(c_text, &LineEdit::set_editable).call_deferred(false);
- callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
- callable_mp(c_text, &LineEdit::set_editable).call_deferred(true);
- }
+ callable_mp((Control *)c_text, &Control::grab_focus).call_deferred();
}
void ColorPicker::_update_controls() {
@@ -719,14 +705,14 @@ void ColorPicker::_text_type_toggled() {
if (text_is_constructor) {
text_type->set_text("");
#ifdef TOOLS_ENABLED
- text_type->set_icon(get_editor_theme_icon(SNAME("Script")));
+ text_type->set_button_icon(get_editor_theme_icon(SNAME("Script")));
#endif
c_text->set_editable(false);
c_text->set_tooltip_text(RTR("Copy this constructor in a script."));
} else {
text_type->set_text("#");
- text_type->set_icon(nullptr);
+ text_type->set_button_icon(nullptr);
c_text->set_editable(true);
c_text->set_tooltip_text(ETR("Enter a hex code (\"#ff0000\") or named color (\"red\")."));
@@ -752,7 +738,7 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) {
}
if (p_shape != SHAPE_NONE) {
shape_popup->set_item_checked(p_shape, true);
- btn_shape->set_icon(shape_popup->get_item_icon(p_shape));
+ btn_shape->set_button_icon(shape_popup->get_item_icon(p_shape));
}
current_shape = p_shape;
@@ -808,9 +794,9 @@ void ColorPicker::_show_hide_preset(const bool &p_is_btn_pressed, Button *p_btn_
void ColorPicker::_update_drop_down_arrow(const bool &p_is_btn_pressed, Button *p_btn_preset) {
if (p_is_btn_pressed) {
- p_btn_preset->set_icon(theme_cache.expanded_arrow);
+ p_btn_preset->set_button_icon(theme_cache.expanded_arrow);
} else {
- p_btn_preset->set_icon(theme_cache.folded_arrow);
+ p_btn_preset->set_button_icon(theme_cache.folded_arrow);
}
}
@@ -1567,23 +1553,21 @@ void ColorPicker::_pick_button_pressed_legacy() {
picker_texture_rect = memnew(TextureRect);
picker_texture_rect->set_anchors_preset(Control::PRESET_FULL_RECT);
+ picker_texture_rect->set_expand_mode(TextureRect::EXPAND_IGNORE_SIZE);
picker_window->add_child(picker_texture_rect);
picker_texture_rect->set_default_cursor_shape(CURSOR_POINTING_HAND);
picker_texture_rect->connect(SceneStringName(gui_input), callable_mp(this, &ColorPicker::_picker_texture_input));
- picker_preview = memnew(Panel);
- picker_preview->set_anchors_preset(Control::PRESET_CENTER_TOP);
- picker_preview->set_mouse_filter(MOUSE_FILTER_IGNORE);
- picker_window->add_child(picker_preview);
-
picker_preview_label = memnew(Label);
- picker_preview->set_anchors_preset(Control::PRESET_CENTER_TOP);
+ picker_preview_label->set_anchors_preset(Control::PRESET_CENTER_TOP);
picker_preview_label->set_text(ETR("Color Picking active"));
- picker_preview->add_child(picker_preview_label);
- picker_preview_style_box = (Ref<StyleBoxFlat>)memnew(StyleBoxFlat);
+ picker_preview_style_box.instantiate();
picker_preview_style_box->set_bg_color(Color(1.0, 1.0, 1.0));
- picker_preview->add_theme_style_override(SceneStringName(panel), picker_preview_style_box);
+ picker_preview_style_box->set_content_margin_all(4.0);
+ picker_preview_label->add_theme_style_override(CoreStringName(normal), picker_preview_style_box);
+
+ picker_window->add_child(picker_preview_label);
}
Rect2i screen_rect;
@@ -1625,7 +1609,7 @@ void ColorPicker::_pick_button_pressed_legacy() {
}
picker_window->set_size(screen_rect.size);
- picker_preview->set_size(screen_rect.size / 10.0); // 10% of size in each axis.
+ picker_preview_label->set_custom_minimum_size(screen_rect.size / 10); // 10% of size in each axis.
picker_window->popup();
}
@@ -1648,7 +1632,7 @@ void ColorPicker::_picker_texture_input(const Ref<InputEvent> &p_event) {
Vector2 ofs = mev->get_position();
picker_color = img->get_pixel(ofs.x, ofs.y);
picker_preview_style_box->set_bg_color(picker_color);
- picker_preview_label->set_self_modulate(picker_color.get_luminance() < 0.5 ? Color(1.0f, 1.0f, 1.0f) : Color(0.0f, 0.0f, 0.0f));
+ picker_preview_label->add_theme_color_override(SceneStringName(font_color), picker_color.get_luminance() < 0.5 ? Color(1.0f, 1.0f, 1.0f) : Color(0.0f, 0.0f, 0.0f));
}
}
}
@@ -2103,7 +2087,9 @@ void ColorPickerButton::pressed() {
float v_offset = show_above ? -minsize.y : get_size().y;
popup->set_position(get_screen_position() + Vector2(h_offset, v_offset));
popup->popup();
- picker->set_focus_on_line_edit();
+ if (DisplayServer::get_singleton()->has_hardware_keyboard()) {
+ picker->set_focus_on_line_edit();
+ }
}
void ColorPickerButton::_notification(int p_what) {
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index ad028584b1..59540d9ace 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -130,7 +130,6 @@ private:
Popup *picker_window = nullptr;
// Legacy color picking.
TextureRect *picker_texture_rect = nullptr;
- Panel *picker_preview = nullptr;
Label *picker_preview_label = nullptr;
Ref<StyleBoxFlat> picker_preview_style_box;
Color picker_color;
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index c1d197ea9b..4b3007543b 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -120,11 +120,11 @@ void Control::_edit_set_state(const Dictionary &p_state) {
void Control::_edit_set_position(const Point2 &p_position) {
ERR_FAIL_COND_MSG(!Engine::get_singleton()->is_editor_hint(), "This function can only be used from editor plugins.");
set_position(p_position, ControlEditorToolbar::get_singleton()->is_anchors_mode_enabled() && get_parent_control());
-};
+}
Point2 Control::_edit_get_position() const {
return get_position();
-};
+}
void Control::_edit_set_scale(const Size2 &p_scale) {
set_scale(p_scale);
@@ -3042,7 +3042,7 @@ void Control::set_layout_direction(Control::LayoutDirection p_direction) {
if (data.layout_dir == p_direction) {
return;
}
- ERR_FAIL_INDEX((int)p_direction, 4);
+ ERR_FAIL_INDEX(p_direction, LAYOUT_DIRECTION_MAX);
data.layout_dir = p_direction;
@@ -3115,13 +3115,20 @@ bool Control::is_layout_rtl() const {
String locale = TranslationServer::get_singleton()->get_tool_locale();
const_cast<Control *>(this)->data.is_rtl = TS->is_locale_right_to_left(locale);
}
- } else if (data.layout_dir == LAYOUT_DIRECTION_LOCALE) {
+ } else if (data.layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) {
if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
const_cast<Control *>(this)->data.is_rtl = true;
} else {
String locale = TranslationServer::get_singleton()->get_tool_locale();
const_cast<Control *>(this)->data.is_rtl = TS->is_locale_right_to_left(locale);
}
+ } else if (data.layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) {
+ if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
+ const_cast<Control *>(this)->data.is_rtl = true;
+ } else {
+ String locale = OS::get_singleton()->get_locale();
+ const_cast<Control *>(this)->data.is_rtl = TS->is_locale_right_to_left(locale);
+ }
} else {
const_cast<Control *>(this)->data.is_rtl = (data.layout_dir == LAYOUT_DIRECTION_RTL);
}
@@ -3574,7 +3581,7 @@ void Control::_bind_methods() {
ADD_GROUP("Layout", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Based on Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Based on Application Locale,Left-to-Right,Right-to-Left,Based on System Locale"), "set_layout_direction", "get_layout_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
@@ -3723,9 +3730,14 @@ void Control::_bind_methods() {
BIND_ENUM_CONSTANT(ANCHOR_END);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_INHERITED);
- BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_APPLICATION_LOCALE);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LTR);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_SYSTEM_LOCALE);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_MAX);
+#ifndef DISABLE_DEPRECATED
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE);
+#endif // DISABLE_DEPRECATED
BIND_ENUM_CONSTANT(TEXT_DIRECTION_INHERITED);
BIND_ENUM_CONSTANT(TEXT_DIRECTION_AUTO);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 6e1621ce58..6cabf10971 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -140,9 +140,14 @@ public:
enum LayoutDirection {
LAYOUT_DIRECTION_INHERITED,
- LAYOUT_DIRECTION_LOCALE,
+ LAYOUT_DIRECTION_APPLICATION_LOCALE,
LAYOUT_DIRECTION_LTR,
- LAYOUT_DIRECTION_RTL
+ LAYOUT_DIRECTION_RTL,
+ LAYOUT_DIRECTION_SYSTEM_LOCALE,
+ LAYOUT_DIRECTION_MAX,
+#ifndef DISABLE_DEPRECATED
+ LAYOUT_DIRECTION_LOCALE = LAYOUT_DIRECTION_APPLICATION_LOCALE,
+#endif // DISABLE_DEPRECATED
};
enum TextDirection {
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index d8e9d1bcc0..111b8579ec 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -197,18 +197,18 @@ void FileDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- dir_up->set_icon(theme_cache.parent_folder);
+ dir_up->set_button_icon(theme_cache.parent_folder);
if (vbox->is_layout_rtl()) {
- dir_prev->set_icon(theme_cache.forward_folder);
- dir_next->set_icon(theme_cache.back_folder);
+ dir_prev->set_button_icon(theme_cache.forward_folder);
+ dir_next->set_button_icon(theme_cache.back_folder);
} else {
- dir_prev->set_icon(theme_cache.back_folder);
- dir_next->set_icon(theme_cache.forward_folder);
+ dir_prev->set_button_icon(theme_cache.back_folder);
+ dir_next->set_button_icon(theme_cache.forward_folder);
}
- refresh->set_icon(theme_cache.reload);
- show_hidden->set_icon(theme_cache.toggle_hidden);
- makedir->set_icon(theme_cache.create_folder);
- show_filename_filter_button->set_icon(theme_cache.toggle_filename_filter);
+ refresh->set_button_icon(theme_cache.reload);
+ show_hidden->set_button_icon(theme_cache.toggle_hidden);
+ makedir->set_button_icon(theme_cache.create_folder);
+ show_filename_filter_button->set_button_icon(theme_cache.toggle_filename_filter);
dir_up->begin_bulk_theme_override();
dir_up->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 646757008a..cb495f9d47 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -733,14 +733,14 @@ void GraphEdit::_update_theme_item_cache() {
void GraphEdit::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- zoom_minus_button->set_icon(theme_cache.zoom_out);
- zoom_reset_button->set_icon(theme_cache.zoom_reset);
- zoom_plus_button->set_icon(theme_cache.zoom_in);
-
- toggle_snapping_button->set_icon(theme_cache.snapping_toggle);
- toggle_grid_button->set_icon(theme_cache.grid_toggle);
- minimap_button->set_icon(theme_cache.minimap_toggle);
- arrange_button->set_icon(theme_cache.layout);
+ zoom_minus_button->set_button_icon(theme_cache.zoom_out);
+ zoom_reset_button->set_button_icon(theme_cache.zoom_reset);
+ zoom_plus_button->set_button_icon(theme_cache.zoom_in);
+
+ toggle_snapping_button->set_button_icon(theme_cache.snapping_toggle);
+ toggle_grid_button->set_button_icon(theme_cache.grid_toggle);
+ minimap_button->set_button_icon(theme_cache.minimap_toggle);
+ arrange_button->set_button_icon(theme_cache.layout);
zoom_label->set_custom_minimum_size(Size2(48, 0) * theme_cache.base_scale);
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index f3cf29d0cf..1ba5ef309b 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -1056,7 +1056,7 @@ void ItemList::_notification(int p_what) {
scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.panel_style->get_margin(SIDE_BOTTOM));
Size2 size = get_size();
- int width = size.width - theme_cache.panel_style->get_margin(SIDE_RIGHT);
+ int width = size.width - theme_cache.panel_style->get_minimum_size().width;
if (scroll_bar->is_visible()) {
width -= scroll_bar_minwidth;
}
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 46c9c7cccc..9853d699d4 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -510,6 +510,7 @@ void MenuBar::_refresh_menu_names() {
if (!popups[i]->has_meta("_menu_name") && String(popups[i]->get_name()) != get_menu_title(i)) {
menu_cache.write[i].name = popups[i]->get_name();
shape(menu_cache.write[i]);
+ queue_redraw();
if (is_global && menu_cache[i].submenu_rid.is_valid()) {
int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[i].submenu_rid);
if (item_idx >= 0) {
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 5432058f7b..79018c40f5 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -225,7 +225,7 @@ void OptionButton::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
popup->set_item_icon(p_idx, p_icon);
if (current == p_idx) {
- set_icon(p_icon);
+ set_button_icon(p_icon);
}
_queue_update_size_cache();
}
@@ -381,7 +381,7 @@ void OptionButton::_select(int p_which, bool p_emit) {
current = NONE_SELECTED;
set_text("");
- set_icon(nullptr);
+ set_button_icon(nullptr);
} else {
ERR_FAIL_INDEX(p_which, popup->get_item_count());
@@ -391,7 +391,7 @@ void OptionButton::_select(int p_which, bool p_emit) {
current = p_which;
set_text(popup->get_item_text(current));
- set_icon(popup->get_item_icon(current));
+ set_button_icon(popup->get_item_icon(current));
}
if (is_inside_tree() && p_emit) {
diff --git a/scene/gui/range.h b/scene/gui/range.h
index b1c2446ded..710fed8645 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -64,7 +64,7 @@ class Range : public Control {
protected:
virtual void _value_changed(double p_value);
- void _notify_shared_value_changed() { shared->emit_value_changed(); };
+ void _notify_shared_value_changed() { shared->emit_value_changed(); }
static void _bind_methods();
diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h
index 681f068fb2..94e1bd4f04 100644
--- a/scene/gui/rich_text_effect.h
+++ b/scene/gui/rich_text_effect.h
@@ -79,20 +79,20 @@ public:
Color get_color() { return color; }
void set_color(Color p_color) { color = p_color; }
- uint32_t get_glyph_index() const { return glyph_index; };
- void set_glyph_index(uint32_t p_glyph_index) { glyph_index = p_glyph_index; };
+ uint32_t get_glyph_index() const { return glyph_index; }
+ void set_glyph_index(uint32_t p_glyph_index) { glyph_index = p_glyph_index; }
- uint16_t get_glyph_flags() const { return glyph_flags; };
- void set_glyph_flags(uint16_t p_glyph_flags) { glyph_flags = p_glyph_flags; };
+ uint16_t get_glyph_flags() const { return glyph_flags; }
+ void set_glyph_flags(uint16_t p_glyph_flags) { glyph_flags = p_glyph_flags; }
- uint8_t get_glyph_count() const { return glyph_count; };
- void set_glyph_count(uint8_t p_glyph_count) { glyph_count = p_glyph_count; };
+ uint8_t get_glyph_count() const { return glyph_count; }
+ void set_glyph_count(uint8_t p_glyph_count) { glyph_count = p_glyph_count; }
- int32_t get_relative_index() const { return relative_index; };
- void set_relative_index(int32_t p_relative_index) { relative_index = p_relative_index; };
+ int32_t get_relative_index() const { return relative_index; }
+ void set_relative_index(int32_t p_relative_index) { relative_index = p_relative_index; }
- RID get_font() const { return font; };
- void set_font(RID p_font) { font = p_font; };
+ RID get_font() const { return font; }
+ void set_font(RID p_font) { font = p_font; }
Dictionary get_environment() { return environment; }
void set_environment(Dictionary p_environment) { environment = p_environment; }
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 1ac0e8b59f..312b538a99 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -461,7 +461,7 @@ void ScrollContainer::update_scrollbars() {
void ScrollContainer::_scroll_moved(float) {
queue_sort();
-};
+}
void ScrollContainer::set_h_scroll(int p_pos) {
h_scroll->set_value(p_pos);
@@ -625,7 +625,7 @@ void ScrollContainer::_bind_methods() {
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollContainer, panel_style, "panel");
GLOBAL_DEF("gui/common/default_scroll_deadzone", 0);
-};
+}
ScrollContainer::ScrollContainer() {
h_scroll = memnew(HScrollBar);
@@ -641,4 +641,4 @@ ScrollContainer::ScrollContainer() {
deadzone = GLOBAL_GET("gui/common/default_scroll_deadzone");
set_clip_contents(true);
-};
+}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 94b105d486..e0d552848d 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -693,9 +693,9 @@ protected:
void _set_symbol_lookup_word(const String &p_symbol);
// Theme items.
- virtual Color _get_brace_mismatch_color() const { return Color(); };
- virtual Color _get_code_folding_color() const { return Color(); };
- virtual Ref<Texture2D> _get_folded_eol_icon() const { return Ref<Texture2D>(); };
+ virtual Color _get_brace_mismatch_color() const { return Color(); }
+ virtual Color _get_code_folding_color() const { return Color(); }
+ virtual Ref<Texture2D> _get_folded_eol_icon() const { return Ref<Texture2D>(); }
/* Text manipulation */
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index c267ff93c6..47bb0643b3 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -340,11 +340,11 @@ Ref<BitMap> TextureButton::get_click_mask() const {
Ref<Texture2D> TextureButton::get_texture_focused() const {
return focused;
-};
+}
void TextureButton::set_texture_focused(const Ref<Texture2D> &p_focused) {
focused = p_focused;
-};
+}
void TextureButton::_set_texture(Ref<Texture2D> *p_destination, const Ref<Texture2D> &p_texture) {
DEV_ASSERT(p_destination);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 646cd9c70e..aab6f672f0 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -961,19 +961,17 @@ TreeItem *TreeItem::_get_prev_in_tree(bool p_wrap, bool p_include_invisible) {
if (!prev_item) {
current = current->parent;
- if (current == tree->root && tree->hide_root) {
- return nullptr;
- } else if (!current) {
- if (p_wrap) {
- current = this;
- TreeItem *temp = get_next_visible();
- while (temp) {
- current = temp;
- temp = temp->get_next_visible();
- }
- } else {
+ if (!current || (current == tree->root && tree->hide_root)) {
+ if (!p_wrap) {
return nullptr;
}
+ // Wrap around to the last visible item.
+ current = this;
+ TreeItem *temp = get_next_visible();
+ while (temp) {
+ current = temp;
+ temp = temp->get_next_visible();
+ }
}
} else {
current = prev_item;
@@ -1101,7 +1099,7 @@ void TreeItem::clear_children() {
first_child = nullptr;
last_child = nullptr;
children_cache.clear();
-};
+}
int TreeItem::get_index() {
int idx = 0;
@@ -2165,12 +2163,18 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? theme_cache.h_separation : theme_cache.item_margin);
int skip2 = 0;
+
+ bool is_row_hovered = (!cache.hover_header_row && cache.hover_item == p_item);
+
for (int i = 0; i < columns.size(); i++) {
if (skip2) {
skip2--;
continue;
}
+ bool is_col_hovered = cache.hover_column == i;
+ bool is_cell_hovered = is_row_hovered && is_col_hovered;
+ bool is_cell_button_hovered = is_cell_hovered && cache.hover_button_index_in_column != -1;
int item_width = get_column_width(i);
if (i == 0) {
@@ -2203,6 +2207,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int total_ofs = ofs - theme_cache.offset.x;
+ // If part of the column is beyond the right side of the control due to scrolling, clamp the label width
+ // so that all buttons attached to the cell remain within view.
if (total_ofs + item_width > p_draw_size.width) {
item_width = MAX(buttons_width, p_draw_size.width - total_ofs);
}
@@ -2247,17 +2253,42 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(r.position.x, r.position.y + r.size.height), r.position + r.size, theme_cache.guide_color, 1);
}
- if (i == 0) {
- if (p_item->cells[0].selected && select_mode == SELECT_ROW) {
+ if (i == 0 && select_mode == SELECT_ROW) {
+ if (p_item->cells[0].selected || is_row_hovered) {
const Rect2 content_rect = _get_content_rect();
Rect2i row_rect = Rect2i(Point2i(content_rect.position.x, item_rect.position.y), Size2i(content_rect.size.x, item_rect.size.y));
if (rtl) {
row_rect.position.x = get_size().width - row_rect.position.x - row_rect.size.x;
}
- if (has_focus()) {
- theme_cache.selected_focus->draw(ci, row_rect);
+
+ if (p_item->cells[0].selected) {
+ if (has_focus()) {
+ theme_cache.selected_focus->draw(ci, row_rect);
+ } else {
+ theme_cache.selected->draw(ci, row_rect);
+ }
+ } else if (!drop_mode_flags) {
+ if (is_cell_button_hovered) {
+ theme_cache.hovered_dimmed->draw(ci, row_rect);
+ } else {
+ theme_cache.hovered->draw(ci, row_rect);
+ }
+ }
+ }
+ }
+
+ if (select_mode != SELECT_ROW) {
+ Rect2i r = cell_rect;
+ if (rtl) {
+ r.position.x = get_size().width - r.position.x - r.size.x;
+ }
+
+ // Cell hover.
+ if (is_cell_hovered && !p_item->cells[i].selected && !drop_mode_flags) {
+ if (is_cell_button_hovered) {
+ theme_cache.hovered_dimmed->draw(ci, r);
} else {
- theme_cache.selected->draw(ci, row_rect);
+ theme_cache.hovered->draw(ci, r);
}
}
}
@@ -2335,7 +2366,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (p_item->cells[i].custom_color) {
cell_color = p_item->cells[i].color;
} else {
- cell_color = p_item->cells[i].selected ? theme_cache.font_selected_color : theme_cache.font_color;
+ bool draw_as_hover = !drop_mode_flags && (select_mode == SELECT_ROW ? is_row_hovered : is_cell_hovered);
+ bool draw_as_hover_dim = draw_as_hover && is_cell_button_hovered;
+ cell_color = p_item->cells[i].selected ? theme_cache.font_selected_color : (draw_as_hover_dim ? theme_cache.font_hovered_dimmed_color : (draw_as_hover ? theme_cache.font_hovered_color : theme_cache.font_color));
}
Color font_outline_color = theme_cache.font_outline_color;
@@ -2487,7 +2520,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
ir.size.width -= downarrow->get_width();
if (p_item->cells[i].custom_button) {
- if (cache.hover_item == p_item && cache.hover_cell == i) {
+ if (cache.hover_item == p_item && cache.hover_column == i) {
if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
draw_style_box(theme_cache.custom_button_pressed, ir);
} else {
@@ -2508,19 +2541,26 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
} break;
}
+ // Draw the buttons inside the cell.
for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> button_texture = p_item->cells[i].buttons[j].texture;
Size2 button_size = button_texture->get_size() + theme_cache.button_pressed->get_minimum_size();
Point2i button_ofs = Point2i(ofs + item_width_with_buttons - button_size.width, p_pos.y) - theme_cache.offset + p_draw_ofs;
- if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item == p_item && cache.click_column == i && cache.click_index == j && !p_item->cells[i].buttons[j].disabled) {
- // Being pressed.
+ bool should_draw_pressed = cache.click_type == Cache::CLICK_BUTTON && cache.click_item == p_item && cache.click_column == i && cache.click_index == j && !p_item->cells[i].buttons[j].disabled;
+ bool should_draw_hovered = !should_draw_pressed && !drop_mode_flags && cache.hover_item == p_item && cache.hover_column == i && cache.hover_button_index_in_column == j && !p_item->cells[i].buttons[j].disabled;
+
+ if (should_draw_pressed || should_draw_hovered) {
Point2 od = button_ofs;
if (rtl) {
od.x = get_size().width - od.x - button_size.x;
}
- theme_cache.button_pressed->draw(get_canvas_item(), Rect2(od.x, od.y, button_size.width, MAX(button_size.height, label_h)));
+ if (should_draw_pressed) {
+ theme_cache.button_pressed->draw(get_canvas_item(), Rect2(od.x, od.y, button_size.width, MAX(button_size.height, label_h)));
+ } else {
+ theme_cache.button_hover->draw(get_canvas_item(), Rect2(od.x, od.y, button_size.width, MAX(button_size.height, label_h)));
+ }
}
button_ofs.y += (label_h - button_size.height) / 2;
@@ -2551,6 +2591,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
+ // Draw the folding arrow.
if (!p_item->disable_folding && !hide_folding && p_item->first_child && p_item->get_visible_child_count() != 0) { //has visible children, draw the guide box
Ref<Texture2D> arrow;
@@ -2966,6 +3007,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
col_width = MAX(button_w, MIN(limit_w, col_width));
}
+ // Cell button detection code.
for (int j = c.buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> b = c.buttons[j].texture;
int w = b->get_size().width + theme_cache.button_pressed->get_minimum_size().width;
@@ -2978,7 +3020,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
// Make sure the click is correct.
- Point2 click_pos = get_global_mouse_position() - get_global_position();
+ const Point2 click_pos = get_local_mouse_position();
if (!get_item_at_position(click_pos)) {
pressed_button = -1;
cache.click_type = Cache::CLICK_NONE;
@@ -3485,7 +3527,11 @@ bool Tree::_scroll(bool p_horizontal, float p_pages) {
double prev_value = scroll->get_value();
scroll->set_value(scroll->get_value() + scroll->get_page() * p_pages);
- return scroll->get_value() != prev_value;
+ bool scroll_happened = scroll->get_value() != prev_value;
+ if (scroll_happened) {
+ _determine_hovered_item();
+ }
+ return scroll_happened;
}
Rect2 Tree::_get_scrollbar_layout_rect() const {
@@ -3710,92 +3756,10 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- Ref<StyleBox> bg = theme_cache.panel_style;
- bool rtl = is_layout_rtl();
-
- Point2 pos = mm->get_position();
- if (rtl) {
- pos.x = get_size().width - pos.x;
- }
- pos -= theme_cache.panel_style->get_offset();
-
- Cache::ClickType old_hover = cache.hover_type;
- int old_index = cache.hover_index;
-
- cache.hover_type = Cache::CLICK_NONE;
- cache.hover_index = 0;
- if (show_column_titles) {
- pos.y -= _get_title_button_height();
- if (pos.y < 0) {
- pos.x += theme_cache.offset.x;
- int len = 0;
- for (int i = 0; i < columns.size(); i++) {
- len += get_column_width(i);
- if (pos.x < len) {
- cache.hover_type = Cache::CLICK_TITLE;
- cache.hover_index = i;
- break;
- }
- }
- }
- }
-
- if (root) {
- Point2 mpos = mm->get_position();
- if (rtl) {
- mpos.x = get_size().width - mpos.x;
- }
- mpos -= theme_cache.panel_style->get_offset();
- mpos.y -= _get_title_button_height();
- if (mpos.y >= 0) {
- if (h_scroll->is_visible_in_tree()) {
- mpos.x += h_scroll->get_value();
- }
- if (v_scroll->is_visible_in_tree()) {
- mpos.y += v_scroll->get_value();
- }
-
- TreeItem *old_it = cache.hover_item;
- int old_col = cache.hover_cell;
-
- int col, h, section;
- TreeItem *it = _find_item_at_pos(root, mpos, col, h, section);
-
- if (drop_mode_flags) {
- if (it != drop_mode_over) {
- drop_mode_over = it;
- queue_redraw();
- }
- if (it && section != drop_mode_section) {
- drop_mode_section = section;
- queue_redraw();
- }
- }
-
- cache.hover_item = it;
- cache.hover_cell = col;
-
- if (it != old_it || col != old_col) {
- if (old_it && old_col >= old_it->cells.size()) {
- // Columns may have changed since last redraw().
- queue_redraw();
- } else {
- // Only need to update if mouse enters/exits a button
- bool was_over_button = old_it && old_it->cells[old_col].custom_button;
- bool is_over_button = it && it->cells[col].custom_button;
- if (was_over_button || is_over_button) {
- queue_redraw();
- }
- }
- }
- }
- }
-
- // Update if mouse enters/exits columns
- if (cache.hover_type != old_hover || cache.hover_index != old_index) {
- queue_redraw();
- }
+ hovered_pos = mm->get_position();
+ _determine_hovered_item();
+ bool rtl = is_layout_rtl();
if (pressing_for_editor && popup_pressing_edited_item && (popup_pressing_edited_item->get_cell_mode(popup_pressing_edited_item_column) == TreeItem::CELL_MODE_RANGE)) {
/* This needs to happen now, because the popup can be closed when pressing another item, and must remain the popup edited item until it actually closes */
popup_edited_item = popup_pressing_edited_item;
@@ -4080,6 +4044,174 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
}
+void Tree::_determine_hovered_item() {
+ Ref<StyleBox> bg = theme_cache.panel_style;
+ bool rtl = is_layout_rtl();
+
+ Point2 pos = hovered_pos;
+ if (rtl) {
+ pos.x = get_size().width - pos.x;
+ }
+ pos -= theme_cache.panel_style->get_offset();
+
+ bool old_header_row = cache.hover_header_row;
+ int old_header_column = cache.hover_header_column;
+ TreeItem *old_item = cache.hover_item;
+ int old_column = cache.hover_column;
+ int old_button_index_in_column = cache.hover_button_index_in_column;
+
+ // Determine hover on column headers.
+ cache.hover_header_row = false;
+ cache.hover_header_column = 0;
+ if (show_column_titles && is_mouse_hovering) {
+ pos.y -= _get_title_button_height();
+ if (pos.y < 0) {
+ pos.x += theme_cache.offset.x;
+ int len = 0;
+ for (int i = 0; i < columns.size(); i++) {
+ len += get_column_width(i);
+ if (pos.x < len) {
+ cache.hover_header_row = true;
+ cache.hover_header_column = i;
+ cache.hover_button_index_in_column = -1;
+ break;
+ }
+ }
+ }
+ }
+
+ // Determine hover on rows and items.
+ if (root && is_mouse_hovering) {
+ Point2 mpos = hovered_pos;
+ if (rtl) {
+ mpos.x = get_size().width - mpos.x;
+ }
+ mpos -= theme_cache.panel_style->get_offset();
+ mpos.y -= _get_title_button_height();
+ if (mpos.y >= 0) {
+ if (h_scroll->is_visible_in_tree()) {
+ mpos.x += h_scroll->get_value();
+ }
+ if (v_scroll->is_visible_in_tree()) {
+ mpos.y += v_scroll->get_value();
+ }
+
+ int col, h, section;
+ TreeItem *it = _find_item_at_pos(root, mpos, col, h, section);
+
+ // Find possible hovered button in cell.
+ int col_button_index = -1;
+
+ Point2 cpos = mpos;
+
+ if (it) {
+ const TreeItem::Cell &c = it->cells[col];
+ int col_width = get_column_width(col);
+
+ // In the first column, tree nesting indent impacts the leftmost possible buttons position
+ // and the clickable area of the folding arrow.
+ int col_indent = 0;
+ if (col == 0) {
+ col_indent = _get_item_h_offset(it);
+ }
+
+ // Compute total width of buttons block including spacings.
+ int buttons_width = 0;
+ for (int j = c.buttons.size() - 1; j >= 0; j--) {
+ Ref<Texture2D> b = c.buttons[j].texture;
+ Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size();
+ buttons_width += size.width + theme_cache.button_margin;
+ }
+
+ // Adjust when buttons are shifted left into view so that they remain visible even
+ // if part of the cell is beyond the right border due to horizontal scrolling and
+ // a long string in one of the items. This matches the drawing & click handling algorithms
+ // that are based on recursion.
+ int clamped_column_offset = 0;
+ int col_left = 0;
+
+ for (int i = 0; i < col; i++) {
+ int i_col_w = get_column_width(i);
+ cpos.x -= i_col_w;
+ col_left += i_col_w;
+ }
+ col_left -= theme_cache.offset.x;
+
+ // Compute buttons offset that makes them visible, in comparison to what would be their
+ // natural position that would cut them off.
+ if (!rtl) {
+ const Rect2 content_rect = _get_content_rect();
+ int cw = content_rect.size.width;
+ int col_right = col_left + col_width;
+ if (col_right > cw) {
+ clamped_column_offset = col_right - cw - theme_cache.scrollbar_h_separation;
+ int max_clamp_offset = col_width - col_indent - buttons_width;
+ if (clamped_column_offset > max_clamp_offset) {
+ clamped_column_offset = max_clamp_offset;
+ }
+ }
+ }
+ col_width -= clamped_column_offset;
+
+ // Find the actual button under coordinates.
+ for (int j = c.buttons.size() - 1; j >= 0; j--) {
+ Ref<Texture2D> b = c.buttons[j].texture;
+ Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size();
+ if (cpos.x > col_width - size.width && col_button_index == -1) {
+ col_button_index = j;
+ }
+ col_width -= size.width + theme_cache.button_margin;
+ }
+ }
+
+ if (drop_mode_flags) {
+ if (it != drop_mode_over) {
+ drop_mode_over = it;
+ queue_redraw();
+ }
+ if (it && section != drop_mode_section) {
+ drop_mode_section = section;
+ queue_redraw();
+ }
+ }
+
+ cache.hover_item = it;
+ cache.hover_column = col;
+ cache.hover_button_index_in_column = col_button_index;
+
+ if (it != old_item || col != old_column) {
+ if (old_item && old_column >= old_item->cells.size()) {
+ // Columns may have changed since last redraw().
+ queue_redraw();
+ } else {
+ // Only need to update if mouse enters/exits a button.
+ bool was_over_button = old_item && old_item->cells[old_column].custom_button;
+ bool is_over_button = it && it->cells[col].custom_button;
+ if (was_over_button || is_over_button) {
+ queue_redraw();
+ }
+ }
+ }
+ }
+ }
+
+ // Reduce useless redraw calls.
+
+ bool hovered_cell_button_changed = (cache.hover_button_index_in_column != old_button_index_in_column);
+ bool hovered_column_changed = (cache.hover_column != old_column);
+
+ // Mouse has moved from row to row, or from cell to cell within same row unless selection mode is full row which saves a useless redraw.
+ bool item_hover_needs_redraw = !cache.hover_header_row && (cache.hover_item != old_item || hovered_cell_button_changed || (select_mode != SELECT_ROW && hovered_column_changed));
+ // Mouse has moved between two different column header sections.
+ bool header_hover_needs_redraw = cache.hover_header_row && cache.hover_header_column != old_header_column;
+ // Mouse has moved between header and "main" areas.
+ bool whole_needs_redraw = cache.hover_header_row != old_header_row;
+
+ if (whole_needs_redraw || header_hover_needs_redraw || item_hover_needs_redraw) {
+ queue_redraw();
+ }
+}
+
bool Tree::edit_selected(bool p_force_edit) {
TreeItem *s = get_selected();
ERR_FAIL_NULL_V_MSG(s, false, "No item selected.");
@@ -4304,9 +4436,20 @@ void Tree::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_MOUSE_ENTER: {
+ is_mouse_hovering = true;
+ _determine_hovered_item();
+ } break;
+
case NOTIFICATION_MOUSE_EXIT: {
- if (cache.hover_type != Cache::CLICK_NONE) {
- cache.hover_type = Cache::CLICK_NONE;
+ is_mouse_hovering = false;
+ // Clear hovered item cache.
+ if (cache.hover_header_row || cache.hover_item != nullptr) {
+ cache.hover_header_row = false;
+ cache.hover_header_column = -1;
+ cache.hover_item = nullptr;
+ cache.hover_column = -1;
+ cache.hover_button_index_in_column = -1;
queue_redraw();
}
} break;
@@ -4420,7 +4563,7 @@ void Tree::_notification(int p_what) {
//title buttons
int ofs2 = theme_cache.panel_style->get_margin(SIDE_LEFT);
for (int i = 0; i < columns.size(); i++) {
- Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? theme_cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? theme_cache.title_button_hover : theme_cache.title_button);
+ Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? theme_cache.title_button_pressed : ((cache.hover_header_row && cache.hover_header_column == i) ? theme_cache.title_button_hover : theme_cache.title_button);
Rect2 tbrect = Rect2(ofs2 - theme_cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh);
if (cache.rtl) {
tbrect.position.x = get_size().width - tbrect.size.x - tbrect.position.x;
@@ -4536,6 +4679,8 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_index) {
}
}
+ _determine_hovered_item();
+
return ti;
}
@@ -4679,8 +4824,10 @@ void Tree::clear() {
popup_edited_item = nullptr;
popup_pressing_edited_item = nullptr;
+ _determine_hovered_item();
+
queue_redraw();
-};
+}
void Tree::set_hide_root(bool p_enabled) {
if (hide_root == p_enabled) {
@@ -4931,6 +5078,7 @@ int Tree::get_columns() const {
}
void Tree::_scroll_moved(float) {
+ _determine_hovered_item();
queue_redraw();
}
@@ -4972,7 +5120,47 @@ int Tree::get_item_offset(TreeItem *p_item) const {
}
}
- return -1; //not found
+ return -1; // Not found.
+}
+
+int Tree::_get_item_h_offset(TreeItem *p_item) const {
+ TreeItem *it = root;
+ int nesting_level = 0;
+ if (!it) {
+ return 0;
+ }
+
+ while (true) {
+ if (it == p_item) {
+ if (!hide_root) {
+ nesting_level += 1;
+ }
+ if (hide_folding) {
+ nesting_level -= 1;
+ }
+ return nesting_level * theme_cache.item_margin;
+ }
+
+ if (it->first_child && !it->collapsed) {
+ it = it->first_child;
+ nesting_level += 1;
+
+ } else if (it->next) {
+ it = it->next;
+ } else {
+ while (!it->next) {
+ it = it->parent;
+ nesting_level -= 1;
+ if (it == nullptr) {
+ return 0;
+ }
+ }
+
+ it = it->next;
+ }
+ }
+
+ return -1; // Not found.
}
void Tree::ensure_cursor_is_visible() {
@@ -5803,10 +5991,13 @@ void Tree::_bind_methods() {
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_FONT, Tree, tb_font, "title_button_font");
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_FONT_SIZE, Tree, tb_font_size, "title_button_font_size");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, hovered);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, hovered_dimmed);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, selected);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, selected_focus);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, cursor);
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Tree, cursor_unfocus, "cursor_unfocused");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, button_hover);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, button_pressed);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, checked);
@@ -5827,6 +6018,8 @@ void Tree::_bind_methods() {
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, custom_button_font_highlight);
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_hovered_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_hovered_dimmed_color);
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_selected_color);
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_disabled_color);
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, drop_position_color);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 86efdfec52..b417b7ee31 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -450,6 +450,9 @@ private:
Vector2 pressing_pos;
Rect2 pressing_item_rect;
+ Vector2 hovered_pos;
+ bool is_mouse_hovering = false;
+
float range_drag_base = 0.0;
bool range_drag_enabled = false;
Vector2 range_drag_capture_pos;
@@ -545,10 +548,13 @@ private:
int font_size = 0;
int tb_font_size = 0;
+ Ref<StyleBox> hovered;
+ Ref<StyleBox> hovered_dimmed;
Ref<StyleBox> selected;
Ref<StyleBox> selected_focus;
Ref<StyleBox> cursor;
Ref<StyleBox> cursor_unfocus;
+ Ref<StyleBox> button_hover;
Ref<StyleBox> button_pressed;
Ref<StyleBox> title_button;
Ref<StyleBox> title_button_hover;
@@ -572,6 +578,8 @@ private:
Ref<Texture2D> updown;
Color font_color;
+ Color font_hovered_color;
+ Color font_hovered_dimmed_color;
Color font_selected_color;
Color font_disabled_color;
Color guide_color;
@@ -623,16 +631,17 @@ private:
};
ClickType click_type = Cache::CLICK_NONE;
- ClickType hover_type = Cache::CLICK_NONE;
int click_index = -1;
int click_id = -1;
TreeItem *click_item = nullptr;
int click_column = 0;
- int hover_index = -1;
+ int hover_header_column = -1;
+ bool hover_header_row = false;
Point2 click_pos;
TreeItem *hover_item = nullptr;
- int hover_cell = -1;
+ int hover_column = -1;
+ int hover_button_index_in_column = -1;
bool rtl = false;
} cache;
@@ -660,6 +669,7 @@ private:
TreeItem *_search_item_text(TreeItem *p_at, const String &p_find, int *r_col, bool p_selectable, bool p_backwards = false);
TreeItem *_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_column, int &h, int &section) const;
+ int _get_item_h_offset(TreeItem *p_item) const;
void _find_button_at_pos(const Point2 &p_pos, TreeItem *&r_item, int &r_column, int &r_index) const;
@@ -689,6 +699,8 @@ private:
bool enable_recursive_folding = true;
+ void _determine_hovered_item();
+
int _count_selected_items(TreeItem *p_from) const;
bool _is_branch_selected(TreeItem *p_from) const;
bool _is_sibling_branch_selected(TreeItem *p_from) const;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index c0386b056f..7c8bf9c809 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -1253,7 +1253,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_update_transform"), &CanvasItem::force_update_transform);
- ClassDB::bind_method(D_METHOD("make_canvas_position_local", "screen_point"), &CanvasItem::make_canvas_position_local);
+ ClassDB::bind_method(D_METHOD("make_canvas_position_local", "viewport_point"), &CanvasItem::make_canvas_position_local);
ClassDB::bind_method(D_METHOD("make_input_local", "event"), &CanvasItem::make_input_local);
ClassDB::bind_method(D_METHOD("set_visibility_layer", "layer"), &CanvasItem::set_visibility_layer);
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 028c2cb2cf..5c4477234b 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -211,20 +211,20 @@ public:
virtual Size2 _edit_get_scale() const = 0;
// Used to rotate the node
- virtual bool _edit_use_rotation() const { return false; };
+ virtual bool _edit_use_rotation() const { return false; }
virtual void _edit_set_rotation(real_t p_rotation) {}
- virtual real_t _edit_get_rotation() const { return 0.0; };
+ virtual real_t _edit_get_rotation() const { return 0.0; }
// Used to resize/move the node
- virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
+ virtual bool _edit_use_rect() const { return false; } // MAYBE REPLACE BY A _edit_get_editmode()
virtual void _edit_set_rect(const Rect2 &p_rect) {}
- virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
- virtual Size2 _edit_get_minimum_size() const { return Size2(-1, -1); }; // LOOKS WEIRD
+ virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); }
+ virtual Size2 _edit_get_minimum_size() const { return Size2(-1, -1); } // LOOKS WEIRD
// Used to set a pivot
- virtual bool _edit_use_pivot() const { return false; };
+ virtual bool _edit_use_pivot() const { return false; }
virtual void _edit_set_pivot(const Point2 &p_pivot) {}
- virtual Point2 _edit_get_pivot() const { return Point2(); };
+ virtual Point2 _edit_get_pivot() const { return Point2(); }
virtual Transform2D _edit_get_transform() const;
#endif
@@ -375,7 +375,7 @@ public:
TextureRepeat get_texture_repeat_in_tree() const;
// Used by control nodes to retrieve the parent's anchorable area
- virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
+ virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); }
int get_canvas_layer() const;
CanvasLayer *get_canvas_layer_node() const;
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index 29166f3d92..9222ce6df3 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -245,7 +245,7 @@ Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) {
}
return ret;
-};
+}
void InstancePlaceholder::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_stored_values", "with_order"), &InstancePlaceholder::get_stored_values, DEFVAL(false));
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 169a5dcb01..54f66e8d4e 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1448,7 +1448,11 @@ void Viewport::_gui_show_tooltip() {
&tooltip_owner);
gui.tooltip_text = gui.tooltip_text.strip_edges();
- if (gui.tooltip_text.is_empty()) {
+ // Controls can implement `make_custom_tooltip` to provide their own tooltip.
+ // This should be a Control node which will be added as child to a TooltipPanel.
+ Control *base_tooltip = tooltip_owner ? tooltip_owner->make_custom_tooltip(gui.tooltip_text) : nullptr;
+
+ if (gui.tooltip_text.is_empty() && !base_tooltip) {
return; // Nothing to show.
}
@@ -1469,21 +1473,17 @@ void Viewport::_gui_show_tooltip() {
// Ensure no opaque background behind the panel as its StyleBox can be partially transparent (e.g. corners).
panel->set_transparent_background(true);
- // Controls can implement `make_custom_tooltip` to provide their own tooltip.
- // This should be a Control node which will be added as child to a TooltipPanel.
- Control *base_tooltip = tooltip_owner->make_custom_tooltip(gui.tooltip_text);
-
// If no custom tooltip is given, use a default implementation.
if (!base_tooltip) {
gui.tooltip_label = memnew(Label);
gui.tooltip_label->set_theme_type_variation(SNAME("TooltipLabel"));
gui.tooltip_label->set_text(gui.tooltip_text);
+ gui.tooltip_label->set_auto_translate_mode(tooltip_owner->get_tooltip_auto_translate_mode());
base_tooltip = gui.tooltip_label;
panel->connect(SceneStringName(mouse_entered), callable_mp(this, &Viewport::_gui_cancel_tooltip));
}
base_tooltip->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- base_tooltip->set_auto_translate_mode(tooltip_owner->get_tooltip_auto_translate_mode());
panel->set_transient(true);
panel->set_flag(Window::FLAG_NO_FOCUS, true);
@@ -1921,7 +1921,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
String tooltip = _gui_get_tooltip(over, gui.tooltip_control->get_global_transform_with_canvas().affine_inverse().xform(mpos));
tooltip = tooltip.strip_edges();
- if (tooltip.is_empty() || tooltip != gui.tooltip_text) {
+ if (tooltip != gui.tooltip_text) {
_gui_cancel_tooltip();
} else {
is_tooltip_shown = true;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 803ce89bc9..045c3ae02d 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -2635,7 +2635,7 @@ void Window::set_unparent_when_invisible(bool p_unparent) {
void Window::set_layout_direction(Window::LayoutDirection p_direction) {
ERR_MAIN_THREAD_GUARD;
- ERR_FAIL_INDEX((int)p_direction, 4);
+ ERR_FAIL_INDEX(p_direction, LAYOUT_DIRECTION_MAX);
layout_dir = p_direction;
propagate_notification(Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED);
@@ -2700,13 +2700,20 @@ bool Window::is_layout_rtl() const {
String locale = TranslationServer::get_singleton()->get_tool_locale();
return TS->is_locale_right_to_left(locale);
}
- } else if (layout_dir == LAYOUT_DIRECTION_LOCALE) {
+ } else if (layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) {
if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
return true;
} else {
String locale = TranslationServer::get_singleton()->get_tool_locale();
return TS->is_locale_right_to_left(locale);
}
+ } else if (layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) {
+ if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
+ return true;
+ } else {
+ String locale = OS::get_singleton()->get_locale();
+ return TS->is_locale_right_to_left(locale);
+ }
} else {
return (layout_dir == LAYOUT_DIRECTION_RTL);
}
@@ -3001,6 +3008,7 @@ void Window::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "sharp_corners"), "set_flag", "get_flag", FLAG_SHARP_CORNERS);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_native"), "set_force_native", "get_force_native");
ADD_GROUP("Limits", "");
@@ -3054,6 +3062,7 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_POPUP);
BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE);
BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH);
+ BIND_ENUM_CONSTANT(FLAG_SHARP_CORNERS);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
@@ -3070,9 +3079,14 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(CONTENT_SCALE_STRETCH_INTEGER);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_INHERITED);
- BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_APPLICATION_LOCALE);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LTR);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_SYSTEM_LOCALE);
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_MAX);
+#ifndef DISABLE_DEPRECATED
+ BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE);
+#endif // DISABLE_DEPRECATED
BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_ABSOLUTE);
BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN);
diff --git a/scene/main/window.h b/scene/main/window.h
index 47aaf73728..0994fc6012 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -62,6 +62,7 @@ public:
FLAG_POPUP = DisplayServer::WINDOW_FLAG_POPUP,
FLAG_EXTEND_TO_TITLE = DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE,
FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH,
+ FLAG_SHARP_CORNERS = DisplayServer::WINDOW_FLAG_SHARP_CORNERS,
FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
};
@@ -86,9 +87,14 @@ public:
enum LayoutDirection {
LAYOUT_DIRECTION_INHERITED,
- LAYOUT_DIRECTION_LOCALE,
+ LAYOUT_DIRECTION_APPLICATION_LOCALE,
LAYOUT_DIRECTION_LTR,
- LAYOUT_DIRECTION_RTL
+ LAYOUT_DIRECTION_RTL,
+ LAYOUT_DIRECTION_SYSTEM_LOCALE,
+ LAYOUT_DIRECTION_MAX,
+#ifndef DISABLE_DEPRECATED
+ LAYOUT_DIRECTION_LOCALE = LAYOUT_DIRECTION_APPLICATION_LOCALE,
+#endif // DISABLE_DEPRECATED
};
enum {
@@ -368,7 +374,7 @@ public:
bool is_wrapping_controls() const;
void child_controls_changed();
- Window *get_exclusive_child() const { return exclusive_child; };
+ Window *get_exclusive_child() const { return exclusive_child; }
Window *get_parent_visible_window() const;
Viewport *get_parent_viewport() const;
diff --git a/scene/property_utils.cpp b/scene/property_utils.cpp
index 94a037bd9b..f068e34beb 100644
--- a/scene/property_utils.cpp
+++ b/scene/property_utils.cpp
@@ -89,6 +89,16 @@ Variant PropertyUtils::get_property_default_value(const Object *p_object, const
*r_is_valid = false;
}
+ // Handle special case "script" property, where the default value is either null or the custom type script.
+ // Do this only if there's no states stack cache to trace for default values.
+ if (!p_states_stack_cache && p_property == CoreStringName(script) && p_object->has_meta(SceneStringName(_custom_type_script))) {
+ Ref<Script> ct_scr = p_object->get_meta(SceneStringName(_custom_type_script));
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return ct_scr;
+ }
+
Ref<Script> topmost_script;
if (const Node *node = Object::cast_to<Node>(p_object)) {
diff --git a/scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp b/scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp
index e3f14539a8..07e9caa713 100644
--- a/scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp
+++ b/scene/resources/2d/navigation_mesh_source_geometry_data_2d.cpp
@@ -43,7 +43,7 @@ void NavigationMeshSourceGeometryData2D::clear() {
bool NavigationMeshSourceGeometryData2D::has_data() {
RWLockRead read_lock(geometry_rwlock);
return traversable_outlines.size();
-};
+}
void NavigationMeshSourceGeometryData2D::clear_projected_obstructions() {
RWLockWrite write_lock(geometry_rwlock);
diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp
index 229e18be23..ca80486363 100644
--- a/scene/resources/2d/tile_set.cpp
+++ b/scene/resources/2d/tile_set.cpp
@@ -174,13 +174,13 @@ void TileMapPattern::set_size(const Size2i &p_size) {
bool TileMapPattern::is_empty() const {
return pattern.is_empty();
-};
+}
void TileMapPattern::clear() {
size = Size2i();
pattern.clear();
emit_changed();
-};
+}
bool TileMapPattern::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "tile_data") {
@@ -571,11 +571,11 @@ void TileSet::set_uv_clipping(bool p_uv_clipping) {
bool TileSet::is_uv_clipping() const {
return uv_clipping;
-};
+}
int TileSet::get_occlusion_layers_count() const {
return occlusion_layers.size();
-};
+}
void TileSet::add_occlusion_layer(int p_index) {
if (p_index < 0) {
@@ -3691,7 +3691,7 @@ Array TileSet::compatibility_tilemap_map(int p_tile_id, Vector2i p_coords, bool
return cannot_convert_array;
break;
}
-};
+}
#endif // DISABLE_DEPRECATED
@@ -4432,7 +4432,7 @@ TileSet *TileSetSource::get_tile_set() const {
void TileSetSource::reset_state() {
tile_set = nullptr;
-};
+}
void TileSetSource::_bind_methods() {
// Base tiles
@@ -6480,9 +6480,9 @@ int TileData::get_terrain_set() const {
}
void TileData::set_terrain(int p_terrain) {
- ERR_FAIL_COND(terrain_set < 0);
ERR_FAIL_COND(p_terrain < -1);
- if (tile_set) {
+ ERR_FAIL_COND(terrain_set < 0 && p_terrain != -1);
+ if (tile_set && terrain_set >= 0) {
ERR_FAIL_COND(p_terrain >= tile_set->get_terrains_count(terrain_set));
}
terrain = p_terrain;
@@ -6495,9 +6495,9 @@ int TileData::get_terrain() const {
void TileData::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
ERR_FAIL_INDEX(p_peering_bit, TileSet::CellNeighbor::CELL_NEIGHBOR_MAX);
- ERR_FAIL_COND(terrain_set < 0);
ERR_FAIL_COND(p_terrain_index < -1);
- if (tile_set) {
+ ERR_FAIL_COND(terrain_set < 0 && p_terrain_index != -1);
+ if (tile_set && terrain_set >= 0) {
ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
ERR_FAIL_COND(!is_valid_terrain_peering_bit(p_peering_bit));
}
diff --git a/scene/resources/2d/tile_set.h b/scene/resources/2d/tile_set.h
index 15e1a16359..7979e2ca39 100644
--- a/scene/resources/2d/tile_set.h
+++ b/scene/resources/2d/tile_set.h
@@ -278,7 +278,7 @@ public:
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
bool operator!=(const TerrainsPattern &p_terrains_pattern) const {
return !operator==(p_terrains_pattern);
- };
+ }
void set_terrain(int p_terrain);
int get_terrain() const;
@@ -812,8 +812,8 @@ public:
// Scenes accessors. Lot are similar to "Alternative tiles".
int get_scene_tiles_count() { return get_alternative_tiles_count(Vector2i()); }
- int get_scene_tile_id(int p_index) { return get_alternative_tile_id(Vector2i(), p_index); };
- bool has_scene_tile_id(int p_id) { return has_alternative_tile(Vector2i(), p_id); };
+ int get_scene_tile_id(int p_index) { return get_alternative_tile_id(Vector2i(), p_index); }
+ bool has_scene_tile_id(int p_id) { return has_alternative_tile(Vector2i(), p_id); }
int create_scene_tile(Ref<PackedScene> p_packed_scene = Ref<PackedScene>(), int p_id_override = -1);
void set_scene_tile_id(int p_id, int p_new_id);
void set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene);
diff --git a/scene/resources/3d/importer_mesh.cpp b/scene/resources/3d/importer_mesh.cpp
index 47cd64f19a..fa2532a310 100644
--- a/scene/resources/3d/importer_mesh.cpp
+++ b/scene/resources/3d/importer_mesh.cpp
@@ -503,6 +503,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
merged_normals_f32.ptr(),
sizeof(float) * 3, // Attribute stride
normal_weights, 3,
+ nullptr, // Vertex lock
index_target,
max_mesh_error,
simplify_options,
diff --git a/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp b/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
index 59366592ce..74dca88423 100644
--- a/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
+++ b/scene/resources/3d/navigation_mesh_source_geometry_data_3d.cpp
@@ -71,7 +71,7 @@ void NavigationMeshSourceGeometryData3D::append_arrays(const Vector<float> &p_ve
bool NavigationMeshSourceGeometryData3D::has_data() {
RWLockRead read_lock(geometry_rwlock);
return vertices.size() && indices.size();
-};
+}
void NavigationMeshSourceGeometryData3D::clear() {
RWLockWrite write_lock(geometry_rwlock);
diff --git a/scene/resources/3d/primitive_meshes.h b/scene/resources/3d/primitive_meshes.h
index 85f46a482a..e68ac7fb26 100644
--- a/scene/resources/3d/primitive_meshes.h
+++ b/scene/resources/3d/primitive_meshes.h
@@ -545,7 +545,7 @@ private:
ContourPoint(const Vector2 &p_pt, bool p_sharp) {
point = p_pt;
sharp = p_sharp;
- };
+ }
};
struct ContourInfo {
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 57a4e35f7a..f0b182503a 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1048,7 +1048,7 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const
}
};
return -1;
-};
+}
Animation::TrackType Animation::get_cache_type(TrackType p_type) {
if (p_type == Animation::TYPE_BEZIER) {
diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp
index 3a021720c6..3a0c207a5d 100644
--- a/scene/resources/camera_attributes.cpp
+++ b/scene/resources/camera_attributes.cpp
@@ -487,7 +487,7 @@ void CameraAttributesPhysical::_bind_methods() {
ADD_GROUP("Auto Exposure", "auto_exposure_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_min_exposure_value", "get_auto_exposure_min_exposure_value");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_max_exposure_value", "get_auto_exposure_max_exposure_value");
-};
+}
CameraAttributesPhysical::CameraAttributesPhysical() {
_update_exposure();
diff --git a/scene/resources/external_texture.cpp b/scene/resources/external_texture.cpp
index 0552bbd081..c8b714372a 100644
--- a/scene/resources/external_texture.cpp
+++ b/scene/resources/external_texture.cpp
@@ -39,12 +39,14 @@ void ExternalTexture::_bind_methods() {
}
uint64_t ExternalTexture::get_external_texture_id() const {
+ _ensure_created();
return RenderingServer::get_singleton()->texture_get_native_handle(texture);
}
void ExternalTexture::set_size(const Size2 &p_size) {
if (p_size.width > 0 && p_size.height > 0 && p_size != size) {
size = p_size;
+ _ensure_created();
RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer);
emit_changed();
}
@@ -57,6 +59,7 @@ Size2 ExternalTexture::get_size() const {
void ExternalTexture::set_external_buffer_id(uint64_t p_external_buffer) {
if (p_external_buffer != external_buffer) {
external_buffer = p_external_buffer;
+ _ensure_created();
RenderingServer::get_singleton()->texture_external_update(texture, size.width, size.height, external_buffer);
}
}
@@ -74,11 +77,29 @@ bool ExternalTexture::has_alpha() const {
}
RID ExternalTexture::get_rid() const {
+ if (!texture.is_valid()) {
+ texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ using_placeholder = true;
+ }
return texture;
}
+void ExternalTexture::_ensure_created() const {
+ if (texture.is_valid() && !using_placeholder) {
+ return;
+ }
+
+ RID new_texture = RenderingServer::get_singleton()->texture_external_create(size.width, size.height);
+ if (using_placeholder) {
+ DEV_ASSERT(texture.is_valid());
+ RenderingServer::get_singleton()->texture_replace(texture, new_texture);
+ using_placeholder = false;
+ } else {
+ texture = new_texture;
+ }
+}
+
ExternalTexture::ExternalTexture() {
- texture = RenderingServer::get_singleton()->texture_external_create(size.width, size.height);
}
ExternalTexture::~ExternalTexture() {
diff --git a/scene/resources/external_texture.h b/scene/resources/external_texture.h
index 96bcd8d0fe..cd60bcc030 100644
--- a/scene/resources/external_texture.h
+++ b/scene/resources/external_texture.h
@@ -38,10 +38,13 @@ class ExternalTexture : public Texture2D {
GDCLASS(ExternalTexture, Texture2D);
private:
- RID texture;
+ mutable RID texture;
+ mutable bool using_placeholder = false;
Size2 size = Size2(256, 256);
uint64_t external_buffer = 0;
+ void _ensure_created() const;
+
protected:
static void _bind_methods();
diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp
index 907c0ab4ca..072542f0ad 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -312,6 +312,8 @@ void ImmediateMesh::surface_end() {
uses_uv2s = false;
surface_active = false;
+
+ emit_changed();
}
void ImmediateMesh::clear_surfaces() {
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 4d1d733f8b..848ae2713d 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -45,23 +45,23 @@ void MeshConvexDecompositionSettings::set_max_concavity(real_t p_max_concavity)
real_t MeshConvexDecompositionSettings::get_max_concavity() const {
return max_concavity;
-};
+}
void MeshConvexDecompositionSettings::set_symmetry_planes_clipping_bias(real_t p_symmetry_planes_clipping_bias) {
symmetry_planes_clipping_bias = CLAMP(p_symmetry_planes_clipping_bias, 0.0, 1.0);
-};
+}
real_t MeshConvexDecompositionSettings::get_symmetry_planes_clipping_bias() const {
return symmetry_planes_clipping_bias;
-};
+}
void MeshConvexDecompositionSettings::set_revolution_axes_clipping_bias(real_t p_revolution_axes_clipping_bias) {
revolution_axes_clipping_bias = CLAMP(p_revolution_axes_clipping_bias, 0.0, 1.0);
-};
+}
real_t MeshConvexDecompositionSettings::get_revolution_axes_clipping_bias() const {
return revolution_axes_clipping_bias;
-};
+}
void MeshConvexDecompositionSettings::set_min_volume_per_convex_hull(real_t p_min_volume_per_convex_hull) {
min_volume_per_convex_hull = CLAMP(p_min_volume_per_convex_hull, 0.0001, 0.01);
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index e234a81c88..4a318a10f0 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -1431,8 +1431,8 @@ void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String &
p_extensions->push_back("tscn");
}
- // Don't allow .tres for PackedScenes.
- if (p_type != "PackedScene") {
+ // Don't allow .tres for PackedScenes or GDExtension.
+ if (p_type != "PackedScene" && p_type != "GDExtension") {
p_extensions->push_back("tres");
}
}
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 24d17108d5..d163a42fa9 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -32,6 +32,7 @@
#include "shader.compat.inc"
#include "core/io/file_access.h"
+#include "scene/main/scene_tree.h"
#include "servers/rendering/shader_language.h"
#include "servers/rendering/shader_preprocessor.h"
#include "servers/rendering_server.h"
@@ -138,6 +139,14 @@ String Shader::get_code() const {
return code;
}
+void Shader::inspect_native_shader_code() {
+ SceneTree *st = SceneTree::get_singleton();
+ RID _shader = get_rid();
+ if (st && _shader.is_valid()) {
+ st->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_native_shader_source_visualizer", "_inspect_shader", _shader);
+ }
+}
+
void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
_update_shader();
_check_shader_rid();
@@ -267,6 +276,9 @@ void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shader_uniform_list", "get_groups"), &Shader::_get_shader_uniform_list, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("inspect_native_shader_code"), &Shader::inspect_native_shader_code);
+ ClassDB::set_method_flags(get_class_static(), _scs_create("inspect_native_shader_code"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code");
BIND_ENUM_CONSTANT(MODE_SPATIAL);
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 18197419f3..7234d37579 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -88,6 +88,8 @@ public:
void set_code(const String &p_code);
String get_code() const;
+ void inspect_native_shader_code();
+
void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
void set_default_texture_parameter(const StringName &p_name, const Ref<Texture> &p_texture, int p_index = 0);
diff --git a/scene/resources/style_box_flat.cpp b/scene/resources/style_box_flat.cpp
index 15816925c1..202ab3615b 100644
--- a/scene/resources/style_box_flat.cpp
+++ b/scene/resources/style_box_flat.cpp
@@ -596,10 +596,10 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "skew"), "set_skew", "get_skew");
ADD_GROUP("Border Width", "border_width_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_border_width", "get_border_width", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_border_width", "get_border_width", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_border_width", "get_border_width", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_border_width", "get_border_width", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_border_width", "get_border_width", SIDE_BOTTOM);
ADD_GROUP("Border", "border_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color");
@@ -607,18 +607,18 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "border_blend"), "set_border_blend", "get_border_blend");
ADD_GROUP("Corner Radius", "corner_radius_");
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,1024,1,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_left", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_top_right", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_TOP_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_right", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "corner_radius_bottom_left", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_corner_radius", "get_corner_radius", CORNER_BOTTOM_LEFT);
ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail");
ADD_GROUP("Expand Margins", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index a072df5bee..3b18e082a1 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -80,13 +80,19 @@ public:
enum {
/* Do not move vertices that are located on the topological border (vertices on triangle edges that don't have a paired triangle). Useful for simplifying portions of the larger mesh. */
SIMPLIFY_LOCK_BORDER = 1 << 0, // From meshopt_SimplifyLockBorder
+ /* Improve simplification performance assuming input indices are a sparse subset of the mesh. Note that error becomes relative to subset extents. */
+ SIMPLIFY_SPARSE = 1 << 1, // From meshopt_SimplifySparse
+ /* Treat error limit and resulting error as absolute instead of relative to mesh extents. */
+ SIMPLIFY_ERROR_ABSOLUTE = 1 << 2, // From meshopt_SimplifyErrorAbsolute
+ /* Remove disconnected parts of the mesh during simplification incrementally, regardless of the topological restrictions inside components. */
+ SIMPLIFY_PRUNE = 1 << 3, // From meshopt_SimplifyPrune
};
typedef void (*OptimizeVertexCacheFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count);
static OptimizeVertexCacheFunc optimize_vertex_cache_func;
typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, unsigned int options, float *r_error);
static SimplifyFunc simplify_func;
- typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, const float *attributes, size_t attribute_stride, const float *attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float *result_error);
+ typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, const float *attributes, size_t attribute_stride, const float *attribute_weights, size_t attribute_count, const unsigned char *vertex_lock, size_t target_index_count, float target_error, unsigned int options, float *result_error);
static SimplifyWithAttribFunc simplify_with_attrib_func;
typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
static SimplifyScaleFunc simplify_scale_func;
@@ -113,7 +119,7 @@ private:
SmoothGroupVertex(const Vertex &p_vertex) {
vertex = p_vertex.vertex;
smooth_group = p_vertex.smooth_group;
- };
+ }
};
struct SmoothGroupVertexHasher {
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 7512955fb3..8b7f21fa9a 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -152,7 +152,7 @@ public:
int hit_test(const Point2 &p_coords) const;
- Mutex &get_mutex() const { return _thread_safe_; };
+ Mutex &get_mutex() const { return _thread_safe_; }
TextParagraph(const String &p_text, const Ref<Font> &p_font, int p_font_size, const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
TextParagraph();
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 140e588291..31daeb3ae3 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -130,6 +130,8 @@ SceneStringNames::SceneStringNames() {
shader_overrides_group = StaticCString::create("_shader_overrides_group_");
shader_overrides_group_active = StaticCString::create("_shader_overrides_group_active_");
+ _custom_type_script = StaticCString::create("_custom_type_script");
+
pressed = StaticCString::create("pressed");
id_pressed = StaticCString::create("id_pressed");
toggled = StaticCString::create("toggled");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index fc22be33b2..0a2ebeda7a 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -143,6 +143,8 @@ public:
StringName shader_overrides_group;
StringName shader_overrides_group_active;
+ StringName _custom_type_script;
+
StringName pressed;
StringName id_pressed;
StringName toggled;
diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp
index caf44ac392..f5065e8de1 100644
--- a/scene/theme/default_theme.cpp
+++ b/scene/theme/default_theme.cpp
@@ -30,6 +30,7 @@
#include "default_theme.h"
+#include "core/io/image.h"
#include "core/os/os.h"
#include "default_font.gen.h"
#include "default_theme_icons.gen.h"
@@ -832,10 +833,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox(SceneStringName(panel), "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
theme->set_stylebox("focus", "Tree", focus);
+ theme->set_stylebox("hovered", "Tree", make_flat_stylebox(Color(1, 1, 1, 0.07)));
+ theme->set_stylebox("hovered_dimmed", "Tree", make_flat_stylebox(Color(1, 1, 1, 0.03)));
theme->set_stylebox("selected", "Tree", make_flat_stylebox(style_selected_color));
theme->set_stylebox("selected_focus", "Tree", make_flat_stylebox(style_selected_color));
theme->set_stylebox("cursor", "Tree", focus);
theme->set_stylebox("cursor_unfocused", "Tree", focus);
+ theme->set_stylebox("button_hover", "Tree", make_flat_stylebox(Color(1, 1, 1, 0.07)));
theme->set_stylebox("button_pressed", "Tree", button_pressed);
theme->set_stylebox("title_button_normal", "Tree", make_flat_stylebox(style_pressed_color, 4, 4, 4, 4));
theme->set_stylebox("title_button_pressed", "Tree", make_flat_stylebox(style_hover_color, 4, 4, 4, 4));
@@ -863,6 +867,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("title_button_color", "Tree", control_font_color);
theme->set_color(SceneStringName(font_color), "Tree", control_font_low_color);
+ theme->set_color("font_hovered_color", "Tree", control_font_hover_color);
+ theme->set_color("font_hovered_dimmed_color", "Tree", control_font_color);
theme->set_color("font_selected_color", "Tree", control_font_pressed_color);
theme->set_color("font_disabled_color", "Tree", control_font_disabled_color);
theme->set_color("font_outline_color", "Tree", Color(0, 0, 0));