summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/camera_2d.cpp3
-rw-r--r--scene/2d/cpu_particles_2d.cpp36
-rw-r--r--scene/2d/cpu_particles_2d.h18
-rw-r--r--scene/2d/gpu_particles_2d.cpp4
-rw-r--r--scene/2d/light_occluder_2d.cpp4
-rw-r--r--scene/2d/line_builder.cpp33
-rw-r--r--scene/2d/path_2d.cpp14
-rw-r--r--scene/2d/path_2d.h4
-rw-r--r--scene/3d/area_3d.cpp10
-rw-r--r--scene/3d/area_3d.h4
-rw-r--r--scene/3d/audio_stream_player_3d.cpp5
-rw-r--r--scene/3d/camera_3d.cpp6
-rw-r--r--scene/3d/cpu_particles_3d.cpp72
-rw-r--r--scene/3d/cpu_particles_3d.h18
-rw-r--r--scene/3d/navigation_region_3d.cpp1
-rw-r--r--scene/3d/path_3d.cpp6
-rw-r--r--scene/3d/physics_joint_3d.cpp13
-rw-r--r--scene/3d/physics_joint_3d.h7
-rw-r--r--scene/3d/proximity_group_3d.cpp94
-rw-r--r--scene/3d/proximity_group_3d.h27
-rw-r--r--scene/3d/reflection_probe.cpp14
-rw-r--r--scene/3d/reflection_probe.h4
-rw-r--r--scene/3d/skeleton_3d.cpp2
-rw-r--r--scene/3d/skeleton_ik_3d.h4
-rw-r--r--scene/3d/soft_body_3d.cpp1
-rw-r--r--scene/3d/sprite_3d.cpp4
-rw-r--r--scene/3d/visual_instance_3d.cpp16
-rw-r--r--scene/3d/visual_instance_3d.h5
-rw-r--r--scene/3d/xr_nodes.cpp8
-rw-r--r--scene/SCsub18
-rw-r--r--scene/animation/SCsub21
-rw-r--r--scene/animation/animation_node_state_machine.cpp4
-rw-r--r--scene/gui/color_picker.cpp2
-rw-r--r--scene/gui/control.cpp146
-rw-r--r--scene/gui/control.h18
-rw-r--r--scene/gui/dialogs.cpp14
-rw-r--r--scene/gui/dialogs.h6
-rw-r--r--scene/gui/file_dialog.cpp20
-rw-r--r--scene/gui/graph_edit.cpp389
-rw-r--r--scene/gui/graph_edit.h67
-rw-r--r--scene/gui/item_list.cpp1
-rw-r--r--scene/gui/label.cpp35
-rw-r--r--scene/gui/line_edit.cpp21
-rw-r--r--scene/gui/popup_menu.cpp39
-rw-r--r--scene/gui/rich_text_effect.cpp31
-rw-r--r--scene/gui/rich_text_effect.h29
-rw-r--r--scene/gui/rich_text_label.cpp2730
-rw-r--r--scene/gui/rich_text_label.h269
-rw-r--r--scene/gui/scroll_bar.cpp12
-rw-r--r--scene/gui/scroll_bar.h1
-rw-r--r--scene/gui/scroll_container.cpp2
-rw-r--r--scene/gui/tab_container.cpp29
-rw-r--r--scene/gui/tab_container.h4
-rw-r--r--scene/gui/tabs.cpp8
-rw-r--r--scene/gui/text_edit.cpp38
-rw-r--r--scene/gui/text_edit.h2
-rw-r--r--scene/gui/texture_progress_bar.cpp (renamed from scene/gui/texture_progress.cpp)114
-rw-r--r--scene/gui/texture_progress_bar.h (renamed from scene/gui/texture_progress.h)16
-rw-r--r--scene/gui/tree.cpp10
-rw-r--r--scene/gui/tree.h2
-rw-r--r--scene/main/canvas_item.cpp4
-rw-r--r--scene/main/node.h5
-rw-r--r--scene/main/scene_tree.cpp4
-rw-r--r--scene/main/viewport.cpp25
-rw-r--r--scene/main/viewport.h8
-rw-r--r--scene/main/window.cpp10
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/register_scene_types.cpp27
-rw-r--r--scene/resources/SCsub21
-rw-r--r--scene/resources/animation.cpp6
-rw-r--r--scene/resources/animation.h2
-rw-r--r--scene/resources/default_theme/default_theme.cpp54
-rw-r--r--scene/resources/default_theme/icon_grid_minimap.pngbin0 -> 640 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h4
-rw-r--r--scene/resources/environment.cpp2
-rw-r--r--scene/resources/font.cpp147
-rw-r--r--scene/resources/font.h20
-rw-r--r--scene/resources/material.cpp6
-rw-r--r--scene/resources/mesh.cpp280
-rw-r--r--scene/resources/mesh.h85
-rw-r--r--scene/resources/packed_scene.cpp10
-rw-r--r--scene/resources/packed_scene.h1
-rw-r--r--scene/resources/particles_material.cpp64
-rw-r--r--scene/resources/particles_material.h26
-rw-r--r--scene/resources/primitive_meshes.cpp42
-rw-r--r--scene/resources/primitive_meshes.h8
-rw-r--r--scene/resources/resource_format_text.cpp1
-rw-r--r--scene/resources/sky_material.cpp2
-rw-r--r--scene/resources/style_box.cpp10
-rw-r--r--scene/resources/style_box.h1
-rw-r--r--scene/resources/surface_tool.cpp725
-rw-r--r--scene/resources/surface_tool.h81
-rw-r--r--scene/resources/text_line.cpp24
-rw-r--r--scene/resources/text_line.h2
-rw-r--r--scene/resources/text_paragraph.cpp57
-rw-r--r--scene/resources/text_paragraph.h2
-rw-r--r--scene/resources/theme.cpp146
-rw-r--r--scene/resources/theme.h22
-rw-r--r--scene/resources/visual_shader.cpp41
-rw-r--r--scene/resources/visual_shader.h2
-rw-r--r--scene/scene_string_names.cpp2
-rw-r--r--scene/scene_string_names.h2
102 files changed, 4271 insertions, 2247 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 79b0b64efb..0d09d21a71 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -77,6 +77,9 @@ void Camera2D::_update_process_mode() {
}
void Camera2D::set_zoom(const Vector2 &p_zoom) {
+ // Setting zoom to zero causes 'affine_invert' issues
+ ERR_FAIL_COND_MSG(Math::is_zero_approx(p_zoom.x) || Math::is_zero_approx(p_zoom.y), "Zoom level must be different from 0 (can be negative).");
+
zoom = p_zoom;
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
_update_scroll();
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index ef2a9a4911..3649746c40 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -397,14 +397,14 @@ Ref<Gradient> CPUParticles2D::get_color_ramp() const {
return color_ramp;
}
-void CPUParticles2D::set_particle_flag(Flags p_flag, bool p_enable) {
- ERR_FAIL_INDEX(p_flag, FLAG_MAX);
- flags[p_flag] = p_enable;
+void CPUParticles2D::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
+ ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX);
+ particle_flags[p_particle_flag] = p_enable;
}
-bool CPUParticles2D::get_particle_flag(Flags p_flag) const {
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags[p_flag];
+bool CPUParticles2D::get_particle_flag(ParticleFlags p_particle_flag) const {
+ ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false);
+ return particle_flags[p_particle_flag];
}
void CPUParticles2D::set_emission_shape(EmissionShape p_shape) {
@@ -905,7 +905,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.color *= p.base_color;
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
if (p.velocity.length() > 0.0) {
p.transform.elements[1] = p.velocity.normalized();
p.transform.elements[0] = p.transform.elements[1].tangent();
@@ -1130,7 +1130,7 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
set_color_ramp(gt->get_gradient());
}
- set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
@@ -1246,8 +1246,8 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles2D::set_color_ramp);
ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles2D::get_color_ramp);
- ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles2D::set_particle_flag);
- ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles2D::get_particle_flag);
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &CPUParticles2D::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &CPUParticles2D::get_particle_flag);
ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles2D::set_emission_shape);
ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles2D::get_emission_shape);
@@ -1279,8 +1279,8 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
- ADD_GROUP("Flags", "flag_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY);
+ ADD_GROUP("Particle Flags", "particle_flag_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
ADD_GROUP("Direction", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "direction"), "set_direction", "get_direction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
@@ -1351,10 +1351,10 @@ void CPUParticles2D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
BIND_ENUM_CONSTANT(PARAM_MAX);
- BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
- BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); // Unused, but exposed for consistency with 3D.
- BIND_ENUM_CONSTANT(FLAG_DISABLE_Z); // Unused, but exposed for consistency with 3D.
- BIND_ENUM_CONSTANT(FLAG_MAX);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y); // Unused, but exposed for consistency with 3D.
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z); // Unused, but exposed for consistency with 3D.
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
@@ -1415,8 +1415,8 @@ CPUParticles2D::CPUParticles2D() {
set_param_randomness(Parameter(i), 0);
}
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
+ for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
+ particle_flags[i] = false;
}
set_color(Color(1, 1, 1, 1));
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 0f2a3e4920..857f19b20f 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -61,11 +61,11 @@ public:
PARAM_MAX
};
- enum Flags {
- FLAG_ALIGN_Y_TO_VELOCITY,
- FLAG_ROTATE_Y, // Unused, but exposed for consistency with 3D.
- FLAG_DISABLE_Z, // Unused, but exposed for consistency with 3D.
- FLAG_MAX
+ enum ParticleFlags {
+ PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY,
+ PARTICLE_FLAG_ROTATE_Y, // Unused, but exposed for consistency with 3D.
+ PARTICLE_FLAG_DISABLE_Z, // Unused, but exposed for consistency with 3D.
+ PARTICLE_FLAG_MAX
};
enum EmissionShape {
@@ -159,7 +159,7 @@ private:
Color color;
Ref<Gradient> color_ramp;
- bool flags[FLAG_MAX];
+ bool particle_flags[PARTICLE_FLAG_MAX];
EmissionShape emission_shape;
float emission_sphere_radius;
@@ -253,8 +253,8 @@ public:
void set_color_ramp(const Ref<Gradient> &p_ramp);
Ref<Gradient> get_color_ramp() const;
- void set_particle_flag(Flags p_flag, bool p_enable);
- bool get_particle_flag(Flags p_flag) const;
+ void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable);
+ bool get_particle_flag(ParticleFlags p_particle_flag) const;
void set_emission_shape(EmissionShape p_shape);
void set_emission_sphere_radius(float p_radius);
@@ -287,7 +287,7 @@ public:
VARIANT_ENUM_CAST(CPUParticles2D::DrawOrder)
VARIANT_ENUM_CAST(CPUParticles2D::Parameter)
-VARIANT_ENUM_CAST(CPUParticles2D::Flags)
+VARIANT_ENUM_CAST(CPUParticles2D::ParticleFlags)
VARIANT_ENUM_CAST(CPUParticles2D::EmissionShape)
#endif // CPU_PARTICLES_2D_H
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index a4a930455b..46096d7460 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -127,9 +127,9 @@ void GPUParticles2D::_update_particle_emission_transform() {
void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
process_material = p_material;
Ref<ParticlesMaterial> pm = p_material;
- if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
+ if (pm.is_valid() && !pm->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
// Likely a new (3D) material, modify it to match 2D space
- pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true);
+ pm->set_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z, true);
pm->set_gravity(Vector3(0, 98, 0));
}
RID material_rid;
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 6908fbeada..b5b39ccc8f 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -238,7 +238,7 @@ Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const {
void LightOccluder2D::set_occluder_light_mask(int p_mask) {
mask = p_mask;
- RS::get_singleton()->canvas_light_occluder_set_light_mask(occluder, mask);
+ RS::get_singleton()->canvas_light_occluder_set_light_mask(occluder, p_mask);
}
int LightOccluder2D::get_occluder_light_mask() const {
@@ -285,7 +285,7 @@ void LightOccluder2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"), "set_occluder_polygon", "get_occluder_polygon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdf_collision"), "set_as_sdf_collision", "is_set_as_sdf_collision");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "occluder_light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask");
}
LightOccluder2D::LightOccluder2D() {
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index f1522dbaeb..e0116d9bad 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -459,39 +459,6 @@ void LineBuilder::strip_begin(Vector2 up, Vector2 down, Color color, float uvx)
_last_index[DOWN] = vi + 1;
}
-void LineBuilder::strip_new_quad(Vector2 up, Vector2 down, Color color, float uvx) {
- int vi = vertices.size();
-
- vertices.push_back(vertices[_last_index[UP]]);
- vertices.push_back(vertices[_last_index[DOWN]]);
- vertices.push_back(up);
- vertices.push_back(down);
-
- if (_interpolate_color) {
- colors.push_back(color);
- colors.push_back(color);
- colors.push_back(color);
- colors.push_back(color);
- }
-
- if (texture_mode != Line2D::LINE_TEXTURE_NONE) {
- uvs.push_back(uvs[_last_index[UP]]);
- uvs.push_back(uvs[_last_index[DOWN]]);
- uvs.push_back(Vector2(uvx, UP));
- uvs.push_back(Vector2(uvx, DOWN));
- }
-
- indices.push_back(vi);
- indices.push_back(vi + 3);
- indices.push_back(vi + 1);
- indices.push_back(vi);
- indices.push_back(vi + 2);
- indices.push_back(vi + 3);
-
- _last_index[UP] = vi + 2;
- _last_index[DOWN] = vi + 3;
-}
-
void LineBuilder::strip_add_quad(Vector2 up, Vector2 down, Color color, float uvx) {
int vi = vertices.size();
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index d305f2805e..f40a993423 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -170,7 +170,7 @@ void PathFollow2D::_update_transform() {
}
Vector2 pos = c->interpolate_baked(offset, cubic);
- if (rotate) {
+ if (rotates) {
float ahead = offset + lookahead;
if (loop && ahead >= path_length) {
@@ -279,7 +279,7 @@ void PathFollow2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &PathFollow2D::set_unit_offset);
ClassDB::bind_method(D_METHOD("get_unit_offset"), &PathFollow2D::get_unit_offset);
- ClassDB::bind_method(D_METHOD("set_rotate", "enable"), &PathFollow2D::set_rotate);
+ ClassDB::bind_method(D_METHOD("set_rotates", "enable"), &PathFollow2D::set_rotates);
ClassDB::bind_method(D_METHOD("is_rotating"), &PathFollow2D::is_rotating);
ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &PathFollow2D::set_cubic_interpolation);
@@ -295,7 +295,7 @@ void PathFollow2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotate"), "set_rotate", "is_rotating");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotates"), "set_rotates", "is_rotating");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead");
@@ -371,13 +371,13 @@ float PathFollow2D::get_lookahead() const {
return lookahead;
}
-void PathFollow2D::set_rotate(bool p_rotate) {
- rotate = p_rotate;
+void PathFollow2D::set_rotates(bool p_rotates) {
+ rotates = p_rotates;
_update_transform();
}
bool PathFollow2D::is_rotating() const {
- return rotate;
+ return rotates;
}
void PathFollow2D::set_loop(bool p_loop) {
@@ -393,7 +393,7 @@ PathFollow2D::PathFollow2D() {
h_offset = 0;
v_offset = 0;
path = nullptr;
- rotate = true;
+ rotates = true;
cubic = true;
loop = true;
lookahead = 4;
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index 7fea75cd7c..fcb8b40125 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -70,7 +70,7 @@ private:
real_t lookahead;
bool cubic;
bool loop;
- bool rotate;
+ bool rotates;
void _update_transform();
@@ -99,7 +99,7 @@ public:
void set_loop(bool p_loop);
bool has_loop() const;
- void set_rotate(bool p_rotate);
+ void set_rotates(bool p_rotates);
bool is_rotating() const;
void set_cubic_interpolation(bool p_enable);
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index b1ffe76662..b1adb0e88e 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -505,11 +505,11 @@ bool Area3D::is_overriding_audio_bus() const {
return audio_bus_override;
}
-void Area3D::set_audio_bus(const StringName &p_audio_bus) {
+void Area3D::set_audio_bus_name(const StringName &p_audio_bus) {
audio_bus = p_audio_bus;
}
-StringName Area3D::get_audio_bus() const {
+StringName Area3D::get_audio_bus_name() const {
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) {
return audio_bus;
@@ -625,8 +625,8 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area3D::set_audio_bus_override);
ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area3D::is_overriding_audio_bus);
- ClassDB::bind_method(D_METHOD("set_audio_bus", "name"), &Area3D::set_audio_bus);
- ClassDB::bind_method(D_METHOD("get_audio_bus"), &Area3D::get_audio_bus);
+ ClassDB::bind_method(D_METHOD("set_audio_bus_name", "name"), &Area3D::set_audio_bus_name);
+ ClassDB::bind_method(D_METHOD("get_audio_bus_name"), &Area3D::get_audio_bus_name);
ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area3D::set_use_reverb_bus);
ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area3D::is_using_reverb_bus);
@@ -665,7 +665,7 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus", "get_audio_bus");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name");
ADD_GROUP("Reverb Bus", "reverb_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 7d1f030baf..51f6317517 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -190,8 +190,8 @@ public:
void set_audio_bus_override(bool p_override);
bool is_overriding_audio_bus() const;
- void set_audio_bus(const StringName &p_audio_bus);
- StringName get_audio_bus() const;
+ void set_audio_bus_name(const StringName &p_audio_bus);
+ StringName get_audio_bus_name() const;
void set_use_reverb_bus(bool p_enable);
bool is_using_reverb_bus() const;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index b093788d75..2907eb3c7e 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -327,9 +327,6 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
return att;
}
-void _update_sound() {
-}
-
void AudioStreamPlayer3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
velocity_tracker->reset(get_global_transform().origin);
@@ -487,7 +484,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (area) {
if (area->is_overriding_audio_bus()) {
//override audio bus
- StringName bus_name = area->get_audio_bus();
+ StringName bus_name = area->get_audio_bus_name();
output.bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
}
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 191159448a..178c5c8ff8 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -519,8 +519,8 @@ void Camera3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,8192,0.001,or_greater"), "set_znear", "get_znear");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_zfar", "get_zfar");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,10,0.001,or_greater"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4000,0.01,or_greater"), "set_zfar", "get_zfar");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
@@ -662,7 +662,7 @@ Camera3D::Camera3D() {
viewport = nullptr;
force_change = false;
mode = PROJECTION_PERSPECTIVE;
- set_perspective(75.0, 0.05, 100.0);
+ set_perspective(75.0, 0.05, 4000.0);
keep_aspect = KEEP_HEIGHT;
layers = 0xfffff;
v_offset = 0;
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index c977e0d4aa..215d9e062c 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -39,7 +39,7 @@ AABB CPUParticles3D::get_aabb() const {
return AABB();
}
-Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_flags) const {
+Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_particle_flags) const {
return Vector<Face3>();
}
@@ -368,17 +368,17 @@ Ref<Gradient> CPUParticles3D::get_color_ramp() const {
return color_ramp;
}
-void CPUParticles3D::set_particle_flag(Flags p_flag, bool p_enable) {
- ERR_FAIL_INDEX(p_flag, FLAG_MAX);
- flags[p_flag] = p_enable;
- if (p_flag == FLAG_DISABLE_Z) {
+void CPUParticles3D::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
+ ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX);
+ particle_flags[p_particle_flag] = p_enable;
+ if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) {
_change_notify();
}
}
-bool CPUParticles3D::get_particle_flag(Flags p_flag) const {
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags[p_flag];
+bool CPUParticles3D::get_particle_flag(ParticleFlags p_particle_flag) const {
+ ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false);
+ return particle_flags[p_particle_flag];
}
void CPUParticles3D::set_emission_shape(EmissionShape p_shape) {
@@ -459,7 +459,7 @@ void CPUParticles3D::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
+ if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
property.usage = 0;
}
}
@@ -675,7 +675,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.hue_rot_rand = Math::randf();
p.anim_offset_rand = Math::randf();
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
@@ -725,7 +725,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.transform.origin = emission_points.get(random_idx);
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
Vector3 normal = emission_normals.get(random_idx);
Vector2 normal_2d(normal.x, normal.y);
Transform2D m2;
@@ -762,7 +762,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.transform = emission_xform * p.transform;
}
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
p.velocity.z = 0.0;
p.transform.origin.z = 0.0;
}
@@ -783,7 +783,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
float tex_orbit_velocity = 0.0;
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]);
}
@@ -830,7 +830,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
Vector3 force = gravity;
Vector3 position = p.transform.origin;
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
position.z = 0.0;
}
//apply linear acceleration
@@ -840,7 +840,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
Vector3 diff = position - org;
force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3();
//apply tangential acceleration;
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
Vector2 yx = Vector2(diff.y, diff.x);
Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized();
force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
@@ -852,7 +852,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
//apply attractor forces
p.velocity += force * local_delta;
//orbit velocity
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
if (orbit_amount != 0.0) {
float ang = orbit_amount * local_delta * Math_PI * 2.0;
@@ -923,8 +923,8 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.color *= p.base_color;
- if (flags[FLAG_DISABLE_Z]) {
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
if (p.velocity.length() > 0.0) {
p.transform.basis.set_axis(1, p.velocity.normalized());
} else {
@@ -941,7 +941,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
} else {
//orient particle Y towards velocity
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
if (p.velocity.length() > 0.0) {
p.transform.basis.set_axis(1, p.velocity.normalized());
} else {
@@ -959,7 +959,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
//turn particle by rotation in Y
- if (flags[FLAG_ROTATE_Y]) {
+ if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) {
Basis rot_y(Vector3(0, 1, 0), p.custom[0]);
p.transform.basis = p.transform.basis * rot_y;
}
@@ -973,7 +973,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
p.transform.basis.scale(Vector3(1, 1, 1) * base_scale);
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
p.velocity.z = 0.0;
p.transform.origin.z = 0.0;
}
@@ -1199,9 +1199,9 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_color_ramp(gt->get_gradient());
}
- set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
- set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
- set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
+ set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ROTATE_Y));
+ set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
@@ -1318,8 +1318,8 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles3D::set_color_ramp);
ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles3D::get_color_ramp);
- ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles3D::set_particle_flag);
- ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles3D::get_particle_flag);
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &CPUParticles3D::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &CPUParticles3D::get_particle_flag);
ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles3D::set_emission_shape);
ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles3D::get_emission_shape);
@@ -1351,10 +1351,10 @@ void CPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
- ADD_GROUP("Flags", "flag_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_particle_flag", "get_particle_flag", FLAG_DISABLE_Z);
+ ADD_GROUP("Particle Flags", "particle_flag_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z);
ADD_GROUP("Direction", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
@@ -1426,10 +1426,10 @@ void CPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
BIND_ENUM_CONSTANT(PARAM_MAX);
- BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
- BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
- BIND_ENUM_CONSTANT(FLAG_DISABLE_Z);
- BIND_ENUM_CONSTANT(FLAG_MAX);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
@@ -1493,8 +1493,8 @@ CPUParticles3D::CPUParticles3D() {
set_param_randomness(Parameter(i), 0);
}
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
+ for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
+ particle_flags[i] = false;
}
can_update = false;
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index da4811b60e..8c1b8a684c 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -61,11 +61,11 @@ public:
PARAM_MAX
};
- enum Flags {
- FLAG_ALIGN_Y_TO_VELOCITY,
- FLAG_ROTATE_Y,
- FLAG_DISABLE_Z,
- FLAG_MAX
+ enum ParticleFlags {
+ PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY,
+ PARTICLE_FLAG_ROTATE_Y,
+ PARTICLE_FLAG_DISABLE_Z,
+ PARTICLE_FLAG_MAX
};
enum EmissionShape {
@@ -160,7 +160,7 @@ private:
Color color;
Ref<Gradient> color_ramp;
- bool flags[FLAG_MAX];
+ bool particle_flags[PARTICLE_FLAG_MAX];
EmissionShape emission_shape;
float emission_sphere_radius;
@@ -256,8 +256,8 @@ public:
void set_color_ramp(const Ref<Gradient> &p_ramp);
Ref<Gradient> get_color_ramp() const;
- void set_particle_flag(Flags p_flag, bool p_enable);
- bool get_particle_flag(Flags p_flag) const;
+ void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable);
+ bool get_particle_flag(ParticleFlags p_particle_flag) const;
void set_emission_shape(EmissionShape p_shape);
void set_emission_sphere_radius(float p_radius);
@@ -290,7 +290,7 @@ public:
VARIANT_ENUM_CAST(CPUParticles3D::DrawOrder)
VARIANT_ENUM_CAST(CPUParticles3D::Parameter)
-VARIANT_ENUM_CAST(CPUParticles3D::Flags)
+VARIANT_ENUM_CAST(CPUParticles3D::ParticleFlags)
VARIANT_ENUM_CAST(CPUParticles3D::EmissionShape)
#endif // CPU_PARTICLES_H
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 3d3467583d..2ae01c7ab8 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -182,6 +182,7 @@ void NavigationRegion3D::bake_navigation_mesh() {
void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
set_navigation_mesh(p_nav_mesh);
bake_thread = nullptr;
+ emit_signal("bake_finished");
}
String NavigationRegion3D::get_configuration_warning() const {
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index f25a64c567..ae6bbad8bf 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -94,10 +94,6 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
return;
}
- if (delta_offset == 0) {
- return;
- }
-
float bl = c->get_baked_length();
if (bl == 0.0) {
return;
@@ -156,7 +152,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
t.origin = pos;
- if (p_update_xyz_rot) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree
+ if (p_update_xyz_rot && delta_offset != 0) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree.
Vector3 t_prev = (pos - c->interpolate_baked(offset - delta_offset, cubic)).normalized();
Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized();
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp
index ab9cdb9fd8..06de5ad0ae 100644
--- a/scene/3d/physics_joint_3d.cpp
+++ b/scene/3d/physics_joint_3d.cpp
@@ -710,9 +710,6 @@ void Generic6DOFJoint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flag_z", "flag", "value"), &Generic6DOFJoint3D::set_flag_z);
ClassDB::bind_method(D_METHOD("get_flag_z", "flag"), &Generic6DOFJoint3D::get_flag_z);
- ClassDB::bind_method(D_METHOD("set_precision", "precision"), &Generic6DOFJoint3D::set_precision);
- ClassDB::bind_method(D_METHOD("get_precision"), &Generic6DOFJoint3D::get_precision);
-
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/upper_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_UPPER_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/lower_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_LOWER_LIMIT);
@@ -801,8 +798,6 @@ void Generic6DOFJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/damping"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "precision", PROPERTY_HINT_RANGE, "1,99999,1"), "set_precision", "get_precision");
-
BIND_ENUM_CONSTANT(PARAM_LINEAR_LOWER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_LINEAR_UPPER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
@@ -921,14 +916,6 @@ bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const {
return flags_z[p_flag];
}
-void Generic6DOFJoint3D::set_precision(int p_precision) {
- precision = p_precision;
-
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_precision(
- get_joint(),
- precision);
-}
-
RID Generic6DOFJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Transform gt = get_global_transform();
//Vector3 cone_twistpos = gt.origin;
diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h
index a65f6db3bf..250ae8bf52 100644
--- a/scene/3d/physics_joint_3d.h
+++ b/scene/3d/physics_joint_3d.h
@@ -300,8 +300,6 @@ protected:
float params_z[PARAM_MAX];
bool flags_z[FLAG_MAX];
- int precision = 1;
-
virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
@@ -324,11 +322,6 @@ public:
void set_flag_z(Flag p_flag, bool p_enabled);
bool get_flag_z(Flag p_flag) const;
- void set_precision(int p_precision);
- int get_precision() const {
- return precision;
- }
-
Generic6DOFJoint3D();
};
diff --git a/scene/3d/proximity_group_3d.cpp b/scene/3d/proximity_group_3d.cpp
index 1a0677c603..7e25255885 100644
--- a/scene/3d/proximity_group_3d.cpp
+++ b/scene/3d/proximity_group_3d.cpp
@@ -32,7 +32,7 @@
#include "core/math/math_funcs.h"
-void ProximityGroup3D::clear_groups() {
+void ProximityGroup3D::_clear_groups() {
Map<StringName, uint32_t>::Element *E;
{
@@ -43,21 +43,21 @@ void ProximityGroup3D::clear_groups() {
while (E && num < size) {
if (E->get() != group_version) {
remove_list[num++] = E->key();
- };
+ }
E = E->next();
- };
+ }
for (int i = 0; i < num; i++) {
groups.erase(remove_list[i]);
- };
- };
+ }
+ }
if (E) {
- clear_groups(); // call until we go through the whole list
- };
-};
+ _clear_groups(); // call until we go through the whole list
+ }
+}
-void ProximityGroup3D::update_groups() {
+void ProximityGroup3D::_update_groups() {
if (grid_radius == Vector3(0, 0, 0)) {
return;
}
@@ -68,20 +68,20 @@ void ProximityGroup3D::update_groups() {
Vector3 vcell = pos / cell_size;
int cell[3] = { Math::fast_ftoi(vcell.x), Math::fast_ftoi(vcell.y), Math::fast_ftoi(vcell.z) };
- add_groups(cell, group_name, 0);
+ _add_groups(cell, group_name, 0);
- clear_groups();
-};
+ _clear_groups();
+}
-void ProximityGroup3D::add_groups(int *p_cell, String p_base, int p_depth) {
+void ProximityGroup3D::_add_groups(int *p_cell, String p_base, int p_depth) {
p_base = p_base + "|";
if (grid_radius[p_depth] == 0) {
if (p_depth == 2) {
_new_group(p_base);
} else {
- add_groups(p_cell, p_base, p_depth + 1);
- };
- };
+ _add_groups(p_cell, p_base, p_depth + 1);
+ }
+ }
int start = p_cell[p_depth] - grid_radius[p_depth];
int end = p_cell[p_depth] + grid_radius[p_depth];
@@ -91,72 +91,72 @@ void ProximityGroup3D::add_groups(int *p_cell, String p_base, int p_depth) {
if (p_depth == 2) {
_new_group(gname);
} else {
- add_groups(p_cell, gname, p_depth + 1);
- };
- };
-};
+ _add_groups(p_cell, gname, p_depth + 1);
+ }
+ }
+}
void ProximityGroup3D::_new_group(StringName p_name) {
const Map<StringName, uint32_t>::Element *E = groups.find(p_name);
if (!E) {
add_to_group(p_name);
- };
+ }
groups[p_name] = group_version;
-};
+}
void ProximityGroup3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_EXIT_TREE:
++group_version;
- clear_groups();
+ _clear_groups();
break;
case NOTIFICATION_TRANSFORM_CHANGED:
- update_groups();
+ _update_groups();
break;
- };
-};
+ }
+}
-void ProximityGroup3D::broadcast(String p_name, Variant p_params) {
+void ProximityGroup3D::broadcast(String p_method, Variant p_parameters) {
Map<StringName, uint32_t>::Element *E;
E = groups.front();
while (E) {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params);
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_method, p_parameters);
E = E->next();
- };
-};
+ }
+}
-void ProximityGroup3D::_proximity_group_broadcast(String p_name, Variant p_params) {
+void ProximityGroup3D::_proximity_group_broadcast(String p_method, Variant p_parameters) {
if (dispatch_mode == MODE_PROXY) {
- get_parent()->call(p_name, p_params);
+ get_parent()->call(p_method, p_parameters);
} else {
- emit_signal("broadcast", p_name, p_params);
- };
-};
+ emit_signal("broadcast", p_method, p_parameters);
+ }
+}
void ProximityGroup3D::set_group_name(const String &p_group_name) {
group_name = p_group_name;
-};
+}
String ProximityGroup3D::get_group_name() const {
return group_name;
-};
+}
void ProximityGroup3D::set_dispatch_mode(DispatchMode p_mode) {
dispatch_mode = p_mode;
-};
+}
ProximityGroup3D::DispatchMode ProximityGroup3D::get_dispatch_mode() const {
return dispatch_mode;
-};
+}
void ProximityGroup3D::set_grid_radius(const Vector3 &p_radius) {
grid_radius = p_radius;
-};
+}
Vector3 ProximityGroup3D::get_grid_radius() const {
return grid_radius;
-};
+}
void ProximityGroup3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_group_name", "name"), &ProximityGroup3D::set_group_name);
@@ -165,19 +165,21 @@ void ProximityGroup3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_dispatch_mode"), &ProximityGroup3D::get_dispatch_mode);
ClassDB::bind_method(D_METHOD("set_grid_radius", "radius"), &ProximityGroup3D::set_grid_radius);
ClassDB::bind_method(D_METHOD("get_grid_radius"), &ProximityGroup3D::get_grid_radius);
- ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup3D::broadcast);
- ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup3D::_proximity_group_broadcast);
+
+ ClassDB::bind_method(D_METHOD("broadcast", "method", "parameters"), &ProximityGroup3D::broadcast);
+
+ ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "method", "parameters"), &ProximityGroup3D::_proximity_group_broadcast);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "group_name"), "set_group_name", "get_group_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "dispatch_mode", PROPERTY_HINT_ENUM, "Proxy,Signal"), "set_dispatch_mode", "get_dispatch_mode");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "grid_radius"), "set_grid_radius", "get_grid_radius");
- ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "group_name"), PropertyInfo(Variant::ARRAY, "parameters")));
+ ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "method"), PropertyInfo(Variant::ARRAY, "parameters")));
BIND_ENUM_CONSTANT(MODE_PROXY);
BIND_ENUM_CONSTANT(MODE_SIGNAL);
-};
+}
ProximityGroup3D::ProximityGroup3D() {
set_notify_transform(true);
-};
+}
diff --git a/scene/3d/proximity_group_3d.h b/scene/3d/proximity_group_3d.h
index dd3a2f0a87..d52843e9a2 100644
--- a/scene/3d/proximity_group_3d.h
+++ b/scene/3d/proximity_group_3d.h
@@ -35,7 +35,6 @@
class ProximityGroup3D : public Node3D {
GDCLASS(ProximityGroup3D, Node3D);
- OBJ_CATEGORY("3D");
public:
enum DispatchMode {
@@ -43,25 +42,25 @@ public:
MODE_SIGNAL,
};
-public:
- void clear_groups();
- void update_groups();
-
- void _notification(int p_what);
-
- DispatchMode dispatch_mode = MODE_PROXY;
-
+private:
Map<StringName, uint32_t> groups;
+
String group_name;
+ DispatchMode dispatch_mode = MODE_PROXY;
+ Vector3 grid_radius = Vector3(1, 1, 1);
float cell_size = 1.0;
- Vector3 grid_radius = Vector3(1, 1, 1);
uint32_t group_version = 0;
- void add_groups(int *p_cell, String p_base, int p_depth);
+ void _clear_groups();
+ void _update_groups();
+ void _add_groups(int *p_cell, String p_base, int p_depth);
void _new_group(StringName p_name);
- void _proximity_group_broadcast(String p_name, Variant p_params);
+ void _proximity_group_broadcast(String p_method, Variant p_parameters);
+
+protected:
+ void _notification(int p_what);
static void _bind_methods();
@@ -75,7 +74,7 @@ public:
void set_grid_radius(const Vector3 &p_radius);
Vector3 get_grid_radius() const;
- void broadcast(String p_name, Variant p_params);
+ void broadcast(String p_method, Variant p_parameters);
ProximityGroup3D();
~ProximityGroup3D() {}
@@ -83,4 +82,4 @@ public:
VARIANT_ENUM_CAST(ProximityGroup3D::DispatchMode);
-#endif
+#endif // PROXIMITY_GROUP_H
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index c7948395d3..c82ed423a7 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -76,6 +76,15 @@ float ReflectionProbe::get_max_distance() const {
return max_distance;
}
+void ReflectionProbe::set_lod_threshold(float p_pixels) {
+ lod_threshold = p_pixels;
+ RS::get_singleton()->reflection_probe_set_lod_threshold(probe, p_pixels);
+}
+
+float ReflectionProbe::get_lod_threshold() const {
+ return lod_threshold;
+}
+
void ReflectionProbe::set_extents(const Vector3 &p_extents) {
extents = p_extents;
@@ -199,6 +208,9 @@ void ReflectionProbe::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_distance", "max_distance"), &ReflectionProbe::set_max_distance);
ClassDB::bind_method(D_METHOD("get_max_distance"), &ReflectionProbe::get_max_distance);
+ ClassDB::bind_method(D_METHOD("set_lod_threshold", "ratio"), &ReflectionProbe::set_lod_threshold);
+ ClassDB::bind_method(D_METHOD("get_lod_threshold"), &ReflectionProbe::get_lod_threshold);
+
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &ReflectionProbe::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &ReflectionProbe::get_extents);
@@ -229,6 +241,7 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_as_interior", "is_set_as_interior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_shadows"), "set_enable_shadows", "are_shadows_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_GROUP("Ambient", "ambient_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ambient_mode", PROPERTY_HINT_ENUM, "Disabled,Environment,ConstantColor"), "set_ambient_mode", "get_ambient_mode");
@@ -256,6 +269,7 @@ ReflectionProbe::ReflectionProbe() {
enable_shadows = false;
cull_mask = (1 << 20) - 1;
update_mode = UPDATE_ONCE;
+ lod_threshold = 1.0;
probe = RenderingServer::get_singleton()->reflection_probe_create();
RS::get_singleton()->instance_set_base(get_instance(), probe);
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index 56177d0f95..4bff2f8bf9 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -63,6 +63,7 @@ private:
AmbientMode ambient_mode;
Color ambient_color;
float ambient_color_energy;
+ float lod_threshold;
uint32_t cull_mask;
UpdateMode update_mode;
@@ -90,6 +91,9 @@ public:
void set_max_distance(float p_distance);
float get_max_distance() const;
+ void set_lod_threshold(float p_pixels);
+ float get_lod_threshold() const;
+
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 0ae1c0e3b6..4425af26f9 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -848,7 +848,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
skin_bindings.insert(skin_ref.operator->());
- skin->connect_compat("changed", skin_ref.operator->(), "_skin_changed");
+ skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed"));
_make_dirty(); //skin needs to be updated, so update skeleton
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index 80acc3e937..6c1db6dd33 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -76,10 +76,6 @@ class FabrikInverseKinematic {
ChainTip(ChainItem *p_chain_item, const EndEffector *p_end_effector) :
chain_item(p_chain_item),
end_effector(p_end_effector) {}
-
- ChainTip(const ChainTip &p_other_ct) :
- chain_item(p_other_ct.chain_item),
- end_effector(p_other_ct.end_effector) {}
};
struct Chain {
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index e633b1eb4a..d811b2e852 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -480,7 +480,6 @@ void SoftBody3D::become_mesh_owner() {
Dictionary surface_lods = mesh->surface_get_lods(0);
uint32_t surface_format = mesh->surface_get_format(0);
- surface_format &= ~(Mesh::ARRAY_COMPRESS_NORMAL);
surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
Ref<ArrayMesh> soft_mesh;
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index b6999beff4..1d20a9cd3b 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -486,7 +486,7 @@ void Sprite3D::_draw() {
RS::get_singleton()->immediate_normal(immediate, normal);
RS::get_singleton()->immediate_tangent(immediate, tangent);
RS::get_singleton()->immediate_color(immediate, color);
- RS::get_singleton()->immediate_uv(immediate, uvs[i]);
+ RS::get_singleton()->immediate_uv(immediate, uvs[index[i]]);
Vector3 vtx;
vtx[x_axis] = vertices[index[i]][0];
@@ -815,7 +815,7 @@ void AnimatedSprite3D::_draw() {
RS::get_singleton()->immediate_normal(immediate, normal);
RS::get_singleton()->immediate_tangent(immediate, tangent);
RS::get_singleton()->immediate_color(immediate, color);
- RS::get_singleton()->immediate_uv(immediate, uvs[i]);
+ RS::get_singleton()->immediate_uv(immediate, uvs[indices[i]]);
Vector3 vtx;
vtx[x_axis] = vertices[indices[i]][0];
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index a1c498e8ab..0b70b0f920 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -278,6 +278,16 @@ float GeometryInstance3D::get_extra_cull_margin() const {
return extra_cull_margin;
}
+void GeometryInstance3D::set_lod_bias(float p_bias) {
+ ERR_FAIL_COND(p_bias < 0.0);
+ lod_bias = p_bias;
+ RS::get_singleton()->instance_geometry_set_lod_bias(get_instance(), lod_bias);
+}
+
+float GeometryInstance3D::get_lod_bias() const {
+ return lod_bias;
+}
+
void GeometryInstance3D::set_shader_instance_uniform(const StringName &p_uniform, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), p_uniform);
@@ -361,6 +371,9 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_gi_mode", "mode"), &GeometryInstance3D::set_gi_mode);
ClassDB::bind_method(D_METHOD("get_gi_mode"), &GeometryInstance3D::get_gi_mode);
+ ClassDB::bind_method(D_METHOD("set_lod_bias", "p_bias"), &GeometryInstance3D::set_lod_bias);
+ ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
+
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb);
ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance3D::get_aabb);
@@ -369,6 +382,7 @@ void GeometryInstance3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias");
ADD_GROUP("Global Illumination", "gi_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Baked,Dynamic"), "set_gi_mode", "get_gi_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale");
@@ -403,6 +417,8 @@ GeometryInstance3D::GeometryInstance3D() {
lod_min_hysteresis = 0;
lod_max_hysteresis = 0;
+ lod_bias = 1.0;
+
gi_mode = GI_MODE_DISABLED;
lightmap_scale = LIGHTMAP_SCALE_1X;
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 51bcb411da..0810b7b4ce 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -112,6 +112,8 @@ private:
float lod_min_hysteresis;
float lod_max_hysteresis;
+ float lod_bias;
+
mutable HashMap<StringName, Variant> instance_uniforms;
mutable HashMap<StringName, StringName> instance_uniform_property_remap;
@@ -151,6 +153,9 @@ public:
void set_extra_cull_margin(float p_margin);
float get_extra_cull_margin() const;
+ void set_lod_bias(float p_bias);
+ float get_lod_bias() const;
+
void set_gi_mode(GIMode p_mode);
GIMode get_gi_mode() const;
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index c0015aa338..763461880f 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -211,7 +211,7 @@ void XRController3D::_notification(int p_what) {
emit_signal("button_pressed", i);
button_states += mask;
} else if (was_pressed && !is_pressed) {
- emit_signal("button_release", i);
+ emit_signal("button_released", i);
button_states -= mask;
};
@@ -257,7 +257,7 @@ void XRController3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh"), &XRController3D::get_mesh);
ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button")));
- ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button")));
+ ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::INT, "button")));
ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
};
@@ -282,7 +282,7 @@ String XRController3D::get_controller_name() const {
return String("Not connected");
};
- return tracker->get_name();
+ return tracker->get_tracker_name();
};
int XRController3D::get_joystick_id() const {
@@ -480,7 +480,7 @@ String XRAnchor3D::get_anchor_name() const {
return String("Not connected");
};
- return tracker->get_name();
+ return tracker->get_tracker_name();
};
bool XRAnchor3D::get_is_active() const {
diff --git a/scene/SCsub b/scene/SCsub
index f9fc00f3f2..ccd2bab8ff 100644
--- a/scene/SCsub
+++ b/scene/SCsub
@@ -4,24 +4,9 @@ Import("env")
env.scene_sources = []
-# Thirdparty code
-thirdparty_dir = "#thirdparty/misc/"
-thirdparty_sources = [
- # C++ sources
- "easing_equations.cpp",
- # C sources
- "mikktspace.c",
-]
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-env_thirdparty = env.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.scene_sources, thirdparty_sources)
-
-# Godot's own sources
+# Godot source files
env.add_source_files(env.scene_sources, "*.cpp")
-
# Chain load SCsubs
SConscript("main/SCsub")
SConscript("gui/SCsub")
@@ -32,7 +17,6 @@ SConscript("audio/SCsub")
SConscript("resources/SCsub")
SConscript("debugger/SCsub")
-
# Build it all as a library
lib = env.add_library("scene", env.scene_sources)
env.Prepend(LIBS=[lib])
diff --git a/scene/animation/SCsub b/scene/animation/SCsub
index fc61250247..cc33a5af84 100644
--- a/scene/animation/SCsub
+++ b/scene/animation/SCsub
@@ -2,4 +2,23 @@
Import("env")
-env.add_source_files(env.scene_sources, "*.cpp")
+# Thirdparty code
+
+thirdparty_obj = []
+
+thirdparty_sources = "#thirdparty/misc/easing_equations.cpp"
+
+env_thirdparty = env.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.scene_sources += thirdparty_obj
+
+# Godot source files
+
+scene_obj = []
+
+env.add_source_files(scene_obj, "*.cpp")
+env.scene_sources += scene_obj
+
+# Needed to force rebuilding the scene files when the thirdparty code is updated.
+env.Depends(scene_obj, thirdparty_obj)
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 17ce05f130..36552c966d 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -565,7 +565,7 @@ void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<Anima
{
Ref<AnimationNode> node = states[p_name].node;
if (node.is_valid()) {
- node->disconnect_compat("tree_changed", this, "_tree_changed");
+ node->disconnect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed));
}
}
@@ -574,7 +574,7 @@ void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<Anima
emit_changed();
emit_signal("tree_changed");
- p_node->connect_compat("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+ p_node->connect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const {
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index f8a67d154b..6ebd1011e9 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -615,7 +615,7 @@ void ColorPicker::_screen_pick_pressed() {
screen->set_default_cursor_shape(CURSOR_POINTING_HAND);
screen->connect("gui_input", callable_mp(this, &ColorPicker::_screen_input));
// It immediately toggles off in the first press otherwise.
- screen->call_deferred("connect", "hide", Callable(btn_pick, "set_pressed"), varray(false));
+ screen->call_deferred("connect", "hidden", Callable(btn_pick, "set_pressed"), varray(false));
}
screen->raise();
#ifndef _MSC_VER
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 46c3a44e98..bdbb0d4684 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -223,13 +223,6 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) {
}
data.icon_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
- } else if (name.begins_with("custom_shaders/")) {
- String dname = name.get_slicec('/', 1);
- if (data.shader_override.has(dname)) {
- data.shader_override[dname]->disconnect("changed", callable_mp(this, &Control::_override_changed));
- }
- data.shader_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
} else if (name.begins_with("custom_styles/")) {
String dname = name.get_slicec('/', 1);
if (data.style_override.has(dname)) {
@@ -264,9 +257,6 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) {
if (name.begins_with("custom_icons/")) {
String dname = name.get_slicec('/', 1);
add_theme_icon_override(dname, p_value);
- } else if (name.begins_with("custom_shaders/")) {
- String dname = name.get_slicec('/', 1);
- add_theme_shader_override(dname, p_value);
} else if (name.begins_with("custom_styles/")) {
String dname = name.get_slicec('/', 1);
add_theme_style_override(dname, p_value);
@@ -318,9 +308,6 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const {
if (sname.begins_with("custom_icons/")) {
String name = sname.get_slicec('/', 1);
r_ret = data.icon_override.has(name) ? Variant(data.icon_override[name]) : Variant();
- } else if (sname.begins_with("custom_shaders/")) {
- String name = sname.get_slicec('/', 1);
- r_ret = data.shader_override.has(name) ? Variant(data.shader_override[name]) : Variant();
} else if (sname.begins_with("custom_styles/")) {
String name = sname.get_slicec('/', 1);
r_ret = data.style_override.has(name) ? Variant(data.style_override[name]) : Variant();
@@ -368,18 +355,6 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
}
{
List<StringName> names;
- theme->get_shader_list(get_class_name(), &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
- if (data.shader_override.has(E->get())) {
- hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
- }
-
- p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_shaders/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "Shader,VisualShader", hint));
- }
- }
- {
- List<StringName> names;
theme->get_stylebox_list(get_class_name(), &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
@@ -481,10 +456,6 @@ bool Control::is_layout_rtl() const {
}
}
-void Control::_resize(const Size2 &p_size) {
- _size_changed();
-}
-
//moved theme configuration here, so controls can set up even if still not inside active scene
void Control::add_child_notify(Node *p_child) {
@@ -901,35 +872,6 @@ Ref<Texture2D> Control::get_icons(Control *p_theme_owner, Window *p_theme_owner_
return Theme::get_default()->get_icon(p_name, p_node_type);
}
-Ref<Shader> Control::get_theme_shader(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
- const Ref<Shader> *sdr = data.shader_override.getptr(p_name);
- if (sdr) {
- return *sdr;
- }
- }
-
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return get_shaders(data.theme_owner, data.theme_owner_window, p_name, type);
-}
-
-Ref<Shader> Control::get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- Ref<Shader> shader;
-
- if (_find_theme_item(p_theme_owner, p_theme_owner_window, shader, &Theme::get_shader, &Theme::has_shader, p_name, p_node_type)) {
- return shader;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_shader(p_name, p_node_type)) {
- return Theme::get_project_default()->get_shader(p_name, p_node_type);
- }
- }
-
- return Theme::get_default()->get_shader(p_name, p_node_type);
-}
-
Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_node_type) const {
if (p_node_type == StringName() || p_node_type == get_class_name()) {
const Ref<StyleBox> *style = data.style_override.getptr(p_name);
@@ -1078,11 +1020,6 @@ bool Control::has_theme_icon_override(const StringName &p_name) const {
return tex != nullptr;
}
-bool Control::has_theme_shader_override(const StringName &p_name) const {
- const Ref<Shader> *sdr = data.shader_override.getptr(p_name);
- return sdr != nullptr;
-}
-
bool Control::has_theme_stylebox_override(const StringName &p_name) const {
const Ref<StyleBox> *style = data.style_override.getptr(p_name);
return style != nullptr;
@@ -1133,31 +1070,6 @@ bool Control::has_icons(Control *p_theme_owner, Window *p_theme_owner_window, co
return Theme::get_default()->has_icon(p_name, p_node_type);
}
-bool Control::has_theme_shader(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
- if (has_theme_shader_override(p_name)) {
- return true;
- }
- }
-
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return has_shaders(data.theme_owner, data.theme_owner_window, p_name, type);
-}
-
-bool Control::has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_shader, p_name, p_node_type)) {
- return true;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_shader(p_name, p_node_type)) {
- return true;
- }
- }
- return Theme::get_default()->has_shader(p_name, p_node_type);
-}
-
bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_node_type) const {
if (p_node_type == StringName() || p_node_type == get_class_name()) {
if (has_theme_stylebox_override(p_name)) {
@@ -1891,23 +1803,6 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur
notification(NOTIFICATION_THEME_CHANGED);
}
-void Control::add_theme_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) {
- if (data.shader_override.has(p_name)) {
- data.shader_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
- }
-
- // clear if "null" is passed instead of a shader
- if (p_shader.is_null()) {
- data.shader_override.erase(p_name);
- } else {
- data.shader_override[p_name] = p_shader;
- if (data.shader_override[p_name].is_valid()) {
- data.shader_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
- }
- }
- notification(NOTIFICATION_THEME_CHANGED);
-}
-
void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
if (data.style_override.has(p_name)) {
data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
@@ -2311,14 +2206,14 @@ String Control::_get_tooltip() const {
return data.tooltip;
}
-void Control::set_focus_neighbour(Margin p_margin, const NodePath &p_neighbour) {
+void Control::set_focus_neighbor(Margin p_margin, const NodePath &p_neighbor) {
ERR_FAIL_INDEX((int)p_margin, 4);
- data.focus_neighbour[p_margin] = p_neighbour;
+ data.focus_neighbor[p_margin] = p_neighbor;
}
-NodePath Control::get_focus_neighbour(Margin p_margin) const {
+NodePath Control::get_focus_neighbor(Margin p_margin) const {
ERR_FAIL_INDEX_V((int)p_margin, 4, NodePath());
- return data.focus_neighbour[p_margin];
+ return data.focus_neighbor[p_margin];
}
void Control::set_focus_next(const NodePath &p_next) {
@@ -2337,17 +2232,17 @@ NodePath Control::get_focus_previous() const {
return data.focus_prev;
}
-#define MAX_NEIGHBOUR_SEARCH_COUNT 512
+#define MAX_NEIGHBOR_SEARCH_COUNT 512
-Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
+Control *Control::_get_focus_neighbor(Margin p_margin, int p_count) {
ERR_FAIL_INDEX_V((int)p_margin, 4, nullptr);
- if (p_count >= MAX_NEIGHBOUR_SEARCH_COUNT) {
+ if (p_count >= MAX_NEIGHBOR_SEARCH_COUNT) {
return nullptr;
}
- if (!data.focus_neighbour[p_margin].is_empty()) {
+ if (!data.focus_neighbor[p_margin].is_empty()) {
Control *c = nullptr;
- Node *n = get_node(data.focus_neighbour[p_margin]);
+ Node *n = get_node(data.focus_neighbor[p_margin]);
if (n) {
c = Object::cast_to<Control>(n);
ERR_FAIL_COND_V_MSG(!c, nullptr, "Neighbor focus node is not a control: " + n->get_name() + ".");
@@ -2365,7 +2260,7 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
return c;
}
- c = c->_get_focus_neighbour(p_margin, p_count + 1);
+ c = c->_get_focus_neighbor(p_margin, p_count + 1);
return c;
}
@@ -2415,12 +2310,12 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
return nullptr;
}
- _window_find_focus_neighbour(vdir, base, points, maxd, dist, &result);
+ _window_find_focus_neighbor(vdir, base, points, maxd, dist, &result);
return result;
}
-void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest) {
+void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest) {
if (Object::cast_to<Viewport>(p_at)) {
return; //bye
}
@@ -2473,7 +2368,7 @@ void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, con
if (childc && childc->data.RI) {
continue; //subwindow, ignore
}
- _window_find_focus_neighbour(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest);
+ _window_find_focus_neighbor(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest);
}
}
@@ -2905,7 +2800,6 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_theme"), &Control::get_theme);
ClassDB::bind_method(D_METHOD("add_theme_icon_override", "name", "texture"), &Control::add_theme_icon_override);
- ClassDB::bind_method(D_METHOD("add_theme_shader_override", "name", "shader"), &Control::add_theme_shader_override);
ClassDB::bind_method(D_METHOD("add_theme_stylebox_override", "name", "stylebox"), &Control::add_theme_style_override);
ClassDB::bind_method(D_METHOD("add_theme_font_override", "name", "font"), &Control::add_theme_font_override);
ClassDB::bind_method(D_METHOD("add_theme_font_size_override", "name", "font_size"), &Control::add_theme_font_size_override);
@@ -2920,7 +2814,6 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "node_type"), &Control::get_theme_constant, DEFVAL(""));
ClassDB::bind_method(D_METHOD("has_theme_icon_override", "name"), &Control::has_theme_icon_override);
- ClassDB::bind_method(D_METHOD("has_theme_shader_override", "name"), &Control::has_theme_shader_override);
ClassDB::bind_method(D_METHOD("has_theme_stylebox_override", "name"), &Control::has_theme_stylebox_override);
ClassDB::bind_method(D_METHOD("has_theme_font_override", "name"), &Control::has_theme_font_override);
ClassDB::bind_method(D_METHOD("has_theme_font_size_override", "name"), &Control::has_theme_font_size_override);
@@ -2950,8 +2843,8 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_default_cursor_shape"), &Control::get_default_cursor_shape);
ClassDB::bind_method(D_METHOD("get_cursor_shape", "position"), &Control::get_cursor_shape, DEFVAL(Point2()));
- ClassDB::bind_method(D_METHOD("set_focus_neighbour", "margin", "neighbour"), &Control::set_focus_neighbour);
- ClassDB::bind_method(D_METHOD("get_focus_neighbour", "margin"), &Control::get_focus_neighbour);
+ ClassDB::bind_method(D_METHOD("set_focus_neighbor", "margin", "neighbor"), &Control::set_focus_neighbor);
+ ClassDB::bind_method(D_METHOD("get_focus_neighbor", "margin"), &Control::get_focus_neighbor);
ClassDB::bind_method(D_METHOD("set_focus_next", "next"), &Control::set_focus_next);
ClassDB::bind_method(D_METHOD("get_focus_next"), &Control::get_focus_next);
@@ -2983,7 +2876,6 @@ void Control::_bind_methods() {
BIND_VMETHOD(MethodInfo("_structured_text_parser", PropertyInfo(Variant::ARRAY, "args"), PropertyInfo(Variant::STRING, "text")));
BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size"));
MethodInfo get_drag_data = MethodInfo("get_drag_data", PropertyInfo(Variant::VECTOR2, "position"));
@@ -3030,10 +2922,10 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
ADD_GROUP("Focus", "focus_");
- ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_BOTTOM);
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_next", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_next", "get_focus_next");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_previous", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_previous", "get_focus_previous");
ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
diff --git a/scene/gui/control.h b/scene/gui/control.h
index e1f05dfe64..d314c7357b 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -207,12 +207,11 @@ private:
CanvasItem *parent_canvas_item;
- NodePath focus_neighbour[4];
+ NodePath focus_neighbor[4];
NodePath focus_next;
NodePath focus_prev;
HashMap<StringName, Ref<Texture2D>> icon_override;
- HashMap<StringName, Ref<Shader>> shader_override;
HashMap<StringName, Ref<StyleBox>> style_override;
HashMap<StringName, Ref<Font>> font_override;
HashMap<StringName, int> font_size_override;
@@ -224,8 +223,8 @@ private:
// used internally
Control *_find_control_at_pos(CanvasItem *p_node, const Point2 &p_pos, const Transform2D &p_xform, Transform2D &r_inv_xform);
- void _window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest);
- Control *_get_focus_neighbour(Margin p_margin, int p_count = 0);
+ void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest);
+ Control *_get_focus_neighbor(Margin p_margin, int p_count = 0);
void _set_anchor(Margin p_margin, float p_anchor);
void _set_position(const Point2 &p_point);
@@ -238,7 +237,6 @@ private:
void _update_minimum_size();
void _update_scroll();
- void _resize(const Size2 &p_size);
void _compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]);
void _compute_anchors(Rect2 p_rect, const float p_margins[4], float (&r_anchors)[4]);
@@ -264,7 +262,6 @@ private:
_FORCE_INLINE_ static bool _has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_node_type);
static Ref<Texture2D> get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static Ref<Shader> get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
static Ref<StyleBox> get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
static Ref<Font> get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
static int get_font_sizes(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
@@ -272,7 +269,6 @@ private:
static int get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
static bool has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static bool has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
static bool has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
static bool has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
static bool has_font_sizes(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
@@ -440,8 +436,8 @@ public:
Control *find_next_valid_focus() const;
Control *find_prev_valid_focus() const;
- void set_focus_neighbour(Margin p_margin, const NodePath &p_neighbour);
- NodePath get_focus_neighbour(Margin p_margin) const;
+ void set_focus_neighbor(Margin p_margin, const NodePath &p_neighbor);
+ NodePath get_focus_neighbor(Margin p_margin) const;
void set_focus_next(const NodePath &p_next);
NodePath get_focus_next() const;
@@ -456,7 +452,6 @@ public:
/* SKINNING */
void add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon);
- void add_theme_shader_override(const StringName &p_name, const Ref<Shader> &p_shader);
void add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style);
void add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font);
void add_theme_font_size_override(const StringName &p_name, int p_font_size);
@@ -464,7 +459,6 @@ public:
void add_theme_constant_override(const StringName &p_name, int p_constant);
Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_node_type = StringName()) const;
Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const;
Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const;
int get_theme_font_size(const StringName &p_name, const StringName &p_node_type = StringName()) const;
@@ -472,7 +466,6 @@ public:
int get_theme_constant(const StringName &p_name, const StringName &p_node_type = StringName()) const;
bool has_theme_icon_override(const StringName &p_name) const;
- bool has_theme_shader_override(const StringName &p_name) const;
bool has_theme_stylebox_override(const StringName &p_name) const;
bool has_theme_font_override(const StringName &p_name) const;
bool has_theme_font_size_override(const StringName &p_name) const;
@@ -480,7 +473,6 @@ public:
bool has_theme_constant_override(const StringName &p_name) const;
bool has_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- bool has_theme_shader(const StringName &p_name, const StringName &p_node_type = StringName()) const;
bool has_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const;
bool has_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const;
bool has_theme_font_size(const StringName &p_name, const StringName &p_node_type = StringName()) const;
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 4f59f4a36a..4e80498108 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -60,7 +60,7 @@ void AcceptDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
- get_ok()->grab_focus();
+ get_ok_button()->grab_focus();
_update_child_rects();
parent_visible = get_parent_visible_window();
if (parent_visible) {
@@ -253,7 +253,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin
return button;
}
-Button *AcceptDialog::add_cancel(const String &p_cancel) {
+Button *AcceptDialog::add_cancel_button(const String &p_cancel) {
String c = p_cancel;
if (p_cancel == "") {
c = RTR("Cancel");
@@ -264,12 +264,12 @@ Button *AcceptDialog::add_cancel(const String &p_cancel) {
}
void AcceptDialog::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_ok"), &AcceptDialog::get_ok);
+ ClassDB::bind_method(D_METHOD("get_ok_button"), &AcceptDialog::get_ok_button);
ClassDB::bind_method(D_METHOD("get_label"), &AcceptDialog::get_label);
ClassDB::bind_method(D_METHOD("set_hide_on_ok", "enabled"), &AcceptDialog::set_hide_on_ok);
ClassDB::bind_method(D_METHOD("get_hide_on_ok"), &AcceptDialog::get_hide_on_ok);
ClassDB::bind_method(D_METHOD("add_button", "text", "right", "action"), &AcceptDialog::add_button, DEFVAL(false), DEFVAL(""));
- ClassDB::bind_method(D_METHOD("add_cancel", "name"), &AcceptDialog::add_cancel);
+ ClassDB::bind_method(D_METHOD("add_cancel_button", "name"), &AcceptDialog::add_cancel_button);
ClassDB::bind_method(D_METHOD("register_text_enter", "line_edit"), &AcceptDialog::register_text_enter);
ClassDB::bind_method(D_METHOD("set_text", "text"), &AcceptDialog::set_text);
ClassDB::bind_method(D_METHOD("get_text"), &AcceptDialog::get_text);
@@ -337,10 +337,10 @@ AcceptDialog::~AcceptDialog() {
// ConfirmationDialog
void ConfirmationDialog::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_cancel"), &ConfirmationDialog::get_cancel);
+ ClassDB::bind_method(D_METHOD("get_cancel_button"), &ConfirmationDialog::get_cancel_button);
}
-Button *ConfirmationDialog::get_cancel() {
+Button *ConfirmationDialog::get_cancel_button() {
return cancel;
}
@@ -349,5 +349,5 @@ ConfirmationDialog::ConfirmationDialog() {
#ifdef TOOLS_ENABLED
set_min_size(Size2(200, 70) * EDSCALE);
#endif
- cancel = add_cancel();
+ cancel = add_cancel_button();
}
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index de08685ce2..8f6e0e86f9 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -79,9 +79,9 @@ public:
void register_text_enter(Node *p_line_edit);
- Button *get_ok() { return ok; }
+ Button *get_ok_button() { return ok; }
Button *add_button(const String &p_text, bool p_right = false, const String &p_action = "");
- Button *add_cancel(const String &p_cancel = "");
+ Button *add_cancel_button(const String &p_cancel = "");
void set_hide_on_ok(bool p_hide);
bool get_hide_on_ok() const;
@@ -104,7 +104,7 @@ protected:
static void _bind_methods();
public:
- Button *get_cancel();
+ Button *get_cancel_button();
ConfirmationDialog();
};
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index eb3d5d5c6d..041b8ef174 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -324,15 +324,15 @@ void FileDialog::deselect_items() {
// And change get_ok title.
if (!tree->is_anything_selected()) {
- get_ok()->set_disabled(_is_open_should_be_disabled());
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
switch (mode) {
case FILE_MODE_OPEN_FILE:
case FILE_MODE_OPEN_FILES:
- get_ok()->set_text(RTR("Open"));
+ get_ok_button()->set_text(RTR("Open"));
break;
case FILE_MODE_OPEN_DIR:
- get_ok()->set_text(RTR("Select Current Folder"));
+ get_ok_button()->set_text(RTR("Select Current Folder"));
break;
case FILE_MODE_OPEN_ANY:
case FILE_MODE_SAVE_FILE:
@@ -356,10 +356,10 @@ void FileDialog::_tree_selected() {
if (!d["dir"]) {
file->set_text(d["name"]);
} else if (mode == FILE_MODE_OPEN_DIR) {
- get_ok()->set_text(RTR("Select This Folder"));
+ get_ok_button()->set_text(RTR("Select This Folder"));
}
- get_ok()->set_disabled(_is_open_should_be_disabled());
+ get_ok_button()->set_disabled(_is_open_should_be_disabled());
}
void FileDialog::_tree_item_activated() {
@@ -646,35 +646,35 @@ void FileDialog::set_file_mode(FileMode p_mode) {
mode = p_mode;
switch (mode) {
case FILE_MODE_OPEN_FILE:
- get_ok()->set_text(RTR("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(RTR("Open a File"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_FILES:
- get_ok()->set_text(RTR("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(RTR("Open File(s)"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_DIR:
- get_ok()->set_text(RTR("Select Current Folder"));
+ get_ok_button()->set_text(RTR("Select Current Folder"));
if (mode_overrides_title) {
set_title(RTR("Open a Directory"));
}
makedir->show();
break;
case FILE_MODE_OPEN_ANY:
- get_ok()->set_text(RTR("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(RTR("Open a File or Directory"));
}
makedir->show();
break;
case FILE_MODE_SAVE_FILE:
- get_ok()->set_text(RTR("Save"));
+ get_ok_button()->set_text(RTR("Save"));
if (mode_overrides_title) {
set_title(RTR("Save a File"));
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 96810e8707..2bcc1890fe 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -31,6 +31,7 @@
#include "graph_edit.h"
#include "core/input/input.h"
+#include "core/math/math_funcs.h"
#include "core/os/keyboard.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
@@ -44,6 +45,9 @@
#define MIN_ZOOM (((1 / ZOOM_SCALE) / ZOOM_SCALE) / ZOOM_SCALE)
#define MAX_ZOOM (1 * ZOOM_SCALE * ZOOM_SCALE * ZOOM_SCALE)
+#define MINIMAP_OFFSET 12
+#define MINIMAP_PADDING 5
+
bool GraphEditFilter::has_point(const Point2 &p_point) const {
return ge->_filter_input(p_point);
}
@@ -52,6 +56,141 @@ GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) {
ge = p_edit;
}
+void GraphEditMinimap::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_gui_input"), &GraphEditMinimap::_gui_input);
+}
+
+GraphEditMinimap::GraphEditMinimap(GraphEdit *p_edit) {
+ ge = p_edit;
+
+ graph_proportions = Vector2(1, 1);
+ graph_padding = Vector2(0, 0);
+ camera_position = Vector2(100, 50);
+ camera_size = Vector2(200, 200);
+ minimap_padding = Vector2(MINIMAP_PADDING, MINIMAP_PADDING);
+ minimap_offset = minimap_padding + _convert_from_graph_position(graph_padding);
+
+ is_pressing = false;
+ is_resizing = false;
+}
+
+void GraphEditMinimap::update_minimap() {
+ Vector2 graph_offset = _get_graph_offset();
+ Vector2 graph_size = _get_graph_size();
+
+ camera_position = ge->get_scroll_ofs() - graph_offset;
+ camera_size = ge->get_size();
+
+ Vector2 render_size = _get_render_size();
+ float target_ratio = render_size.x / render_size.y;
+ float graph_ratio = graph_size.x / graph_size.y;
+
+ graph_proportions = graph_size;
+ graph_padding = Vector2(0, 0);
+ if (graph_ratio > target_ratio) {
+ graph_proportions.x = graph_size.x;
+ graph_proportions.y = graph_size.x / target_ratio;
+ graph_padding.y = Math::abs(graph_size.y - graph_proportions.y) / 2;
+ } else {
+ graph_proportions.x = graph_size.y * target_ratio;
+ graph_proportions.y = graph_size.y;
+ graph_padding.x = Math::abs(graph_size.x - graph_proportions.x) / 2;
+ }
+
+ // This centers minimap inside the minimap rectangle.
+ minimap_offset = minimap_padding + _convert_from_graph_position(graph_padding);
+}
+
+Rect2 GraphEditMinimap::get_camera_rect() {
+ Vector2 camera_center = _convert_from_graph_position(camera_position + camera_size / 2) + minimap_offset;
+ Vector2 camera_viewport = _convert_from_graph_position(camera_size);
+ Vector2 camera_position = (camera_center - camera_viewport / 2);
+ return Rect2(camera_position, camera_viewport);
+}
+
+Vector2 GraphEditMinimap::_get_render_size() {
+ if (!is_inside_tree()) {
+ return Vector2(0, 0);
+ }
+
+ return get_size() - 2 * minimap_padding;
+}
+
+Vector2 GraphEditMinimap::_get_graph_offset() {
+ return Vector2(ge->h_scroll->get_min(), ge->v_scroll->get_min());
+}
+
+Vector2 GraphEditMinimap::_get_graph_size() {
+ Vector2 graph_size = Vector2(ge->h_scroll->get_max(), ge->v_scroll->get_max()) - Vector2(ge->h_scroll->get_min(), ge->v_scroll->get_min());
+
+ if (graph_size.x == 0) {
+ graph_size.x = 1;
+ }
+ if (graph_size.y == 0) {
+ graph_size.y = 1;
+ }
+
+ return graph_size;
+}
+
+Vector2 GraphEditMinimap::_convert_from_graph_position(const Vector2 &p_position) {
+ Vector2 map_position = Vector2(0, 0);
+ Vector2 render_size = _get_render_size();
+
+ map_position.x = p_position.x * render_size.x / graph_proportions.x;
+ map_position.y = p_position.y * render_size.y / graph_proportions.y;
+
+ return map_position;
+}
+
+Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position) {
+ Vector2 graph_position = Vector2(0, 0);
+ Vector2 render_size = _get_render_size();
+
+ graph_position.x = p_position.x * graph_proportions.x / render_size.x;
+ graph_position.y = p_position.y * graph_proportions.y / render_size.y;
+
+ return graph_position;
+}
+
+void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
+ Ref<InputEventMouseButton> mb = p_ev;
+ Ref<InputEventMouseMotion> mm = p_ev;
+
+ if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ is_pressing = true;
+
+ Ref<Texture2D> resizer = get_theme_icon("resizer");
+ Rect2 resizer_hitbox = Rect2(Point2(), resizer->get_size());
+ if (resizer_hitbox.has_point(mb->get_position())) {
+ is_resizing = true;
+ } else {
+ Vector2 click_position = _convert_to_graph_position(mb->get_position() - minimap_padding) - graph_padding;
+ _adjust_graph_scroll(click_position);
+ }
+ } else {
+ is_pressing = false;
+ is_resizing = false;
+ }
+ accept_event();
+ } else if (mm.is_valid() && is_pressing) {
+ if (is_resizing) {
+ ge->set_minimap_size(ge->get_minimap_size() - mm->get_relative());
+ update();
+ } else {
+ Vector2 click_position = _convert_to_graph_position(mm->get_position() - minimap_padding) - graph_padding;
+ _adjust_graph_scroll(click_position);
+ }
+ accept_event();
+ }
+}
+
+void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) {
+ Vector2 graph_offset = _get_graph_offset();
+ ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2);
+}
+
Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) {
if (is_node_connected(p_from, p_from_port, p_to, p_to_port)) {
return OK;
@@ -64,6 +203,7 @@ Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const S
c.activity = 0;
connections.push_back(c);
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
@@ -85,6 +225,7 @@ void GraphEdit::disconnect_node(const StringName &p_from, int p_from_port, const
if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) {
connections.erase(E);
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
return;
@@ -118,6 +259,7 @@ void GraphEdit::_scroll_moved(double) {
awaiting_scroll_offset_update = true;
}
top_layer->update();
+ minimap->update();
update();
if (!setting_scroll_ofs) { //in godot, signals on change value are avoided as a convention
@@ -234,6 +376,7 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
ERR_FAIL_COND(!gn);
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
}
@@ -241,13 +384,15 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
void GraphEdit::add_child_notify(Node *p_child) {
Control::add_child_notify(p_child);
- top_layer->call_deferred("raise"); //top layer always on top!
+ top_layer->call_deferred("raise"); // Top layer always on top!
+
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
if (gn) {
gn->set_scale(Vector2(zoom, zoom));
gn->connect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved), varray(gn));
gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised), varray(gn));
gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update));
+ gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update));
_graph_node_moved(gn);
gn->set_mouse_filter(MOUSE_FILTER_PASS);
}
@@ -255,14 +400,17 @@ void GraphEdit::add_child_notify(Node *p_child) {
void GraphEdit::remove_child_notify(Node *p_child) {
Control::remove_child_notify(p_child);
+
if (is_inside_tree()) {
- top_layer->call_deferred("raise"); //top layer always on top!
+ top_layer->call_deferred("raise"); // Top layer always on top!
}
+
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
if (gn) {
gn->disconnect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised));
gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update));
+ gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update));
}
}
@@ -275,6 +423,7 @@ void GraphEdit::_notification(int p_what) {
zoom_reset->set_icon(get_theme_icon("reset"));
zoom_plus->set_icon(get_theme_icon("more"));
snap_button->set_icon(get_theme_icon("snap"));
+ minimap_button->set_icon(get_theme_icon("minimap"));
}
if (p_what == NOTIFICATION_READY) {
Size2 hmin = h_scroll->get_combined_minimum_size();
@@ -338,6 +487,7 @@ void GraphEdit::_notification(int p_what) {
if (p_what == NOTIFICATION_RESIZED) {
_update_scroll();
top_layer->update();
+ minimap->update();
}
}
@@ -472,6 +622,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_to = mm->get_position();
connecting_target = false;
top_layer->update();
+ minimap->update();
connecting_valid = just_disconnected || click_pos.distance_to(connecting_to) > 20.0 * zoom;
if (connecting_valid) {
@@ -541,6 +692,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting = false;
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
}
@@ -632,12 +784,12 @@ void GraphEdit::_bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors,
}
}
-void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color) {
+void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio = 1.0) {
//cubic bezier code
float diff = p_to.x - p_from.x;
float cp_offset;
- int cp_len = get_theme_constant("bezier_len_pos");
- int cp_neg_len = get_theme_constant("bezier_len_neg");
+ int cp_len = get_theme_constant("bezier_len_pos") * p_bezier_ratio;
+ int cp_neg_len = get_theme_constant("bezier_len_neg") * p_bezier_ratio;
if (diff > 0) {
cp_offset = MIN(cp_len, diff * 0.5);
@@ -659,9 +811,9 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const
colors.push_back(p_to_color);
#ifdef TOOLS_ENABLED
- p_where->draw_polyline_colors(points, colors, Math::floor(2 * EDSCALE), true);
+ p_where->draw_polyline_colors(points, colors, Math::floor(p_width * EDSCALE), lines_antialiased);
#else
- p_where->draw_polyline_colors(points, colors, 2, true);
+ p_where->draw_polyline_colors(points, colors, p_width, lines_antialiased);
#endif
}
@@ -708,7 +860,7 @@ void GraphEdit::_connections_layer_draw() {
color = color.lerp(activity_color, E->get().activity);
tocolor = tocolor.lerp(activity_color, E->get().activity);
}
- _draw_cos_line(connections_layer, frompos, topos, color, tocolor);
+ _draw_cos_line(connections_layer, frompos, topos, color, tocolor, lines_thickness);
}
while (to_erase.size()) {
@@ -747,7 +899,7 @@ void GraphEdit::_top_layer_draw() {
if (!connecting_out) {
SWAP(pos, topos);
}
- _draw_cos_line(top_layer, pos, topos, col, col);
+ _draw_cos_line(top_layer, pos, topos, col, col, lines_thickness);
}
if (box_selecting) {
@@ -756,6 +908,114 @@ void GraphEdit::_top_layer_draw() {
}
}
+void GraphEdit::_minimap_draw() {
+ if (!is_minimap_enabled()) {
+ return;
+ }
+
+ minimap->update_minimap();
+
+ // Draw the minimap background.
+ Rect2 minimap_rect = Rect2(Point2(), minimap->get_size());
+ minimap->draw_style_box(minimap->get_theme_stylebox("bg"), minimap_rect);
+
+ Vector2 graph_offset = minimap->_get_graph_offset();
+ Vector2 minimap_offset = minimap->minimap_offset;
+
+ // Draw comment graph nodes.
+ for (int i = get_child_count() - 1; i >= 0; i--) {
+ GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
+ if (!gn || !gn->is_comment()) {
+ continue;
+ }
+
+ Vector2 node_position = minimap->_convert_from_graph_position(gn->get_offset() * zoom - graph_offset) + minimap_offset;
+ Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom);
+ Rect2 node_rect = Rect2(node_position, node_size);
+
+ Ref<StyleBoxFlat> sb_minimap = minimap->get_theme_stylebox("node")->duplicate();
+
+ // Override default values with colors provided by the GraphNode's stylebox, if possible.
+ Ref<StyleBoxFlat> sbf = gn->get_theme_stylebox(gn->is_selected() ? "commentfocus" : "comment");
+ if (sbf.is_valid()) {
+ Color node_color = sbf->get_bg_color();
+ sb_minimap->set_bg_color(node_color);
+ }
+
+ minimap->draw_style_box(sb_minimap, node_rect);
+ }
+
+ // Draw regular graph nodes.
+ for (int i = get_child_count() - 1; i >= 0; i--) {
+ GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
+ if (!gn || gn->is_comment()) {
+ continue;
+ }
+
+ Vector2 node_position = minimap->_convert_from_graph_position(gn->get_offset() * zoom - graph_offset) + minimap_offset;
+ Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom);
+ Rect2 node_rect = Rect2(node_position, node_size);
+
+ Ref<StyleBoxFlat> sb_minimap = minimap->get_theme_stylebox("node")->duplicate();
+
+ // Override default values with colors provided by the GraphNode's stylebox, if possible.
+ Ref<StyleBoxFlat> sbf = gn->get_theme_stylebox(gn->is_selected() ? "selectedframe" : "frame");
+ if (sbf.is_valid()) {
+ Color node_color = sbf->get_border_color();
+ sb_minimap->set_bg_color(node_color);
+ }
+
+ minimap->draw_style_box(sb_minimap, node_rect);
+ }
+
+ // Draw node connections.
+ Color activity_color = get_theme_color("activity");
+ for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
+ NodePath fromnp(E->get().from);
+
+ Node *from = get_node(fromnp);
+ if (!from) {
+ continue;
+ }
+ GraphNode *gfrom = Object::cast_to<GraphNode>(from);
+ if (!gfrom) {
+ continue;
+ }
+
+ NodePath tonp(E->get().to);
+ Node *to = get_node(tonp);
+ if (!to) {
+ continue;
+ }
+ GraphNode *gto = Object::cast_to<GraphNode>(to);
+ if (!gto) {
+ continue;
+ }
+
+ Vector2 from_slot_position = gfrom->get_offset() * zoom + gfrom->get_connection_output_position(E->get().from_port);
+ Vector2 from_position = minimap->_convert_from_graph_position(from_slot_position - graph_offset) + minimap_offset;
+ Color from_color = gfrom->get_connection_output_color(E->get().from_port);
+ Vector2 to_slot_position = gto->get_offset() * zoom + gto->get_connection_input_position(E->get().to_port);
+ Vector2 to_position = minimap->_convert_from_graph_position(to_slot_position - graph_offset) + minimap_offset;
+ Color to_color = gto->get_connection_input_color(E->get().to_port);
+
+ if (E->get().activity > 0) {
+ from_color = from_color.lerp(activity_color, E->get().activity);
+ to_color = to_color.lerp(activity_color, E->get().activity);
+ }
+ _draw_cos_line(minimap, from_position, to_position, from_color, to_color, 1.0, 0.5);
+ }
+
+ // Draw the "camera" viewport.
+ Rect2 camera_rect = minimap->get_camera_rect();
+ minimap->draw_style_box(minimap->get_theme_stylebox("camera"), camera_rect);
+
+ // Draw the resizer control.
+ Ref<Texture2D> resizer = minimap->get_theme_icon("resizer");
+ Color resizer_color = minimap->get_theme_color("resizer_color");
+ minimap->draw_texture(resizer, Point2(), resizer_color);
+}
+
void GraphEdit::set_selected(Node *p_child) {
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -836,6 +1096,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
top_layer->update();
+ minimap->update();
}
Ref<InputEventMouseButton> b = p_ev;
@@ -858,10 +1119,12 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
gn->set_selected(select);
}
top_layer->update();
+ minimap->update();
} else {
if (connecting) {
connecting = false;
top_layer->update();
+ minimap->update();
} else {
emit_signal("popup_request", b->get_global_position());
}
@@ -902,6 +1165,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
dragging = false;
top_layer->update();
+ minimap->update();
update();
connections_layer->update();
}
@@ -1012,6 +1276,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
box_selecting = false;
previus_selected.clear();
top_layer->update();
+ minimap->update();
}
if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) {
@@ -1079,6 +1344,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
if (Math::is_equal_approx(E->get().activity, p_activity)) {
//update only if changed
top_layer->update();
+ minimap->update();
connections_layer->update();
}
E->get().activity = p_activity;
@@ -1089,6 +1355,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
void GraphEdit::clear_connections() {
connections.clear();
+ minimap->update();
update();
connections_layer->update();
}
@@ -1112,6 +1379,7 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
top_layer->update();
_update_scroll();
+ minimap->update();
connections_layer->update();
if (is_visible_in_tree()) {
@@ -1229,6 +1497,63 @@ void GraphEdit::_snap_value_changed(double) {
update();
}
+void GraphEdit::set_minimap_size(Vector2 p_size) {
+ minimap->set_size(p_size);
+ Vector2 minimap_size = minimap->get_size(); // The size might've been adjusted by the minimum size.
+
+ minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
+ minimap->set_margin(Margin::MARGIN_LEFT, -minimap_size.x - MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_TOP, -minimap_size.y - MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_RIGHT, -MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET);
+ minimap->update();
+}
+
+Vector2 GraphEdit::get_minimap_size() const {
+ return minimap->get_size();
+}
+
+void GraphEdit::set_minimap_opacity(float p_opacity) {
+ minimap->set_modulate(Color(1, 1, 1, p_opacity));
+ minimap->update();
+}
+
+float GraphEdit::get_minimap_opacity() const {
+ Color minimap_modulate = minimap->get_modulate();
+ return minimap_modulate.a;
+}
+
+void GraphEdit::set_minimap_enabled(bool p_enable) {
+ minimap_button->set_pressed(p_enable);
+ minimap->update();
+}
+
+bool GraphEdit::is_minimap_enabled() const {
+ return minimap_button->is_pressed();
+}
+
+void GraphEdit::_minimap_toggled() {
+ minimap->update();
+}
+
+void GraphEdit::set_connection_lines_thickness(float p_thickness) {
+ lines_thickness = p_thickness;
+ update();
+}
+
+float GraphEdit::get_connection_lines_thickness() const {
+ return lines_thickness;
+}
+
+void GraphEdit::set_connection_lines_antialiased(bool p_antialiased) {
+ lines_antialiased = p_antialiased;
+ update();
+}
+
+bool GraphEdit::is_connection_lines_antialiased() const {
+ return lines_antialiased;
+}
+
HBoxContainer *GraphEdit::get_zoom_hbox() {
return zoom_hb;
}
@@ -1260,6 +1585,20 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_snap", "enable"), &GraphEdit::set_use_snap);
ClassDB::bind_method(D_METHOD("is_using_snap"), &GraphEdit::is_using_snap);
+ ClassDB::bind_method(D_METHOD("set_connection_lines_thickness", "pixels"), &GraphEdit::set_connection_lines_thickness);
+ ClassDB::bind_method(D_METHOD("get_connection_lines_thickness"), &GraphEdit::get_connection_lines_thickness);
+
+ ClassDB::bind_method(D_METHOD("set_connection_lines_antialiased", "pixels"), &GraphEdit::set_connection_lines_antialiased);
+ ClassDB::bind_method(D_METHOD("is_connection_lines_antialiased"), &GraphEdit::is_connection_lines_antialiased);
+
+ ClassDB::bind_method(D_METHOD("set_minimap_size", "p_size"), &GraphEdit::set_minimap_size);
+ ClassDB::bind_method(D_METHOD("get_minimap_size"), &GraphEdit::get_minimap_size);
+ ClassDB::bind_method(D_METHOD("set_minimap_opacity", "p_opacity"), &GraphEdit::set_minimap_opacity);
+ ClassDB::bind_method(D_METHOD("get_minimap_opacity"), &GraphEdit::get_minimap_opacity);
+
+ ClassDB::bind_method(D_METHOD("set_minimap_enabled", "enable"), &GraphEdit::set_minimap_enabled);
+ ClassDB::bind_method(D_METHOD("is_minimap_enabled"), &GraphEdit::is_minimap_enabled);
+
ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects);
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
@@ -1275,6 +1614,12 @@ void GraphEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_snap"), "set_use_snap", "is_using_snap");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom"), "set_zoom", "get_zoom");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_thickness"), "set_connection_lines_thickness", "get_connection_lines_thickness");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "connection_lines_antialiased"), "set_connection_lines_antialiased", "is_connection_lines_antialiased");
+ ADD_GROUP("Minimap", "minimap");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "minimap_enabled"), "set_minimap_enabled", "is_minimap_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimap_size"), "set_minimap_size", "get_minimap_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "minimap_opacity"), "set_minimap_opacity", "get_minimap_opacity");
ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
@@ -1380,6 +1725,32 @@ GraphEdit::GraphEdit() {
snap_amount->connect("value_changed", callable_mp(this, &GraphEdit::_snap_value_changed));
zoom_hb->add_child(snap_amount);
+ minimap_button = memnew(Button);
+ minimap_button->set_flat(true);
+ minimap_button->set_toggle_mode(true);
+ minimap_button->set_tooltip(RTR("Enable grid minimap."));
+ minimap_button->connect("pressed", callable_mp(this, &GraphEdit::_minimap_toggled));
+ minimap_button->set_pressed(true);
+ minimap_button->set_focus_mode(FOCUS_NONE);
+ zoom_hb->add_child(minimap_button);
+
+ Vector2 minimap_size = Vector2(240, 160);
+ float minimap_opacity = 0.65;
+
+ minimap = memnew(GraphEditMinimap(this));
+ top_layer->add_child(minimap);
+ minimap->set_name("_minimap");
+ minimap->set_modulate(Color(1, 1, 1, minimap_opacity));
+ minimap->set_mouse_filter(MOUSE_FILTER_STOP);
+ minimap->set_custom_minimum_size(Vector2(50, 50));
+ minimap->set_size(minimap_size);
+ minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
+ minimap->set_margin(Margin::MARGIN_LEFT, -minimap_size.x - MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_TOP, -minimap_size.y - MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_RIGHT, -MINIMAP_OFFSET);
+ minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET);
+ minimap->connect("draw", callable_mp(this, &GraphEdit::_minimap_draw));
+
setting_scroll_ofs = false;
just_disconnected = false;
set_clip_contents(true);
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index d87bd41f27..d081789784 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -45,6 +45,7 @@ class GraphEditFilter : public Control {
GDCLASS(GraphEditFilter, Control);
friend class GraphEdit;
+ friend class GraphEditMinimap;
GraphEdit *ge;
virtual bool has_point(const Point2 &p_point) const override;
@@ -52,6 +53,45 @@ public:
GraphEditFilter(GraphEdit *p_edit);
};
+class GraphEditMinimap : public Control {
+ GDCLASS(GraphEditMinimap, Control);
+
+ friend class GraphEdit;
+ friend class GraphEditFilter;
+ GraphEdit *ge;
+
+protected:
+ static void _bind_methods();
+
+public:
+ GraphEditMinimap(GraphEdit *p_edit);
+
+ void update_minimap();
+ Rect2 get_camera_rect();
+
+private:
+ Vector2 minimap_padding;
+ Vector2 minimap_offset;
+ Vector2 graph_proportions;
+ Vector2 graph_padding;
+ Vector2 camera_position;
+ Vector2 camera_size;
+
+ bool is_pressing;
+ bool is_resizing;
+
+ Vector2 _get_render_size();
+ Vector2 _get_graph_offset();
+ Vector2 _get_graph_size();
+
+ Vector2 _convert_from_graph_position(const Vector2 &p_position);
+ Vector2 _convert_to_graph_position(const Vector2 &p_position);
+
+ void _gui_input(const Ref<InputEvent> &p_ev);
+
+ void _adjust_graph_scroll(const Vector2 &p_offset);
+};
+
class GraphEdit : public Control {
GDCLASS(GraphEdit, Control);
@@ -72,6 +112,8 @@ private:
Button *snap_button;
SpinBox *snap_amount;
+ Button *minimap_button;
+
void _zoom_minus();
void _zoom_reset();
void _zoom_plus();
@@ -116,9 +158,12 @@ private:
bool awaiting_scroll_offset_update;
List<Connection> connections;
+ float lines_thickness = 2.0f;
+ bool lines_antialiased = true;
+
void _bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const;
- void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color);
+ void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio);
void _graph_node_raised(Node *p_gn);
void _graph_node_moved(Node *p_gn);
@@ -129,12 +174,14 @@ private:
Control *connections_layer;
GraphEditFilter *top_layer;
+ GraphEditMinimap *minimap;
void _top_layer_input(const Ref<InputEvent> &p_ev);
bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos);
void _top_layer_draw();
void _connections_layer_draw();
+ void _minimap_draw();
void _update_scroll_offset();
Array _get_connection_list() const;
@@ -171,6 +218,9 @@ private:
void _snap_toggled();
void _snap_value_changed(double);
+ friend class GraphEditMinimap;
+ void _minimap_toggled();
+
bool _check_clickable_control(Control *p_control, const Vector2 &pos);
protected:
@@ -196,7 +246,16 @@ public:
void set_zoom_custom(float p_zoom, const Vector2 &p_center);
float get_zoom() const;
+ void set_minimap_size(Vector2 p_size);
+ Vector2 get_minimap_size() const;
+ void set_minimap_opacity(float p_opacity);
+ float get_minimap_opacity() const;
+
+ void set_minimap_enabled(bool p_enable);
+ bool is_minimap_enabled() const;
+
GraphEditFilter *get_top_layer() const { return top_layer; }
+ GraphEditMinimap *get_minimap() const { return minimap; }
void get_connection_list(List<Connection> *r_connections) const;
void set_right_disconnects(bool p_enable);
@@ -219,6 +278,12 @@ public:
int get_snap() const;
void set_snap(int p_snap);
+ void set_connection_lines_thickness(float p_thickness);
+ float get_connection_lines_thickness() const;
+
+ void set_connection_lines_antialiased(bool p_antialiased);
+ bool is_connection_lines_antialiased() const;
+
HBoxContainer *get_zoom_hbox();
GraphEdit();
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 53fe5712c7..5be7804ac1 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -78,6 +78,7 @@ void ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) {
item.icon_region = Rect2i();
item.icon_modulate = Color(1, 1, 1, 1);
//item.text=p_item;
+ item.text_buf.instance();
item.selectable = p_selectable;
item.selected = false;
item.disabled = false;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index e83c062e8a..566d77e3fd 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -64,16 +64,17 @@ bool Label::is_uppercase() const {
}
int Label::get_line_height(int p_line) const {
+ Ref<Font> font = get_theme_font("font");
if (p_line >= 0 && p_line < lines_rid.size()) {
- return TS->shaped_text_get_size(lines_rid[p_line]).y;
+ return TS->shaped_text_get_size(lines_rid[p_line]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM);
} else if (lines_rid.size() > 0) {
int h = 0;
for (int i = 0; i < lines_rid.size(); i++) {
- h = MAX(h, TS->shaped_text_get_size(lines_rid[i]).y);
+ h = MAX(h, TS->shaped_text_get_size(lines_rid[i]).y) + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM);
}
return h;
} else {
- return get_theme_font("font")->get_height(get_theme_font_size("font_size"));
+ return font->get_height(get_theme_font_size("font_size"));
}
}
@@ -138,6 +139,7 @@ void Label::_shape() {
void Label::_update_visible() {
int line_spacing = get_theme_constant("line_spacing", "Label");
Ref<StyleBox> style = get_theme_stylebox("normal", "Label");
+ Ref<Font> font = get_theme_font("font");
int lines_visible = lines_rid.size();
if (max_lines_visible >= 0 && lines_visible > max_lines_visible) {
@@ -147,7 +149,7 @@ void Label::_update_visible() {
minsize.height = 0;
int last_line = MIN(lines_rid.size(), lines_visible + lines_skipped);
for (int64_t i = lines_skipped; i < last_line; i++) {
- minsize.height += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing;
+ minsize.height += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing;
if (minsize.height > (get_size().height - style->get_minimum_size().height + line_spacing)) {
break;
}
@@ -197,7 +199,7 @@ void Label::_notification(int p_what) {
// Get number of lines to fit to the height.
for (int64_t i = lines_skipped; i < lines_rid.size(); i++) {
- total_h += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing;
+ total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing;
if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) {
break;
}
@@ -213,7 +215,7 @@ void Label::_notification(int p_what) {
// Get real total height.
total_h = 0;
for (int64_t i = lines_skipped; i < last_line; i++) {
- total_h += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing;
+ total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing;
}
int vbegin = 0, vsep = 0;
@@ -249,8 +251,10 @@ void Label::_notification(int p_what) {
if (percent_visible < 1) {
int total_glyphs = 0;
for (int i = lines_skipped; i < last_line; i++) {
- const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
- for (int j = 0; j < glyphs.size(); j++) {
+ const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]);
+ const TextServer::Glyph *glyphs = visual.ptr();
+ int gl_size = visual.size();
+ for (int j = 0; j < gl_size; j++) {
if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
total_glyphs++;
}
@@ -263,7 +267,7 @@ void Label::_notification(int p_what) {
ofs.y = style->get_offset().y + vbegin;
for (int i = lines_skipped; i < last_line; i++) {
ofs.x = 0;
- ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + font->get_spacing(Font::SPACING_TOP);
switch (align) {
case ALIGN_FILL:
case ALIGN_LEFT: {
@@ -285,11 +289,13 @@ void Label::_notification(int p_what) {
} break;
}
- const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
+ const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]);
+ const TextServer::Glyph *glyphs = visual.ptr();
+ int gl_size = visual.size();
float x = ofs.x;
int outlines_drawn = glyhps_drawn;
- for (int j = 0; j < glyphs.size(); j++) {
+ for (int j = 0; j < gl_size; j++) {
for (int k = 0; k < glyphs[j].repeat; k++) {
if (glyphs[j].font_rid != RID()) {
if (font_color_shadow.a > 0) {
@@ -318,7 +324,7 @@ void Label::_notification(int p_what) {
}
ofs.x = x;
- for (int j = 0; j < glyphs.size(); j++) {
+ for (int j = 0; j < gl_size; j++) {
for (int k = 0; k < glyphs[j].repeat; k++) {
if (glyphs[j].font_rid != RID()) {
TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_color);
@@ -337,7 +343,7 @@ void Label::_notification(int p_what) {
}
}
- ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing + font->get_spacing(Font::SPACING_BOTTOM);
}
}
@@ -381,12 +387,13 @@ int Label::get_line_count() const {
}
int Label::get_visible_line_count() const {
+ Ref<Font> font = get_theme_font("font");
Ref<StyleBox> style = get_theme_stylebox("normal");
int line_spacing = get_theme_constant("line_spacing");
int lines_visible = 0;
float total_h = 0;
for (int64_t i = lines_skipped; i < lines_rid.size(); i++) {
- total_h += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing;
+ total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing;
if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) {
break;
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 2eaa814419..9f8b944f4c 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -228,6 +228,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} break;
+ case (KEY_Y): // PASTE (Yank for unix users).
case (KEY_V): { // PASTE.
if (editable) {
@@ -258,13 +259,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} break;
- case (KEY_Y): { // PASTE (Yank for unix users).
-
- if (editable) {
- paste_text();
- }
-
- } break;
case (KEY_K): { // Delete from cursor_pos to end.
if (editable) {
@@ -732,6 +726,7 @@ void LineEdit::_notification(int p_what) {
style = get_theme_stylebox("read_only");
draw_caret = false;
}
+ Ref<Font> font = get_theme_font("font");
style->draw(ci, Rect2(Point2(), size));
@@ -742,7 +737,7 @@ void LineEdit::_notification(int p_what) {
int x_ofs = 0;
bool using_placeholder = text.empty() && ime_text.empty();
float text_width = TS->shaped_text_get_size(text_rid).x;
- float text_height = TS->shaped_text_get_size(text_rid).y;
+ float text_height = TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM);
switch (align) {
case ALIGN_FILL:
@@ -833,14 +828,16 @@ void LineEdit::_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_color);
}
}
- const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(text_rid);
+ const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(text_rid);
+ const TextServer::Glyph *glyphs = visual.ptr();
+ int gl_size = visual.size();
// Draw text.
ofs.y += TS->shaped_text_get_ascent(text_rid);
- for (int i = 0; i < glyphs.size(); i++) {
+ for (int i = 0; i < gl_size; i++) {
bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end;
for (int j = 0; j < glyphs[i].repeat; j++) {
- if (ceil(ofs.x) >= x_ofs && floor(ofs.x + glyphs[i].advance) <= ofs_max) {
+ if (ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) {
if (glyphs[i].font_rid != RID()) {
TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_color_selected : font_color);
} else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
@@ -1570,7 +1567,7 @@ Size2 LineEdit::get_minimum_size() const {
min_size.width = MAX(min_size.width, full_width + space_size);
}
- min_size.height = MAX(TS->shaped_text_get_size(text_rid).y, font->get_height(font_size));
+ min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM), font->get_height(font_size));
// Take icons into account.
bool using_placeholder = text.empty() && ime_text.empty();
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 6dbf005f73..07f03ad40e 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -232,12 +232,13 @@ void PopupMenu::_submenu_timeout() {
}
void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
- if (p_event->is_action("ui_down") && p_event->is_pressed() && mouse_over != items.size() - 1) {
+ if (p_event->is_action("ui_down") && p_event->is_pressed()) {
int search_from = mouse_over + 1;
if (search_from >= items.size()) {
search_from = 0;
}
+ bool match_found = false;
for (int i = search_from; i < items.size(); i++) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
@@ -245,15 +246,31 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
_scroll_to_item(i);
control->update();
set_input_as_handled();
+ match_found = true;
break;
}
}
- } else if (p_event->is_action("ui_up") && p_event->is_pressed() && mouse_over != 0) {
+
+ if (!match_found) {
+ // If the last item is not selectable, try re-searching from the start.
+ for (int i = 0; i < search_from; i++) {
+ if (!items[i].separator && !items[i].disabled) {
+ mouse_over = i;
+ emit_signal("id_focused", i);
+ _scroll_to_item(i);
+ control->update();
+ set_input_as_handled();
+ break;
+ }
+ }
+ }
+ } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
int search_from = mouse_over - 1;
if (search_from < 0) {
search_from = items.size() - 1;
}
+ bool match_found = false;
for (int i = search_from; i >= 0; i--) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
@@ -261,9 +278,24 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
_scroll_to_item(i);
control->update();
set_input_as_handled();
+ match_found = true;
break;
}
}
+
+ if (!match_found) {
+ // If the first item is not selectable, try re-searching from the end.
+ for (int i = items.size() - 1; i >= search_from; i--) {
+ if (!items[i].separator && !items[i].disabled) {
+ mouse_over = i;
+ emit_signal("id_focused", i);
+ _scroll_to_item(i);
+ control->update();
+ set_input_as_handled();
+ break;
+ }
+ }
+ }
} else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
Node *n = get_parent();
if (n && Object::cast_to<PopupMenu>(n)) {
@@ -446,6 +478,7 @@ void PopupMenu::_draw_items() {
Color font_color_disabled = get_theme_color("font_color_disabled");
Color font_color_accel = get_theme_color("font_color_accel");
Color font_color_hover = get_theme_color("font_color_hover");
+ Color font_color_separator = get_theme_color("font_color_separator");
float scroll_width = scroll_container->get_v_scrollbar()->is_visible_in_tree() ? scroll_container->get_v_scrollbar()->get_size().width : 0;
float display_width = control->get_size().width - scroll_width;
@@ -548,7 +581,7 @@ void PopupMenu::_draw_items() {
if (items[i].separator) {
if (text != String()) {
int center = (display_width - items[i].text_buf->get_size().width) / 2;
- items[i].text_buf->draw(ci, Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), font_color_disabled);
+ items[i].text_buf->draw(ci, Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), font_color_separator);
}
} else {
item_ofs.x += icon_ofs + check_ofs;
diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp
index 76ca8abcc7..5b201f45d3 100644
--- a/scene/gui/rich_text_effect.cpp
+++ b/scene/gui/rich_text_effect.cpp
@@ -64,11 +64,8 @@ RichTextEffect::RichTextEffect() {
}
void CharFXTransform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_relative_index"), &CharFXTransform::get_relative_index);
- ClassDB::bind_method(D_METHOD("set_relative_index", "index"), &CharFXTransform::set_relative_index);
-
- ClassDB::bind_method(D_METHOD("get_absolute_index"), &CharFXTransform::get_absolute_index);
- ClassDB::bind_method(D_METHOD("set_absolute_index", "index"), &CharFXTransform::set_absolute_index);
+ ClassDB::bind_method(D_METHOD("get_range"), &CharFXTransform::get_range);
+ ClassDB::bind_method(D_METHOD("set_range", "range"), &CharFXTransform::set_range);
ClassDB::bind_method(D_METHOD("get_elapsed_time"), &CharFXTransform::get_elapsed_time);
ClassDB::bind_method(D_METHOD("set_elapsed_time", "time"), &CharFXTransform::set_elapsed_time);
@@ -76,6 +73,9 @@ void CharFXTransform::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_visible"), &CharFXTransform::is_visible);
ClassDB::bind_method(D_METHOD("set_visibility", "visibility"), &CharFXTransform::set_visibility);
+ ClassDB::bind_method(D_METHOD("is_outline"), &CharFXTransform::is_outline);
+ ClassDB::bind_method(D_METHOD("set_outline", "outline"), &CharFXTransform::set_outline);
+
ClassDB::bind_method(D_METHOD("get_offset"), &CharFXTransform::get_offset);
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &CharFXTransform::set_offset);
@@ -85,27 +85,24 @@ void CharFXTransform::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &CharFXTransform::get_environment);
ClassDB::bind_method(D_METHOD("set_environment", "environment"), &CharFXTransform::set_environment);
- ClassDB::bind_method(D_METHOD("get_character"), &CharFXTransform::get_character);
- ClassDB::bind_method(D_METHOD("set_character", "character"), &CharFXTransform::set_character);
+ ClassDB::bind_method(D_METHOD("get_glyph_index"), &CharFXTransform::get_glyph_index);
+ ClassDB::bind_method(D_METHOD("set_glyph_index", "glyph_index"), &CharFXTransform::set_glyph_index);
+
+ ClassDB::bind_method(D_METHOD("get_font"), &CharFXTransform::get_font);
+ ClassDB::bind_method(D_METHOD("set_font", "font"), &CharFXTransform::set_font);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "relative_index"), "set_relative_index", "get_relative_index");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "absolute_index"), "set_absolute_index", "get_absolute_index");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "range"), "set_range", "get_range");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time"), "set_elapsed_time", "get_elapsed_time");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visibility", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "outline"), "set_outline", "is_outline");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "env"), "set_environment", "get_environment");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "character"), "set_character", "get_character");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_index"), "set_glyph_index", "get_glyph_index");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "font"), "set_font", "get_font");
}
CharFXTransform::CharFXTransform() {
- relative_index = 0;
- absolute_index = 0;
- visibility = true;
- offset = Point2();
- color = Color();
- character = 0;
- elapsed_time = 0.0f;
}
CharFXTransform::~CharFXTransform() {
diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h
index e6b9f09e4d..1aa62c1c83 100644
--- a/scene/gui/rich_text_effect.h
+++ b/scene/gui/rich_text_effect.h
@@ -54,32 +54,37 @@ protected:
static void _bind_methods();
public:
- uint64_t relative_index;
- uint64_t absolute_index;
- bool visibility;
+ Vector2i range;
+ bool visibility = true;
+ bool outline = false;
Point2 offset;
Color color;
- char32_t character;
- float elapsed_time;
+ float elapsed_time = 0.0f;
Dictionary environment;
+ uint32_t glpyh_index = 0;
+ RID font;
CharFXTransform();
~CharFXTransform();
- uint64_t get_relative_index() { return relative_index; }
- void set_relative_index(uint64_t p_index) { relative_index = p_index; }
- uint64_t get_absolute_index() { return absolute_index; }
- void set_absolute_index(uint64_t p_index) { absolute_index = p_index; }
+ Vector2i get_range() { return range; }
+ void set_range(const Vector2i &p_range) { range = p_range; }
float get_elapsed_time() { return elapsed_time; }
void set_elapsed_time(float p_elapsed_time) { elapsed_time = p_elapsed_time; }
bool is_visible() { return visibility; }
- void set_visibility(bool p_vis) { visibility = p_vis; }
+ void set_visibility(bool p_visibility) { visibility = p_visibility; }
+ bool is_outline() { return outline; }
+ void set_outline(bool p_outline) { outline = p_outline; }
Point2 get_offset() { return offset; }
void set_offset(Point2 p_offset) { offset = p_offset; }
Color get_color() { return color; }
void set_color(Color p_color) { color = p_color; }
- int get_character() { return (int)character; }
- void set_character(int p_char) { character = (char32_t)p_char; }
+
+ uint32_t get_glyph_index() const { return glpyh_index; };
+ void set_glyph_index(uint32_t p_glpyh_index) { glpyh_index = p_glpyh_index; };
+ 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/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 08214b958e..244d90ca6b 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -140,741 +140,1088 @@ Rect2 RichTextLabel::_get_text_rect() {
return Rect2(style->get_offset(), get_size() - style->get_minimum_size());
}
-int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) {
- ERR_FAIL_INDEX_V((int)p_mode, 3, 0);
-
- RID ci;
- if (r_outside) {
- *r_outside = false;
+RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item_from, RichTextLabel::Item *p_item_to, int p_position) {
+ int offset = 0;
+ for (Item *it = p_item_from; it && it != p_item_to; it = _get_next_item(it)) {
+ switch (it->type) {
+ case ITEM_TEXT: {
+ ItemText *t = (ItemText *)it;
+ offset += t->text.length();
+ if (offset > p_position) {
+ return it;
+ }
+ } break;
+ case ITEM_NEWLINE:
+ case ITEM_IMAGE:
+ case ITEM_TABLE: {
+ offset += 1;
+ } break;
+ default:
+ break;
+ }
}
- if (p_mode == PROCESS_DRAW) {
- ci = get_canvas_item();
+ return p_item_from;
+}
- if (r_click_item) {
- *r_click_item = nullptr;
- }
+String RichTextLabel::_roman(int p_num, bool p_capitalize) const {
+ if (p_num > 3999) {
+ return "ERR";
+ };
+ String s;
+ if (p_capitalize) {
+ String M[] = { "", "M", "MM", "MMM" };
+ String C[] = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" };
+ String X[] = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" };
+ String I[] = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
+ s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10];
+ } else {
+ String M[] = { "", "m", "mm", "mmm" };
+ String C[] = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
+ String X[] = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
+ String I[] = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
+ s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10];
}
- Line &l = p_frame->lines.write[p_line];
- Item *it = l.from;
+ return s;
+}
- int line_ofs = 0;
- int margin = _find_margin(it, p_base_font);
- Align align = _find_align(it);
- int line = 0;
- int spaces = 0;
+String RichTextLabel::_letters(int p_num, bool p_capitalize) const {
+ int64_t n = p_num;
- int height = get_size().y;
+ int chars = 0;
+ do {
+ n /= 24;
+ chars++;
+ } while (n);
- if (p_mode != PROCESS_CACHE) {
- ERR_FAIL_INDEX_V(line, l.offset_caches.size(), 0);
- line_ofs = l.offset_caches[line];
- }
+ String s;
+ s.resize(chars + 1);
+ char32_t *c = s.ptrw();
+ c[chars] = 0;
+ n = p_num;
+ do {
+ int mod = ABS(n % 24);
+ char a = (p_capitalize ? 'A' : 'a');
+ c[--chars] = a + mod - 1;
- if (p_mode == PROCESS_CACHE) {
- l.offset_caches.clear();
- l.height_caches.clear();
- l.ascent_caches.clear();
- l.descent_caches.clear();
- l.char_count = 0;
- l.minimum_width = 0;
- l.maximum_width = 0;
- }
+ n /= 24;
+ } while (n);
- int wofs = margin;
- int spaces_size = 0;
- int align_ofs = 0;
+ return s;
+}
- if (p_mode != PROCESS_CACHE && align != ALIGN_FILL) {
- wofs += line_ofs;
- }
+void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width) {
+ ERR_FAIL_COND(p_frame == nullptr);
+ ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size());
+
+ Line &l = p_frame->lines.write[p_line];
- int begin = margin;
+ l.offset.x = _find_margin(l.from, p_base_font, p_base_font_size);
+ l.text_buf->set_width(p_width - l.offset.x);
- Ref<Font> cfont = _find_font(it);
- if (cfont.is_null()) {
- cfont = p_base_font;
+ if (tab_size > 0) { // Align inline tabs.
+ Vector<float> tabs;
+ tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width);
+ l.text_buf->tab_align(tabs);
}
- //line height should be the font height for the first time, this ensures that an empty line will never have zero height and successive newlines are displayed
- int line_height = cfont->get_height();
- int line_ascent = cfont->get_ascent();
- int line_descent = cfont->get_descent();
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ switch (it->type) {
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ int hseparation = get_theme_constant("table_hseparation");
+ int vseparation = get_theme_constant("table_vseparation");
+ int col_count = table->columns.size();
- int backtrack = 0; // for dynamic hidden content.
+ for (int i = 0; i < col_count; i++) {
+ table->columns.write[i].width = 0;
+ }
- int nonblank_line_count = 0; //number of nonblank lines as counted during PROCESS_DRAW
+ int idx = 0;
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+ for (int i = 0; i < frame->lines.size(); i++) {
+ _resize_line(frame, i, p_base_font, p_base_font_size, 1);
+ }
+ idx++;
+ }
- Variant meta;
+ // Compute minimum width for each cell.
+ const int available_width = p_width - hseparation * (col_count - 1);
-#define RETURN return nonblank_line_count
-
-#define NEW_LINE \
- { \
- if (p_mode != PROCESS_CACHE) { \
- line++; \
- backtrack = 0; \
- if (!line_is_blank) { \
- nonblank_line_count++; \
- } \
- line_is_blank = true; \
- if (line < l.offset_caches.size()) \
- line_ofs = l.offset_caches[line]; \
- wofs = margin; \
- if (align != ALIGN_FILL) \
- wofs += line_ofs; \
- } else { \
- int used = wofs - margin; \
- switch (align) { \
- case ALIGN_LEFT: \
- l.offset_caches.push_back(0); \
- break; \
- case ALIGN_CENTER: \
- l.offset_caches.push_back(((p_width - margin) - used) / 2); \
- break; \
- case ALIGN_RIGHT: \
- l.offset_caches.push_back(((p_width - margin) - used)); \
- break; \
- case ALIGN_FILL: \
- l.offset_caches.push_back(line_wrapped ? ((p_width - margin) - used) : 0); \
- break; \
- } \
- l.height_caches.push_back(line_height); \
- l.ascent_caches.push_back(line_ascent); \
- l.descent_caches.push_back(line_descent); \
- l.space_caches.push_back(spaces); \
- } \
- line_wrapped = false; \
- y += line_height + get_theme_constant(SceneStringNames::get_singleton()->line_separation); \
- line_height = 0; \
- line_ascent = 0; \
- line_descent = 0; \
- spaces = 0; \
- spaces_size = 0; \
- wofs = begin; \
- align_ofs = 0; \
- if (p_mode != PROCESS_CACHE) { \
- lh = line < l.height_caches.size() ? l.height_caches[line] : 1; \
- line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; \
- line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; \
- if (align != ALIGN_FILL) { \
- if (line < l.offset_caches.size()) { \
- wofs = l.offset_caches[line]; \
- } \
- } \
- } \
- if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && p_click_pos.x < p_ofs.x + wofs) { \
- if (r_outside) \
- *r_outside = true; \
- *r_click_item = it; \
- *r_click_char = rchar; \
- RETURN; \
- } \
- }
-
-#define ENSURE_WIDTH(m_width) \
- if (p_mode == PROCESS_CACHE) { \
- l.maximum_width = MAX(l.maximum_width, MIN(p_width, wofs + m_width)); \
- l.minimum_width = MAX(l.minimum_width, m_width); \
- } \
- if (wofs - backtrack + m_width > p_width) { \
- line_wrapped = true; \
- if (p_mode == PROCESS_CACHE) { \
- if (spaces > 0) \
- spaces -= 1; \
- } \
- const bool x_in_range = (p_click_pos.x > p_ofs.x + wofs) && (!p_frame->cell || p_click_pos.x < p_ofs.x + p_width); \
- if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && x_in_range) { \
- if (r_outside) \
- *r_outside = true; \
- *r_click_item = it; \
- *r_click_char = rchar; \
- RETURN; \
- } \
- NEW_LINE \
- }
-
-#define ADVANCE(m_width) \
- { \
- if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && p_click_pos.x >= p_ofs.x + wofs && p_click_pos.x < p_ofs.x + wofs + m_width) { \
- if (r_outside) \
- *r_outside = false; \
- *r_click_item = it; \
- *r_click_char = rchar; \
- RETURN; \
- } \
- wofs += m_width; \
- }
-
-#define CHECK_HEIGHT(m_height) \
- if (m_height > line_height) { \
- line_height = m_height; \
- }
-
-#define YRANGE_VISIBLE(m_top, m_height) \
- (m_height > 0 && ((m_top >= 0 && m_top < height) || ((m_top + m_height - 1) >= 0 && (m_top + m_height - 1) < height)))
-
- Color selection_fg;
- Color selection_bg;
-
- if (p_mode == PROCESS_DRAW) {
- selection_fg = get_theme_color("font_color_selected");
- selection_bg = get_theme_color("selection_color");
- }
-
- int rchar = 0;
- int lh = 0;
- bool line_is_blank = true;
- bool line_wrapped = false;
- int fh = 0;
+ // Compute available width and total ratio (for expanders).
+ int total_ratio = 0;
+ int remaining_width = available_width;
+ table->total_width = hseparation;
- while (it) {
- switch (it->type) {
- case ITEM_ALIGN: {
- ItemAlign *align_it = static_cast<ItemAlign *>(it);
+ for (int i = 0; i < col_count; i++) {
+ remaining_width -= table->columns[i].min_width;
+ if (table->columns[i].max_width > table->columns[i].min_width) {
+ table->columns.write[i].expand = true;
+ }
+ if (table->columns[i].expand) {
+ total_ratio += table->columns[i].expand_ratio;
+ }
+ }
- align = align_it->align;
+ // Assign actual widths.
+ for (int i = 0; i < col_count; i++) {
+ table->columns.write[i].width = table->columns[i].min_width;
+ if (table->columns[i].expand && total_ratio > 0) {
+ table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
+ }
+ table->total_width += table->columns[i].width + hseparation;
+ }
- } break;
- case ITEM_INDENT: {
- if (it != l.from) {
- ItemIndent *indent_it = static_cast<ItemIndent *>(it);
-
- int indent = indent_it->level * tab_size * cfont->get_char_size(' ').width;
- margin += indent;
- begin += indent;
- wofs += indent;
+ // Resize to max_width if needed and distribute the remaining space.
+ bool table_need_fit = true;
+ while (table_need_fit) {
+ table_need_fit = false;
+ // Fit slim.
+ for (int i = 0; i < col_count; i++) {
+ if (!table->columns[i].expand) {
+ continue;
+ }
+ int dif = table->columns[i].width - table->columns[i].max_width;
+ if (dif > 0) {
+ table_need_fit = true;
+ table->columns.write[i].width = table->columns[i].max_width;
+ table->total_width -= dif;
+ total_ratio -= table->columns[i].expand_ratio;
+ }
+ }
+ // Grow.
+ remaining_width = available_width - table->total_width;
+ if (remaining_width > 0 && total_ratio > 0) {
+ for (int i = 0; i < col_count; i++) {
+ if (table->columns[i].expand) {
+ int dif = table->columns[i].max_width - table->columns[i].width;
+ if (dif > 0) {
+ int slice = table->columns[i].expand_ratio * remaining_width / total_ratio;
+ int incr = MIN(dif, slice);
+ table->columns.write[i].width += incr;
+ table->total_width += incr;
+ }
+ }
+ }
+ }
}
+ // Update line width and get total height.
+ idx = 0;
+ table->total_height = 0;
+ table->rows.clear();
+
+ Vector2 offset;
+ float row_height = 0;
+
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+
+ int column = idx % col_count;
+
+ offset.x += frame->padding.position.x;
+ float yofs = frame->padding.position.y;
+ for (int i = 0; i < frame->lines.size(); i++) {
+ frame->lines.write[i].text_buf->set_width(table->columns[column].width);
+ table->columns.write[column].width = MAX(table->columns.write[column].width, ceil(frame->lines[i].text_buf->get_size().x));
+
+ if (i > 0) {
+ frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y;
+ } else {
+ frame->lines.write[i].offset.y = 0;
+ }
+ frame->lines.write[i].offset += Vector2(offset.x, offset.y);
+
+ float h = frame->lines[i].text_buf->get_size().y;
+ if (frame->min_size_over.y > 0) {
+ h = MAX(h, frame->min_size_over.y);
+ }
+ if (frame->max_size_over.y > 0) {
+ h = MIN(h, frame->max_size_over.y);
+ }
+ yofs += h;
+ }
+ yofs += frame->padding.size.y;
+ offset.x += table->columns[column].width + hseparation + frame->padding.size.x;
+
+ row_height = MAX(yofs, row_height);
+ if (column == col_count - 1) {
+ offset.x = 0;
+ row_height += vseparation;
+ table->total_height += row_height;
+ offset.y += row_height;
+ table->rows.push_back(row_height);
+ row_height = 0;
+ }
+ idx++;
+ }
+ l.text_buf->resize_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align);
} break;
- case ITEM_TEXT: {
- ItemText *text = static_cast<ItemText *>(it);
+ default:
+ break;
+ }
+ }
+ if (p_line > 0) {
+ l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y;
+ } else {
+ l.offset.y = 0;
+ }
+}
+
+void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset) {
+ ERR_FAIL_COND(p_frame == nullptr);
+ ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size());
+
+ Line &l = p_frame->lines.write[p_line];
+
+ // Clear cache.
+ l.text_buf->clear();
+ l.text_buf->set_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_TRIM_EDGE_SPACES);
+ l.char_offset = *r_char_offset;
+ l.char_count = 0;
+
+ // Add indent.
+ l.offset.x = _find_margin(l.from, p_base_font, p_base_font_size);
+ l.text_buf->set_width(p_width - l.offset.x);
+ l.text_buf->set_align((HAlign)_find_align(l.from));
+ l.text_buf->set_direction(_find_direction(l.from));
+
+ if (tab_size > 0) { // Align inline tabs.
+ Vector<float> tabs;
+ tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width);
+ l.text_buf->tab_align(tabs);
+ }
+
+ // Shape current paragraph.
+ String text;
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ if (visible_characters >= 0 && l.char_offset + l.char_count > visible_characters) {
+ break;
+ }
+ switch (it->type) {
+ case ITEM_NEWLINE: {
Ref<Font> font = _find_font(it);
if (font.is_null()) {
font = p_base_font;
}
+ int font_size = _find_font_size(it);
+ if (font_size == -1) {
+ font_size = p_base_font_size;
+ }
+ l.text_buf->add_string("\n", font, font_size, Dictionary(), "");
+ text += "\n";
+ l.char_count += 1;
+ } break;
+ case ITEM_TEXT: {
+ ItemText *t = (ItemText *)it;
+ Ref<Font> font = _find_font(it);
+ if (font.is_null()) {
+ font = p_base_font;
+ }
+ int font_size = _find_font_size(it);
+ if (font_size == -1) {
+ font_size = p_base_font_size;
+ }
+ Dictionary font_ftr = _find_font_features(it);
+ String lang = _find_language(it);
+ String tx = t->text;
+ if (visible_characters >= 0 && l.char_offset + l.char_count + tx.length() > visible_characters) {
+ tx = tx.substr(0, l.char_offset + l.char_count + tx.length() - visible_characters);
+ }
- const char32_t *c = text->text.get_data();
- const char32_t *cf = c;
- int ascent = font->get_ascent();
- int descent = font->get_descent();
-
- Color color;
- Color font_color_shadow;
- bool underline = false;
- bool strikethrough = false;
- ItemFade *fade = nullptr;
- int it_char_start = p_char_count;
-
- Vector<ItemFX *> fx_stack = Vector<ItemFX *>();
- _fetch_item_fx_stack(text, fx_stack);
- bool custom_fx_ok = true;
-
- if (p_mode == PROCESS_DRAW) {
- color = _find_color(text, p_base_color);
- font_color_shadow = _find_color(text, p_font_color_shadow);
- if (_find_underline(text) || (_find_meta(text, &meta) && underline_meta)) {
- underline = true;
- } else if (_find_strikethrough(text)) {
- strikethrough = true;
- }
+ l.text_buf->add_string(tx, font, font_size, font_ftr, lang);
+ text += tx;
+ l.char_count += tx.length();
+ } break;
+ case ITEM_IMAGE: {
+ ItemImage *img = (ItemImage *)it;
+ l.text_buf->add_object((uint64_t)it, img->image->get_size(), img->inline_align, 1);
+ text += String::chr(0xfffc);
+ } break;
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ int hseparation = get_theme_constant("table_hseparation");
+ int vseparation = get_theme_constant("table_vseparation");
+ int col_count = table->columns.size();
+ int t_char_count = 0;
+ // Set minimums to zero.
+ for (int i = 0; i < col_count; i++) {
+ table->columns.write[i].min_width = 0;
+ table->columns.write[i].max_width = 0;
+ table->columns.write[i].width = 0;
+ }
+ // Compute minimum width for each cell.
+ const int available_width = p_width - hseparation * (col_count - 1);
- Item *fade_item = it;
- while (fade_item) {
- if (fade_item->type == ITEM_FADE) {
- fade = static_cast<ItemFade *>(fade_item);
- break;
- }
- fade_item = fade_item->parent;
- }
+ int idx = 0;
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
- } else if (p_mode == PROCESS_CACHE) {
- l.char_count += text->text.length();
+ int column = idx % col_count;
+ for (int i = 0; i < frame->lines.size(); i++) {
+ int char_offset = l.char_offset + l.char_count;
+ _shape_line(frame, i, p_base_font, p_base_font_size, 1, &char_offset);
+ int cell_ch = (char_offset - (l.char_offset + l.char_count));
+ l.char_count += cell_ch;
+ t_char_count += cell_ch;
+
+ table->columns.write[column].min_width = MAX(table->columns[column].min_width, ceil(frame->lines[i].text_buf->get_size().x));
+ table->columns.write[column].max_width = MAX(table->columns[column].max_width, ceil(frame->lines[i].text_buf->get_non_wraped_size().x));
+ }
+ idx++;
}
- rchar = 0;
- //FontDrawer drawer(font, Color(1, 1, 1));
- while (*c) {
- int end = 0;
- int w = 0;
- int fw = 0;
+ // Compute available width and total ratio (for expanders).
+ int total_ratio = 0;
+ int remaining_width = available_width;
+ table->total_width = hseparation;
- lh = 0;
+ for (int i = 0; i < col_count; i++) {
+ remaining_width -= table->columns[i].min_width;
+ if (table->columns[i].max_width > table->columns[i].min_width) {
+ table->columns.write[i].expand = true;
+ }
+ if (table->columns[i].expand) {
+ total_ratio += table->columns[i].expand_ratio;
+ }
+ }
- if (p_mode != PROCESS_CACHE) {
- lh = line < l.height_caches.size() ? l.height_caches[line] : 1;
- line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1;
- line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1;
+ // Assign actual widths.
+ for (int i = 0; i < col_count; i++) {
+ table->columns.write[i].width = table->columns[i].min_width;
+ if (table->columns[i].expand && total_ratio > 0) {
+ table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
}
- while (c[end] != 0 && !(end && c[end - 1] == ' ' && c[end] != ' ')) {
- int cw = font->get_char_size(c[end], c[end + 1]).width;
- if (c[end] == '\t') {
- cw = tab_size * font->get_char_size(' ').width;
- }
+ table->total_width += table->columns[i].width + hseparation;
+ }
- if (end > 0 && fw + cw + begin > p_width) {
- break; //don't allow lines longer than assigned width
+ // Resize to max_width if needed and distribute the remaining space.
+ bool table_need_fit = true;
+ while (table_need_fit) {
+ table_need_fit = false;
+ // Fit slim.
+ for (int i = 0; i < col_count; i++) {
+ if (!table->columns[i].expand) {
+ continue;
+ }
+ int dif = table->columns[i].width - table->columns[i].max_width;
+ if (dif > 0) {
+ table_need_fit = true;
+ table->columns.write[i].width = table->columns[i].max_width;
+ table->total_width -= dif;
+ total_ratio -= table->columns[i].expand_ratio;
}
-
- fw += cw;
-
- end++;
}
- CHECK_HEIGHT(fh);
- ENSURE_WIDTH(fw);
-
- line_ascent = MAX(line_ascent, ascent);
- line_descent = MAX(line_descent, descent);
- fh = line_ascent + line_descent;
-
- if (end && c[end - 1] == ' ') {
- if (p_mode == PROCESS_CACHE) {
- spaces_size += font->get_char_size(' ').width;
- } else if (align == ALIGN_FILL) {
- int ln = MIN(l.offset_caches.size() - 1, line);
- if (l.space_caches[ln]) {
- align_ofs = spaces * l.offset_caches[ln] / l.space_caches[ln];
+ // Grow.
+ remaining_width = available_width - table->total_width;
+ if (remaining_width > 0 && total_ratio > 0) {
+ for (int i = 0; i < col_count; i++) {
+ if (table->columns[i].expand) {
+ int dif = table->columns[i].max_width - table->columns[i].width;
+ if (dif > 0) {
+ int slice = table->columns[i].expand_ratio * remaining_width / total_ratio;
+ int incr = MIN(dif, slice);
+ table->columns.write[i].width += incr;
+ table->total_width += incr;
+ }
}
}
- spaces++;
}
+ }
- {
- int ofs = 0 - backtrack;
+ // Update line width and get total height.
+ idx = 0;
+ table->total_height = 0;
+ table->rows.clear();
- for (int i = 0; i < end; i++) {
- int pofs = wofs + ofs;
+ Vector2 offset;
+ float row_height = 0;
- if (p_mode == PROCESS_POINTER && r_click_char && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh) {
- int cw = font->get_char_size(c[i], c[i + 1]).x;
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
- if (c[i] == '\t') {
- cw = tab_size * font->get_char_size(' ').width;
- }
+ int column = idx % col_count;
- if (p_click_pos.x - cw / 2 > p_ofs.x + align_ofs + pofs) {
- rchar = int((&c[i]) - cf);
- }
+ offset.x += frame->padding.position.x;
+ float yofs = frame->padding.position.y;
+ for (int i = 0; i < frame->lines.size(); i++) {
+ frame->lines.write[i].text_buf->set_width(table->columns[column].width);
+ table->columns.write[column].width = MAX(table->columns.write[column].width, ceil(frame->lines[i].text_buf->get_size().x));
- ofs += cw;
- } else if (p_mode == PROCESS_DRAW) {
- bool selected = false;
- Color fx_color = Color(color);
- Point2 fx_offset;
- char32_t fx_char = c[i];
-
- if (selection.active) {
- int cofs = (&c[i]) - cf;
- if ((text->index > selection.from->index || (text->index == selection.from->index && cofs >= selection.from_char)) && (text->index < selection.to->index || (text->index == selection.to->index && cofs <= selection.to_char))) {
- selected = true;
- }
- }
+ if (i > 0) {
+ frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y;
+ } else {
+ frame->lines.write[i].offset.y = 0;
+ }
+ frame->lines.write[i].offset += Vector2(offset.x, offset.y);
- int cw = 0;
- int c_item_offset = p_char_count - it_char_start;
+ float h = frame->lines[i].text_buf->get_size().y;
+ if (frame->min_size_over.y > 0) {
+ h = MAX(h, frame->min_size_over.y);
+ }
+ if (frame->max_size_over.y > 0) {
+ h = MIN(h, frame->max_size_over.y);
+ }
+ yofs += h;
+ }
+ yofs += frame->padding.size.y;
+ offset.x += table->columns[column].width + hseparation + frame->padding.size.x;
- float faded_visibility = 1.0f;
- if (fade) {
- if (c_item_offset >= fade->starting_index) {
- faded_visibility -= (float)(c_item_offset - fade->starting_index) / (float)fade->length;
- faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility;
- }
- fx_color.a = faded_visibility;
- }
+ row_height = MAX(yofs, row_height);
+ if (column == col_count - 1) {
+ offset.x = 0;
+ row_height += vseparation;
+ table->total_height += row_height;
+ offset.y += row_height;
+ table->rows.push_back(row_height);
+ row_height = 0;
+ }
+ idx++;
+ }
+
+ l.text_buf->add_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align, t_char_count);
+ text += String::chr(0xfffc).repeat(t_char_count);
+ } break;
+ default:
+ break;
+ }
+ }
- bool visible = visible_characters < 0 || ((p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - line_descent - line_ascent, line_ascent + line_descent)) &&
- faded_visibility > 0.0f);
+ //Apply BiDi override.
+ l.text_buf->set_bidi_override(structured_text_parser(_find_stt(l.from), st_args, text));
- const bool previously_visible = visible;
+ *r_char_offset = l.char_offset + l.char_count;
- for (int j = 0; j < fx_stack.size(); j++) {
- ItemFX *item_fx = fx_stack[j];
+ if (p_line > 0) {
+ l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y;
+ } else {
+ l.offset.y = 0;
+ }
+}
- if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
- ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
+float RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &p_shadow_ofs) {
+ Vector2 off;
- Ref<CharFXTransform> charfx = item_custom->char_fx_transform;
- Ref<RichTextEffect> custom_effect = item_custom->custom_effect;
+ ERR_FAIL_COND_V(p_frame == nullptr, off.y);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), off.y);
- if (!custom_effect.is_null()) {
- charfx->elapsed_time = item_custom->elapsed_time;
- charfx->relative_index = c_item_offset;
- charfx->absolute_index = p_char_count;
- charfx->visibility = visible;
- charfx->offset = fx_offset;
- charfx->color = fx_color;
- charfx->character = fx_char;
+ Line &l = p_frame->lines.write[p_line];
- bool effect_status = custom_effect->_process_effect_impl(charfx);
- custom_fx_ok = effect_status;
+ Item *it_from = l.from;
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ Variant meta;
- fx_offset += charfx->offset;
- fx_color = charfx->color;
- visible &= charfx->visibility;
- fx_char = charfx->character;
- }
- } else if (item_fx->type == ITEM_SHAKE) {
- ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
-
- uint64_t char_current_rand = item_shake->offset_random(c_item_offset);
- uint64_t char_previous_rand = item_shake->offset_previous_random(c_item_offset);
- uint64_t max_rand = 2147483647;
- double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
- n_time = (n_time > 1.0) ? 1.0 : n_time;
- fx_offset += Point2(Math::lerp(Math::sin(previous_offset),
- Math::sin(current_offset),
- n_time),
- Math::lerp(Math::cos(previous_offset),
- Math::cos(current_offset),
- n_time)) *
- (float)item_shake->strength / 10.0f;
- } else if (item_fx->type == ITEM_WAVE) {
- ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
-
- double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_wave->amplitude / 10.0f);
- fx_offset += Point2(0, 1) * value;
- } else if (item_fx->type == ITEM_TORNADO) {
- ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
-
- double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius);
- double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius);
- fx_offset += Point2(torn_x, torn_y);
- } else if (item_fx->type == ITEM_RAINBOW) {
- ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
-
- fx_color = fx_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + pofs) / 50)),
- item_rainbow->saturation,
- item_rainbow->value,
- fx_color.a);
- }
- }
+ if (it_from == nullptr) {
+ return off.y;
+ }
- if (visible) {
- line_is_blank = false;
- w += font->get_char_size(c[i], c[i + 1]).x;
- }
+ RID ci = get_canvas_item();
+ bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL);
+ bool lrtl = is_layout_rtl();
- if (c[i] == '\t') {
- visible = false;
- }
+ Vector<int> list_index;
+ Vector<ItemList *> list_items;
+ _find_list(l.from, list_index, list_items);
- if (visible) {
- if (selected) {
- cw = font->get_char_size(fx_char, c[i + 1]).x;
- draw_rect(Rect2(p_ofs.x + pofs, p_ofs.y + y, cw, lh), selection_bg);
- }
+ String prefix;
+ for (int i = 0; i < list_index.size(); i++) {
+ if (rtl) {
+ prefix = prefix + ".";
+ } else {
+ prefix = "." + prefix;
+ }
+ String segment;
+ if (list_items[i]->list_type == LIST_DOTS) {
+ static const char32_t _prefix[2] = { 0x25CF, 0 };
+ prefix = _prefix;
+ break;
+ } else if (list_items[i]->list_type == LIST_NUMBERS) {
+ segment = TS->format_number(itos(list_index[i]), _find_language(l.from));
+ } else if (list_items[i]->list_type == LIST_LETTERS) {
+ segment = _letters(list_index[i], list_items[i]->capitalize);
+ } else if (list_items[i]->list_type == LIST_ROMAN) {
+ segment = _roman(list_index[i], list_items[i]->capitalize);
+ }
+ if (rtl) {
+ prefix = prefix + segment;
+ } else {
+ prefix = segment + prefix;
+ }
+ }
+ if (prefix != "") {
+ Ref<Font> font = _find_font(l.from);
+ if (font.is_null()) {
+ font = get_theme_font("normal_font");
+ }
+ int font_size = _find_font_size(l.from);
+ if (font_size == -1) {
+ font_size = get_theme_font_size("normal_font_size");
+ }
+ if (rtl) {
+ float offx = 0.0f;
+ if (!lrtl && p_frame == main) { // Skip Scrollbar.
+ offx -= scroll_w;
+ }
+ font->draw_string(ci, p_ofs + Vector2(p_width - l.offset.x + offx, l.text_buf->get_line_ascent(0)), " " + prefix, HALIGN_LEFT, l.offset.x, font_size, _find_color(l.from, p_base_color));
+ } else {
+ float offx = 0.0f;
+ if (lrtl && p_frame == main) { // Skip Scrollbar.
+ offx += scroll_w;
+ }
+ font->draw_string(ci, p_ofs + Vector2(offx, l.text_buf->get_line_ascent(0)), prefix + " ", HALIGN_RIGHT, l.offset.x, font_size, _find_color(l.from, p_base_color));
+ }
+ }
- if (p_font_color_shadow.a > 0) {
- float x_ofs_shadow = align_ofs + pofs;
- float y_ofs_shadow = y + lh - line_descent;
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow);
+ // Draw text.
+ for (int line = 0; line < l.text_buf->get_line_count(); line++) {
+ RID rid = l.text_buf->get_line_rid(line);
- if (p_shadow_as_outline) {
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], -1, p_font_color_shadow);
- }
- }
+ float width = l.text_buf->get_width();
+ float length = TS->shaped_text_get_width(rid);
- if (selected) {
- font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), fx_char, c[i + 1], -1, override_selected_font_color ? selection_fg : fx_color);
- } else {
- cw = font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent) + fx_offset, fx_char, c[i + 1], -1, fx_color);
- }
- } else if (previously_visible && c[i] != '\t') {
- backtrack += font->get_char_size(fx_char, c[i + 1]).x;
- }
+ // Draw line.
- p_char_count++;
- if (c[i] == '\t') {
- cw = tab_size * font->get_char_size(' ').width;
- backtrack = MAX(0, backtrack - cw);
+ if (rtl) {
+ off.x = p_width - l.offset.x - width;
+ if (!lrtl && p_frame == main) { // Skip Scrollbar.
+ off.x -= scroll_w;
+ }
+ } else {
+ off.x = l.offset.x;
+ if (lrtl && p_frame == main) { // Skip Scrollbar.
+ off.x += scroll_w;
+ }
+ }
+
+ // Draw text.
+ switch (l.text_buf->get_align()) {
+ case HALIGN_FILL:
+ case HALIGN_LEFT: {
+ if (rtl) {
+ off.x += width - length;
+ }
+ } break;
+ case HALIGN_CENTER: {
+ off.x += Math::floor((width - length) / 2.0);
+ } break;
+ case HALIGN_RIGHT: {
+ if (!rtl) {
+ off.x += width - length;
+ }
+ } break;
+ }
+
+ //draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS
+
+ off.y += TS->shaped_text_get_ascent(rid);
+ // Draw inlined objects.
+ Array objects = TS->shaped_text_get_objects(rid);
+ for (int i = 0; i < objects.size(); i++) {
+ Item *it = (Item *)(uint64_t)objects[i];
+ if (it != nullptr) {
+ Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]);
+ //draw_rect(rect, Color(1,0,0), false, 2); //DEBUG_RECTS
+ switch (it->type) {
+ case ITEM_IMAGE: {
+ ItemImage *img = static_cast<ItemImage *>(it);
+ img->image->draw_rect(ci, Rect2(p_ofs + rect.position + off, rect.size), false, img->color);
+ } break;
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ Color odd_row_bg = get_theme_color("table_odd_row_bg");
+ Color even_row_bg = get_theme_color("table_even_row_bg");
+ Color border = get_theme_color("table_border");
+ int col_count = table->columns.size();
+ int row_count = table->rows.size();
+
+ int idx = 0;
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+
+ int col = idx % col_count;
+ int row = idx / col_count;
+
+ if (frame->lines.size() != 0 && row < row_count) {
+ Vector2 coff = frame->lines[0].offset;
+ if (rtl) {
+ coff.x = rect.size.width - table->columns[col].width - coff.x;
+ }
+ if (row % 2 == 0) {
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true);
+ } else {
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true);
}
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false);
+ }
- ofs += cw;
+ for (int j = 0; j < frame->lines.size(); j++) {
+ _draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_base_color, p_outline_size, p_outline_color, p_font_color_shadow, p_shadow_as_outline, p_shadow_ofs);
}
+ idx++;
}
+ } break;
+ default:
+ break;
+ }
+ }
+ }
- if (underline) {
- Color uc = color;
- uc.a *= 0.5;
- int uy = y + lh - line_descent + font->get_underline_position();
- float underline_width = font->get_underline_thickness();
-#ifdef TOOLS_ENABLED
- underline_width *= EDSCALE;
-#endif
- RS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, underline_width);
- } else if (strikethrough) {
- Color uc = color;
- uc.a *= 0.5;
- int uy = y + lh - (line_ascent + line_descent) / 2;
- float strikethrough_width = font->get_underline_thickness();
-#ifdef TOOLS_ENABLED
- strikethrough_width *= EDSCALE;
-#endif
- RS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, strikethrough_width);
- }
- }
+ const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid);
+ const TextServer::Glyph *glyphs = visual.ptr();
+ int gl_size = visual.size();
- ADVANCE(fw);
- CHECK_HEIGHT(fh); //must be done somewhere
- c = &c[end];
- }
+ Vector2 gloff = off;
+ // Draw oulines and shadow.
+ for (int i = 0; i < gl_size; i++) {
+ Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
+ int size = _find_outline_size(it);
+ Color font_color = _find_outline_color(it, Color(0, 0, 0, 0));
+ if (size <= 0) {
+ gloff.x += glyphs[i].advance;
+ continue;
+ }
- } break;
- case ITEM_IMAGE: {
- lh = 0;
- if (p_mode != PROCESS_CACHE) {
- lh = line < l.height_caches.size() ? l.height_caches[line] : 1;
- } else {
- l.char_count += 1; //images count as chars too
+ // Get FX.
+ ItemFade *fade = nullptr;
+ Item *fade_item = it;
+ while (fade_item) {
+ if (fade_item->type == ITEM_FADE) {
+ fade = static_cast<ItemFade *>(fade_item);
+ break;
}
+ fade_item = fade_item->parent;
+ }
- ItemImage *img = static_cast<ItemImage *>(it);
+ Vector<ItemFX *> fx_stack;
+ _fetch_item_fx_stack(it, fx_stack);
+ bool custom_fx_ok = true;
- Ref<Font> font = _find_font(it);
- if (font.is_null()) {
- font = p_base_font;
+ Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off);
+ RID frid = glyphs[i].font_rid;
+ uint32_t gl = glyphs[i].index;
+
+ //Apply fx.
+ float faded_visibility = 1.0f;
+ if (fade) {
+ if (glyphs[i].start >= fade->starting_index) {
+ faded_visibility -= (float)(glyphs[i].start - fade->starting_index) / (float)fade->length;
+ faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility;
}
+ font_color.a = faded_visibility;
+ }
- if (p_mode == PROCESS_POINTER && r_click_char) {
- *r_click_char = 0;
+ bool visible = (font_color.a != 0);
+
+ for (int j = 0; j < fx_stack.size(); j++) {
+ ItemFX *item_fx = fx_stack[j];
+ if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
+ ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
+
+ Ref<CharFXTransform> charfx = item_custom->char_fx_transform;
+ Ref<RichTextEffect> custom_effect = item_custom->custom_effect;
+
+ if (!custom_effect.is_null()) {
+ charfx->elapsed_time = item_custom->elapsed_time;
+ charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end);
+ charfx->visibility = visible;
+ charfx->outline = true;
+ charfx->font = frid;
+ charfx->glpyh_index = gl;
+ charfx->offset = fx_offset;
+ charfx->color = font_color;
+
+ bool effect_status = custom_effect->_process_effect_impl(charfx);
+ custom_fx_ok = effect_status;
+
+ fx_offset += charfx->offset;
+ font_color = charfx->color;
+ frid = charfx->font;
+ gl = charfx->glpyh_index;
+ visible &= charfx->visibility;
+ }
+ } else if (item_fx->type == ITEM_SHAKE) {
+ ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
+
+ uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
+ uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
+ uint64_t max_rand = 2147483647;
+ double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
+ n_time = (n_time > 1.0) ? 1.0 : n_time;
+ fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
+ } else if (item_fx->type == ITEM_WAVE) {
+ ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
+
+ double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
+ fx_offset += Point2(0, 1) * value;
+ } else if (item_fx->type == ITEM_TORNADO) {
+ ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
+
+ double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
+ double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
+ fx_offset += Point2(torn_x, torn_y);
+ } else if (item_fx->type == ITEM_RAINBOW) {
+ ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
+
+ font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + gloff.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a);
}
+ }
- ENSURE_WIDTH(img->size.width);
+ Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
- bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->size.height, img->size.height));
+ // Draw glyph outlines.
+ for (int j = 0; j < glyphs[i].repeat; j++) {
if (visible) {
- line_is_blank = false;
- }
-
- if (p_mode == PROCESS_DRAW && visible) {
- img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size), false, img->color);
+ if (frid != RID()) {
+ if (p_shadow_as_outline) {
+ TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, shadow_ofs.y), gl, p_font_color_shadow);
+ TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(shadow_ofs.x, -shadow_ofs.y), gl, p_font_color_shadow);
+ TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, -shadow_ofs.y), gl, p_font_color_shadow);
+ }
+ TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff, gl, font_color);
+ }
}
- p_char_count++;
-
- ADVANCE(img->size.width);
- CHECK_HEIGHT((img->size.height + font->get_descent()));
+ gloff.x += glyphs[i].advance;
+ }
+ }
- } break;
- case ITEM_NEWLINE: {
- lh = 0;
+ // Draw main text.
+ Color selection_fg = get_theme_color("font_color_selected");
+ Color selection_bg = get_theme_color("selection_color");
- if (p_mode != PROCESS_CACHE) {
- lh = line < l.height_caches.size() ? l.height_caches[line] : 1;
- line_is_blank = true;
- }
+ int sel_start = -1;
+ int sel_end = -1;
- } break;
- case ITEM_TABLE: {
- lh = 0;
- ItemTable *table = static_cast<ItemTable *>(it);
- int hseparation = get_theme_constant("table_hseparation");
- int vseparation = get_theme_constant("table_vseparation");
- Color ccolor = _find_color(table, p_base_color);
- Vector2 draw_ofs = Point2(wofs, y);
- Color font_color_shadow = get_theme_color("font_color_shadow");
- bool use_outline = get_theme_constant("shadow_as_outline");
- Point2 shadow_ofs2(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
-
- if (p_mode == PROCESS_CACHE) {
- int idx = 0;
- //set minimums to zero
- for (int i = 0; i < table->columns.size(); i++) {
- table->columns.write[i].min_width = 0;
- table->columns.write[i].max_width = 0;
- table->columns.write[i].width = 0;
- }
- //compute minimum width for each cell
- const int available_width = p_width - hseparation * (table->columns.size() - 1) - wofs;
+ if (selection.active && (selection.from_frame->lines[selection.from_line].char_offset + selection.from_char) <= (l.char_offset + TS->shaped_text_get_range(rid).y) && (selection.to_frame->lines[selection.to_line].char_offset + selection.to_char) >= (l.char_offset + TS->shaped_text_get_range(rid).x)) {
+ sel_start = MAX(TS->shaped_text_get_range(rid).x, (selection.from_frame->lines[selection.from_line].char_offset + selection.from_char) - l.char_offset);
+ sel_end = MIN(TS->shaped_text_get_range(rid).y, (selection.to_frame->lines[selection.to_line].char_offset + selection.to_char) - l.char_offset);
- for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
- ERR_CONTINUE(E->get()->type != ITEM_FRAME); //children should all be frames
- ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+ Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_start, sel_end);
+ for (int i = 0; i < sel.size(); i++) {
+ Rect2 rect = Rect2(sel[i].x + p_ofs.x + off.x, p_ofs.y + off.y - TS->shaped_text_get_ascent(rid), sel[i].y - sel[i].x, TS->shaped_text_get_size(rid).y);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_bg);
+ }
+ }
- int column = idx % table->columns.size();
+ for (int i = 0; i < gl_size; i++) {
+ bool selected = selection.active && (sel_start != -1) && (glyphs[i].start >= sel_start) && (glyphs[i].end <= sel_end);
+ Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
+ Color font_color = _find_color(it, p_base_color);
+ if (_find_underline(it) || (_find_meta(it, &meta) && underline_meta)) {
+ Color uc = font_color;
+ uc.a *= 0.5;
+ float y_off = TS->shaped_text_get_underline_position(rid);
+ float underline_width = TS->shaped_text_get_underline_thickness(rid);
+#ifdef TOOLS_ENABLED
+ underline_width *= EDSCALE;
+#endif
+ draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
+ } else if (_find_strikethrough(it)) {
+ Color uc = font_color;
+ uc.a *= 0.5;
+ float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
+ float underline_width = TS->shaped_text_get_underline_thickness(rid);
+#ifdef TOOLS_ENABLED
+ underline_width *= EDSCALE;
+#endif
+ draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
+ }
- int ly = 0;
+ // Get FX.
+ ItemFade *fade = nullptr;
+ Item *fade_item = it;
+ while (fade_item) {
+ if (fade_item->type == ITEM_FADE) {
+ fade = static_cast<ItemFade *>(fade_item);
+ break;
+ }
+ fade_item = fade_item->parent;
+ }
- for (int i = 0; i < frame->lines.size(); i++) {
- _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs2);
- table->columns.write[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width);
- table->columns.write[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width);
- }
- idx++;
- }
+ Vector<ItemFX *> fx_stack;
+ _fetch_item_fx_stack(it, fx_stack);
+ bool custom_fx_ok = true;
- //compute available width and total ratio (for expanders)
+ Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off);
+ RID frid = glyphs[i].font_rid;
+ uint32_t gl = glyphs[i].index;
- int total_ratio = 0;
- int remaining_width = available_width;
- table->total_width = hseparation;
+ //Apply fx.
+ float faded_visibility = 1.0f;
+ if (fade) {
+ if (glyphs[i].start >= fade->starting_index) {
+ faded_visibility -= (float)(glyphs[i].start - fade->starting_index) / (float)fade->length;
+ faded_visibility = faded_visibility < 0.0f ? 0.0f : faded_visibility;
+ }
+ font_color.a = faded_visibility;
+ }
- for (int i = 0; i < table->columns.size(); i++) {
- remaining_width -= table->columns[i].min_width;
- if (table->columns[i].max_width > table->columns[i].min_width) {
- table->columns.write[i].expand = true;
- }
- if (table->columns[i].expand) {
- total_ratio += table->columns[i].expand_ratio;
- }
+ bool visible = (font_color.a != 0);
+
+ for (int j = 0; j < fx_stack.size(); j++) {
+ ItemFX *item_fx = fx_stack[j];
+ if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
+ ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
+
+ Ref<CharFXTransform> charfx = item_custom->char_fx_transform;
+ Ref<RichTextEffect> custom_effect = item_custom->custom_effect;
+
+ if (!custom_effect.is_null()) {
+ charfx->elapsed_time = item_custom->elapsed_time;
+ charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end);
+ charfx->visibility = visible;
+ charfx->outline = false;
+ charfx->font = frid;
+ charfx->glpyh_index = gl;
+ charfx->offset = fx_offset;
+ charfx->color = font_color;
+
+ bool effect_status = custom_effect->_process_effect_impl(charfx);
+ custom_fx_ok = effect_status;
+
+ fx_offset += charfx->offset;
+ font_color = charfx->color;
+ frid = charfx->font;
+ gl = charfx->glpyh_index;
+ visible &= charfx->visibility;
}
+ } else if (item_fx->type == ITEM_SHAKE) {
+ ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
+
+ uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
+ uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
+ uint64_t max_rand = 2147483647;
+ double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
+ n_time = (n_time > 1.0) ? 1.0 : n_time;
+ fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
+ } else if (item_fx->type == ITEM_WAVE) {
+ ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
+
+ double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
+ fx_offset += Point2(0, 1) * value;
+ } else if (item_fx->type == ITEM_TORNADO) {
+ ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
+
+ double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
+ double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
+ fx_offset += Point2(torn_x, torn_y);
+ } else if (item_fx->type == ITEM_RAINBOW) {
+ ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
+
+ font_color = font_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + off.x) / 50)), item_rainbow->saturation, item_rainbow->value, font_color.a);
+ }
+ }
- //assign actual widths
- for (int i = 0; i < table->columns.size(); i++) {
- table->columns.write[i].width = table->columns[i].min_width;
- if (table->columns[i].expand && total_ratio > 0) {
- table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
- }
- table->total_width += table->columns[i].width + hseparation;
- }
+ if (selected) {
+ font_color = override_selected_font_color ? selection_fg : font_color;
+ }
- //resize to max_width if needed and distribute the remaining space
- bool table_need_fit = true;
- while (table_need_fit) {
- table_need_fit = false;
- //fit slim
- for (int i = 0; i < table->columns.size(); i++) {
- if (!table->columns[i].expand) {
- continue;
- }
- int dif = table->columns[i].width - table->columns[i].max_width;
- if (dif > 0) {
- table_need_fit = true;
- table->columns.write[i].width = table->columns[i].max_width;
- table->total_width -= dif;
- total_ratio -= table->columns[i].expand_ratio;
- }
- }
- //grow
- remaining_width = available_width - table->total_width;
- if (remaining_width > 0 && total_ratio > 0) {
- for (int i = 0; i < table->columns.size(); i++) {
- if (table->columns[i].expand) {
- int dif = table->columns[i].max_width - table->columns[i].width;
- if (dif > 0) {
- int slice = table->columns[i].expand_ratio * remaining_width / total_ratio;
- int incr = MIN(dif, slice);
- table->columns.write[i].width += incr;
- table->total_width += incr;
- }
- }
- }
- }
+ // Draw glyphs.
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (visible) {
+ if (frid != RID()) {
+ TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
+ } else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
}
+ }
+ off.x += glyphs[i].advance;
+ }
+ }
+ off.y += TS->shaped_text_get_descent(rid);
+ }
- //compute caches properly again with the right width
- idx = 0;
- for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
- ERR_CONTINUE(E->get()->type != ITEM_FRAME); //children should all be frames
- ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+ return off.y;
+}
- int column = idx % table->columns.size();
+void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside) {
+ if (r_click_item) {
+ *r_click_item = nullptr;
+ }
+ if (r_click_char != nullptr) {
+ *r_click_char = 0;
+ }
+ if (r_outside != nullptr) {
+ *r_outside = true;
+ }
- for (int i = 0; i < frame->lines.size(); i++) {
- int ly = 0;
- _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs2);
- frame->lines.write[i].height_cache = ly; //actual height
- frame->lines.write[i].height_accum_cache = ly; //actual height
- }
- idx++;
- }
- }
+ Size2 size = get_size();
+ Rect2 text_rect = _get_text_rect();
- Point2 offset(align_ofs + hseparation, vseparation);
+ int vofs = vscroll->get_value();
- int row_height = 0;
- //draw using computed caches
- int idx = 0;
- for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
- ERR_CONTINUE(E->get()->type != ITEM_FRAME); //children should all be frames
- ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+ // Search for the first line.
+ int from_line = 0;
- int column = idx % table->columns.size();
+ //TODO, change to binary search ?
+ while (from_line < main->lines.size()) {
+ if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y + _get_text_rect().get_position().y >= vofs) {
+ break;
+ }
+ from_line++;
+ }
- int ly = 0;
- int yofs = 0;
+ if (from_line >= main->lines.size()) {
+ return;
+ }
- int lines_h = frame->lines[frame->lines.size() - 1].height_accum_cache - (frame->lines[0].height_accum_cache - frame->lines[0].height_cache);
- int lines_ofs = p_ofs.y + offset.y + draw_ofs.y;
+ Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
+ while (ofs.y < size.height && from_line < main->lines.size()) {
+ ofs.y += _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
+ if (r_outside != nullptr) {
+ *r_outside = false;
+ }
+ return;
+ }
+ from_line++;
+ }
+}
- bool visible = lines_ofs < get_size().height && lines_ofs + lines_h >= 0;
- if (visible) {
- line_is_blank = false;
- }
+float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char) {
+ Vector2 off;
- for (int i = 0; i < frame->lines.size(); i++) {
- if (visible) {
- if (p_mode == PROCESS_DRAW) {
- nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs2);
- } else if (p_mode == PROCESS_POINTER) {
- _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs2, p_click_pos, r_click_item, r_click_char, r_outside);
- if (r_click_item && *r_click_item) {
- RETURN; // exit early
- }
- }
- }
+ int char_pos = -1;
+ Line &l = p_frame->lines.write[p_line];
+ bool rtl = (l.text_buf->get_direction() == TextServer::DIRECTION_RTL);
+ bool lrtl = is_layout_rtl();
+ bool table_hit = false;
- yofs += frame->lines[i].height_cache;
- if (p_mode == PROCESS_CACHE) {
- frame->lines.write[i].height_accum_cache = offset.y + draw_ofs.y + frame->lines[i].height_cache;
- }
- }
+ for (int line = 0; line < l.text_buf->get_line_count(); line++) {
+ RID rid = l.text_buf->get_line_rid(line);
- row_height = MAX(yofs, row_height);
- offset.x += table->columns[column].width + hseparation;
+ float width = l.text_buf->get_width();
+ float length = TS->shaped_text_get_width(rid);
- if (column == table->columns.size() - 1) {
- offset.y += row_height + vseparation;
- offset.x = hseparation;
- row_height = 0;
- }
- idx++;
- }
+ if (rtl) {
+ off.x = p_width - l.offset.x - width;
+ if (!lrtl && p_frame == main) { // Skip Scrollbar.
+ off.x -= scroll_w;
+ }
+ } else {
+ off.x = l.offset.x;
+ if (lrtl && p_frame == main) { // Skip Scrollbar.
+ off.x += scroll_w;
+ }
+ }
- int total_height = offset.y;
- if (row_height) {
- total_height = row_height + vseparation;
+ switch (l.text_buf->get_align()) {
+ case HALIGN_FILL:
+ case HALIGN_LEFT: {
+ if (rtl) {
+ off.x += width - length;
}
+ } break;
+ case HALIGN_CENTER: {
+ off.x += Math::floor((width - length) / 2.0);
+ } break;
+ case HALIGN_RIGHT: {
+ if (!rtl) {
+ off.x += width - length;
+ }
+ } break;
+ }
- ADVANCE(table->total_width);
- CHECK_HEIGHT(total_height);
+ off.y += TS->shaped_text_get_ascent(rid);
- } break;
+ Array objects = TS->shaped_text_get_objects(rid);
+ for (int i = 0; i < objects.size(); i++) {
+ Item *it = (Item *)(uint64_t)objects[i];
+ if (it != nullptr) {
+ Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]);
+ if (rect.has_point(p_click - p_ofs - off)) {
+ switch (it->type) {
+ case ITEM_TABLE: {
+ int hseparation = get_theme_constant("table_hseparation");
+ int vseparation = get_theme_constant("table_vseparation");
- default: {
- }
- }
+ ItemTable *table = static_cast<ItemTable *>(it);
- Item *itp = it;
+ table_hit = true;
- it = _get_next_item(it);
+ int idx = 0;
+ int col_count = table->columns.size();
+ int row_count = table->rows.size();
- if (it && (p_line + 1 < p_frame->lines.size()) && p_frame->lines[p_line + 1].from == it) {
- if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh) {
- //went to next line, but pointer was on the previous one
- if (r_outside) {
- *r_outside = true;
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+
+ int col = idx % col_count;
+ int row = idx / col_count;
+
+ if (frame->lines.size() != 0 && row < row_count) {
+ Vector2 coff = frame->lines[0].offset;
+ if (rtl) {
+ coff.x = rect.size.width - table->columns[col].width - coff.x;
+ }
+ Rect2 crect = Rect2(p_ofs + off + rect.position + coff - frame->padding.position, Size2(table->columns[col].width + hseparation, table->rows[row] + vseparation) + frame->padding.position + frame->padding.size);
+ if (col == col_count - 1) {
+ if (rtl) {
+ crect.size.x = crect.position.x + crect.size.x;
+ crect.position.x = 0;
+ } else {
+ crect.size.x = get_size().x;
+ }
+ }
+ if (crect.has_point(p_click)) {
+ for (int j = 0; j < frame->lines.size(); j++) {
+ _find_click_in_line(frame, j, p_ofs + off + rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
+ return off.y;
+ }
+ }
+ }
+ }
+ idx++;
+ }
+ } break;
+ default:
+ break;
+ }
}
- *r_click_item = itp;
- *r_click_char = rchar;
- RETURN;
}
+ }
+ Rect2 rect = Rect2(p_ofs + off - Vector2(0, TS->shaped_text_get_ascent(rid)), Size2(get_size().x, TS->shaped_text_get_size(rid).y));
- break;
+ if (rect.has_point(p_click) && !table_hit) {
+ char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
}
+ off.y += TS->shaped_text_get_descent(rid);
}
- NEW_LINE;
- RETURN;
+ if (char_pos >= 0) {
+ // Find item.
+ if (r_click_item != nullptr) {
+ Item *it = p_frame->lines[p_line].from;
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ it = _get_item_at_pos(it, it_to, char_pos);
+ *r_click_item = it;
+ }
+
+ if (r_click_frame != nullptr) {
+ *r_click_frame = p_frame;
+ }
+
+ if (r_click_line != nullptr) {
+ *r_click_line = p_line;
+ }
+
+ if (r_click_char != nullptr) {
+ *r_click_char = char_pos;
+ }
+ }
-#undef RETURN
-#undef NEW_LINE
-#undef ENSURE_WIDTH
-#undef ADVANCE
-#undef CHECK_HEIGHT
+ return off.y;
}
void RichTextLabel::_scroll_changed(double) {
@@ -910,7 +1257,7 @@ void RichTextLabel::_update_scroll() {
vscroll->hide();
}
- main->first_invalid_line = 0; //invalidate ALL
+ main->first_resized_line = 0; //invalidate ALL
_validate_line_caches(main);
}
}
@@ -960,10 +1307,11 @@ void RichTextLabel::_notification(int p_what) {
}
} break;
case NOTIFICATION_RESIZED: {
- main->first_invalid_line = 0; //invalidate ALL
+ main->first_resized_line = 0; //invalidate ALL
update();
} break;
+ case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
if (bbcode != "") {
set_bbcode(bbcode);
@@ -971,11 +1319,11 @@ void RichTextLabel::_notification(int p_what) {
main->first_invalid_line = 0; //invalidate ALL
update();
-
} break;
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
+ case NOTIFICATION_TRANSLATION_CHANGED: {
+ main->first_invalid_line = 0; //invalidate ALL
update();
-
} break;
case NOTIFICATION_DRAW: {
_validate_line_caches(main);
@@ -994,36 +1342,37 @@ void RichTextLabel::_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
}
- int ofs = vscroll->get_value();
-
- //todo, change to binary search
+ float vofs = vscroll->get_value();
+ // Search for the first line.
int from_line = 0;
- int total_chars = 0;
+
+ //TODO, change to binary search ?
while (from_line < main->lines.size()) {
- if (main->lines[from_line].height_accum_cache + _get_text_rect().get_position().y >= ofs) {
+ if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y + _get_text_rect().get_position().y >= vofs) {
break;
}
- total_chars += main->lines[from_line].char_count;
from_line++;
}
if (from_line >= main->lines.size()) {
break; //nothing to draw
}
- int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs;
Ref<Font> base_font = get_theme_font("normal_font");
Color base_color = get_theme_color("default_color");
+ Color outline_color = get_theme_color("outline_color");
+ int outline_size = get_theme_constant("outline_size");
Color font_color_shadow = get_theme_color("font_color_shadow");
bool use_outline = get_theme_constant("shadow_as_outline");
Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
visible_line_count = 0;
- while (y < size.height && from_line < main->lines.size()) {
- visible_line_count++;
- _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), nullptr, nullptr, nullptr, total_chars);
- total_chars += main->lines[from_line].char_count;
+ // New cache draw.
+ Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
+ while (ofs.y < size.height && from_line < main->lines.size()) {
+ visible_line_count++;
+ ofs.y += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_color_shadow, use_outline, shadow_ofs);
from_line++;
}
} break;
@@ -1036,50 +1385,12 @@ void RichTextLabel::_notification(int p_what) {
}
}
-void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item, int *r_click_char, bool *r_outside) {
- if (r_click_item) {
- *r_click_item = nullptr;
- }
-
- Rect2 text_rect = _get_text_rect();
- int ofs = vscroll->get_value();
- Color font_color_shadow = get_theme_color("font_color_shadow");
- bool use_outline = get_theme_constant("shadow_as_outline");
- Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
-
- //todo, change to binary search
- int from_line = 0;
-
- while (from_line < p_frame->lines.size()) {
- if (p_frame->lines[from_line].height_accum_cache >= ofs) {
- break;
- }
- from_line++;
- }
-
- if (from_line >= p_frame->lines.size()) {
- return;
- }
-
- int y = (p_frame->lines[from_line].height_accum_cache - p_frame->lines[from_line].height_cache) - ofs;
- Ref<Font> base_font = get_theme_font("normal_font");
- Color base_color = get_theme_color("default_color");
-
- while (y < text_rect.get_size().height && from_line < p_frame->lines.size()) {
- _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_POINTER, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, p_click, r_click_item, r_click_char, r_outside);
- if (r_click_item && *r_click_item) {
- return;
- }
- from_line++;
- }
-}
-
Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const {
if (!underline_meta) {
return CURSOR_ARROW;
}
- if (selection.click) {
+ if (selection.click_item) {
return CURSOR_IBEAM;
}
@@ -1087,10 +1398,13 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
return CURSOR_ARROW; //invalid
}
- int line = 0;
+ if (main->first_resized_line < main->lines.size()) {
+ return CURSOR_ARROW; //invalid
+ }
+
Item *item = nullptr;
- bool outside;
- ((RichTextLabel *)(this))->_find_click(main, p_pos, &item, &line, &outside);
+ bool outside = true;
+ ((RichTextLabel *)(this))->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside);
if (item && !outside && ((RichTextLabel *)(this))->_find_meta(item, nullptr)) {
return CURSOR_POINTING_HAND;
@@ -1106,27 +1420,37 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
if (main->first_invalid_line < main->lines.size()) {
return;
}
+ if (main->first_resized_line < main->lines.size()) {
+ return;
+ }
if (b->get_button_index() == BUTTON_LEFT) {
if (b->is_pressed() && !b->is_doubleclick()) {
scroll_updated = false;
- int line = 0;
- Item *item = nullptr;
-
+ ItemFrame *c_frame = nullptr;
+ int c_line = 0;
+ Item *c_item = nullptr;
+ int c_index = 0;
bool outside;
- _find_click(main, b->get_position(), &item, &line, &outside);
- if (item) {
+ _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
+ if (c_item != nullptr) {
if (selection.enabled) {
- selection.click = item;
- selection.click_char = line;
+ selection.click_frame = c_frame;
+ selection.click_item = c_item;
+ selection.click_line = c_line;
+ selection.click_char = c_index;
// Erase previous selection.
if (selection.active) {
- selection.from = nullptr;
- selection.from_char = '\0';
- selection.to = nullptr;
- selection.to_char = '\0';
+ selection.from_frame = nullptr;
+ selection.from_line = 0;
+ selection.from_item = nullptr;
+ selection.from_char = 0;
+ selection.to_frame = nullptr;
+ selection.to_line = 0;
+ selection.to_item = nullptr;
+ selection.to_char = 0;
selection.active = false;
update();
@@ -1135,44 +1459,49 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
} else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) {
//doubleclick: select word
- int line = 0;
- Item *item = nullptr;
+
+ ItemFrame *c_frame = nullptr;
+ int c_line = 0;
+ Item *c_item = nullptr;
+ int c_index = 0;
bool outside;
- _find_click(main, b->get_position(), &item, &line, &outside);
+ _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
- while (item && item->type != ITEM_TEXT) {
- item = _get_next_item(item, true);
- }
+ if (c_frame) {
+ const Line &l = c_frame->lines[c_line];
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(l.text_buf->get_rid());
+ for (int i = 0; i < words.size(); i++) {
+ if (c_index >= words[i].x && c_index < words[i].y) {
+ selection.from_frame = c_frame;
+ selection.from_line = c_line;
+ selection.from_item = c_item;
+ selection.from_char = words[i].x;
+
+ selection.to_frame = c_frame;
+ selection.to_line = c_line;
+ selection.to_item = c_item;
+ selection.to_char = words[i].y;
- if (item && item->type == ITEM_TEXT) {
- String itext = static_cast<ItemText *>(item)->text;
-
- int beg, end;
- if (select_word(itext, line, beg, end)) {
- selection.from = item;
- selection.to = item;
- selection.from_char = beg;
- selection.to_char = end - 1;
- selection.active = true;
- update();
+ selection.active = true;
+ update();
+ break;
+ }
}
}
} else if (!b->is_pressed()) {
- selection.click = nullptr;
+ selection.click_item = nullptr;
if (!b->is_doubleclick() && !scroll_updated) {
- int line = 0;
- Item *item = nullptr;
+ Item *c_item = nullptr;
- bool outside;
- _find_click(main, b->get_position(), &item, &line, &outside);
+ bool outside = true;
+ _find_click(main, b->get_position(), nullptr, nullptr, &c_item, nullptr, &outside);
- if (item) {
+ if (c_item) {
Variant meta;
- if (!outside && _find_meta(item, &meta)) {
+ if (!outside && _find_meta(c_item, &meta)) {
//meta clicked
-
emit_signal("meta_clicked", meta);
}
}
@@ -1221,13 +1550,13 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
} break;
case KEY_UP: {
if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height());
+ vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size")));
handled = true;
}
} break;
case KEY_DOWN: {
if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height());
+ vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size")));
handled = true;
}
} break;
@@ -1265,27 +1594,32 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
if (main->first_invalid_line < main->lines.size()) {
return;
}
+ if (main->first_resized_line < main->lines.size()) {
+ return;
+ }
- int line = 0;
- Item *item = nullptr;
+ ItemFrame *c_frame = nullptr;
+ int c_line = 0;
+ Item *c_item = nullptr;
+ int c_index = 0;
bool outside;
- _find_click(main, m->get_position(), &item, &line, &outside);
- if (selection.click) {
- if (!item) {
- return; // do not update
- }
-
- selection.from = selection.click;
+ _find_click(main, m->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
+ if (selection.click_item && c_item) {
+ selection.from_frame = selection.click_frame;
+ selection.from_line = selection.click_line;
+ selection.from_item = selection.click_item;
selection.from_char = selection.click_char;
- selection.to = item;
- selection.to_char = line;
+ selection.to_frame = c_frame;
+ selection.to_line = c_line;
+ selection.to_item = c_item;
+ selection.to_char = c_index;
bool swap = false;
- if (selection.from->index > selection.to->index) {
+ if (selection.from_item->index > selection.to_item->index) {
swap = true;
- } else if (selection.from->index == selection.to->index) {
+ } else if (selection.from_item->index == selection.to_item->index) {
if (selection.from_char > selection.to_char) {
swap = true;
} else if (selection.from_char == selection.to_char) {
@@ -1295,7 +1629,9 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
if (swap) {
- SWAP(selection.from, selection.to);
+ SWAP(selection.from_frame, selection.to_frame);
+ SWAP(selection.from_line, selection.to_line);
+ SWAP(selection.from_item, selection.to_item);
SWAP(selection.from_char, selection.to_char);
}
@@ -1305,7 +1641,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
Variant meta;
ItemMeta *item_meta;
- if (item && !outside && _find_meta(item, &meta, &item_meta)) {
+ if (c_item && !outside && _find_meta(c_item, &meta, &item_meta)) {
if (meta_hovering != item_meta) {
if (meta_hovering) {
emit_signal("meta_hover_ended", current_meta);
@@ -1322,6 +1658,31 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
}
+void RichTextLabel::_find_frame(Item *p_item, ItemFrame **r_frame, int *r_line) {
+ if (r_frame != nullptr) {
+ *r_frame = nullptr;
+ }
+ if (r_line != nullptr) {
+ *r_line = 0;
+ }
+
+ Item *item = p_item;
+
+ while (item) {
+ if (item->parent != nullptr && item->parent->type == ITEM_FRAME) {
+ if (r_frame != nullptr) {
+ *r_frame = (ItemFrame *)item->parent;
+ }
+ if (r_line != nullptr) {
+ *r_line = item->line;
+ }
+ return;
+ }
+
+ item = item->parent;
+ }
+}
+
Ref<Font> RichTextLabel::_find_font(Item *p_item) {
Item *fontitem = p_item;
@@ -1337,10 +1698,103 @@ Ref<Font> RichTextLabel::_find_font(Item *p_item) {
return Ref<Font>();
}
-int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font) {
+int RichTextLabel::_find_font_size(Item *p_item) {
+ Item *sizeitem = p_item;
+
+ while (sizeitem) {
+ if (sizeitem->type == ITEM_FONT_SIZE) {
+ ItemFontSize *fi = static_cast<ItemFontSize *>(sizeitem);
+ return fi->font_size;
+ }
+
+ sizeitem = sizeitem->parent;
+ }
+
+ return -1;
+}
+
+int RichTextLabel::_find_outline_size(Item *p_item) {
+ Item *sizeitem = p_item;
+
+ while (sizeitem) {
+ if (sizeitem->type == ITEM_OUTLINE_SIZE) {
+ ItemOutlineSize *fi = static_cast<ItemOutlineSize *>(sizeitem);
+ return fi->outline_size;
+ }
+
+ sizeitem = sizeitem->parent;
+ }
+
+ return 0;
+}
+
+Dictionary RichTextLabel::_find_font_features(Item *p_item) {
+ Item *ffitem = p_item;
+
+ while (ffitem) {
+ if (ffitem->type == ITEM_FONT_FEATURES) {
+ ItemFontFeatures *fi = static_cast<ItemFontFeatures *>(ffitem);
+ return fi->opentype_features;
+ }
+
+ ffitem = ffitem->parent;
+ }
+
+ return Dictionary();
+}
+
+RichTextLabel::ItemList *RichTextLabel::_find_list_item(Item *p_item) {
Item *item = p_item;
- int margin = 0;
+ while (item) {
+ if (item->type == ITEM_LIST) {
+ return static_cast<ItemList *>(item);
+ }
+ item = item->parent;
+ }
+
+ return nullptr;
+}
+
+int RichTextLabel::_find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list) {
+ Item *item = p_item;
+ Item *prev_item = p_item;
+
+ int level = 0;
+
+ while (item) {
+ if (item->type == ITEM_LIST) {
+ ItemList *list = static_cast<ItemList *>(item);
+
+ ItemFrame *frame = nullptr;
+ int line = -1;
+ _find_frame(list, &frame, &line);
+
+ int index = 1;
+ if (frame != nullptr) {
+ for (int i = list->line + 1; i <= prev_item->line; i++) {
+ if (_find_list_item(frame->lines[i].from) == list) {
+ index++;
+ }
+ }
+ }
+
+ r_index.push_back(index);
+ r_list.push_back(list);
+
+ prev_item = item;
+ }
+ level++;
+ item = item->parent;
+ }
+
+ return level;
+}
+
+int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size) {
+ Item *item = p_item;
+
+ float margin = 0;
while (item) {
if (item->type == ITEM_INDENT) {
@@ -1348,16 +1802,22 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font) {
if (font.is_null()) {
font = p_base_font;
}
-
- ItemIndent *indent = static_cast<ItemIndent *>(item);
-
- margin += indent->level * tab_size * font->get_char_size(' ').width;
+ int font_size = _find_font_size(item);
+ if (font_size == -1) {
+ font_size = p_base_font_size;
+ }
+ margin += tab_size * font->get_char_size('m', 0, font_size).width;
} else if (item->type == ITEM_LIST) {
Ref<Font> font = _find_font(item);
if (font.is_null()) {
font = p_base_font;
}
+ int font_size = _find_font_size(item);
+ if (font_size == -1) {
+ font_size = p_base_font_size;
+ }
+ margin += tab_size * font->get_char_size('m', 0, font_size).width;
}
item = item->parent;
@@ -1370,9 +1830,9 @@ RichTextLabel::Align RichTextLabel::_find_align(Item *p_item) {
Item *item = p_item;
while (item) {
- if (item->type == ITEM_ALIGN) {
- ItemAlign *align = static_cast<ItemAlign *>(item);
- return align->align;
+ if (item->type == ITEM_PARAGRAPH) {
+ ItemParagraph *p = static_cast<ItemParagraph *>(item);
+ return p->align;
}
item = item->parent;
@@ -1381,6 +1841,57 @@ RichTextLabel::Align RichTextLabel::_find_align(Item *p_item) {
return default_align;
}
+TextServer::Direction RichTextLabel::_find_direction(Item *p_item) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_PARAGRAPH) {
+ ItemParagraph *p = static_cast<ItemParagraph *>(item);
+ if (p->direction != Control::TEXT_DIRECTION_INHERITED) {
+ return (TextServer::Direction)p->direction;
+ }
+ }
+
+ item = item->parent;
+ }
+
+ if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
+ return is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR;
+ } else {
+ return (TextServer::Direction)text_direction;
+ }
+}
+
+Control::StructuredTextParser RichTextLabel::_find_stt(Item *p_item) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_PARAGRAPH) {
+ ItemParagraph *p = static_cast<ItemParagraph *>(item);
+ return p->st_parser;
+ }
+
+ item = item->parent;
+ }
+
+ return st_parser;
+}
+
+String RichTextLabel::_find_language(Item *p_item) {
+ Item *item = p_item;
+
+ while (item) {
+ if (item->type == ITEM_PARAGRAPH) {
+ ItemParagraph *p = static_cast<ItemParagraph *>(item);
+ return p->language;
+ }
+
+ item = item->parent;
+ }
+
+ return language;
+}
+
Color RichTextLabel::_find_color(Item *p_item, const Color &p_default_color) {
Item *item = p_item;
@@ -1396,25 +1907,26 @@ Color RichTextLabel::_find_color(Item *p_item, const Color &p_default_color) {
return p_default_color;
}
-bool RichTextLabel::_find_underline(Item *p_item) {
+Color RichTextLabel::_find_outline_color(Item *p_item, const Color &p_default_color) {
Item *item = p_item;
while (item) {
- if (item->type == ITEM_UNDERLINE) {
- return true;
+ if (item->type == ITEM_OUTLINE_COLOR) {
+ ItemOutlineColor *color = static_cast<ItemOutlineColor *>(item);
+ return color->color;
}
item = item->parent;
}
- return false;
+ return p_default_color;
}
-bool RichTextLabel::_find_strikethrough(Item *p_item) {
+bool RichTextLabel::_find_underline(Item *p_item) {
Item *item = p_item;
while (item) {
- if (item->type == ITEM_STRIKETHROUGH) {
+ if (item->type == ITEM_UNDERLINE) {
return true;
}
@@ -1424,17 +1936,17 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) {
return false;
}
-bool RichTextLabel::_find_by_type(Item *p_item, ItemType p_type) {
- ERR_FAIL_INDEX_V((int)p_type, 19, false);
-
+bool RichTextLabel::_find_strikethrough(Item *p_item) {
Item *item = p_item;
while (item) {
- if (item->type == p_type) {
+ if (item->type == ITEM_STRIKETHROUGH) {
return true;
}
+
item = item->parent;
}
+
return false;
}
@@ -1530,38 +2042,67 @@ bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) {
void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
if (p_frame->first_invalid_line == p_frame->lines.size()) {
+ if (p_frame->first_resized_line == p_frame->lines.size()) {
+ return;
+ }
+
+ // Resize lines without reshaping.
+ Size2 size = get_size();
+ if (fixed_width != -1) {
+ size.width = fixed_width;
+ }
+ Rect2 text_rect = _get_text_rect();
+
+ Ref<Font> base_font = get_theme_font("normal_font");
+ int base_font_size = get_theme_font_size("normal_font_size");
+
+ for (int i = p_frame->first_resized_line; i < p_frame->lines.size(); i++) {
+ _resize_line(p_frame, i, base_font, base_font_size, text_rect.get_size().width - scroll_w);
+ }
+
+ int total_height = 0;
+ if (p_frame->lines.size()) {
+ total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height;
+ }
+
+ p_frame->first_resized_line = p_frame->lines.size();
+
+ updating_scroll = true;
+ vscroll->set_max(total_height);
+ vscroll->set_page(size.height);
+ if (scroll_follow && scroll_following) {
+ vscroll->set_value(total_height - size.height);
+ }
+ updating_scroll = false;
+
+ if (fit_content_height) {
+ minimum_size_changed();
+ }
return;
}
- //validate invalid lines
+ // Shape invalid lines.
Size2 size = get_size();
if (fixed_width != -1) {
size.width = fixed_width;
}
Rect2 text_rect = _get_text_rect();
- Color font_color_shadow = get_theme_color("font_color_shadow");
- bool use_outline = get_theme_constant("shadow_as_outline");
- Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
Ref<Font> base_font = get_theme_font("normal_font");
+ int base_font_size = get_theme_font_size("normal_font_size");
+ int total_chars = (p_frame->first_invalid_line == 0) ? 0 : (p_frame->lines[p_frame->first_invalid_line].char_offset + p_frame->lines[p_frame->first_invalid_line].char_count);
for (int i = p_frame->first_invalid_line; i < p_frame->lines.size(); i++) {
- int y = 0;
- _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, i, PROCESS_CACHE, base_font, Color(), font_color_shadow, use_outline, shadow_ofs);
- p_frame->lines.write[i].height_cache = y;
- p_frame->lines.write[i].height_accum_cache = y;
-
- if (i > 0) {
- p_frame->lines.write[i].height_accum_cache += p_frame->lines[i - 1].height_accum_cache;
- }
+ _shape_line(p_frame, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, &total_chars);
}
int total_height = 0;
if (p_frame->lines.size()) {
- total_height = p_frame->lines[p_frame->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height;
+ total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height;
}
- main->first_invalid_line = p_frame->lines.size();
+ p_frame->first_invalid_line = p_frame->lines.size();
+ p_frame->first_resized_line = p_frame->lines.size();
updating_scroll = true;
vscroll->set_max(total_height);
@@ -1569,7 +2110,6 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
if (scroll_follow && scroll_following) {
vscroll->set_value(total_height - size.height);
}
-
updating_scroll = false;
if (fit_content_height) {
@@ -1641,6 +2181,13 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline)
p_item->parent = current;
p_item->E = current->subitems.push_back(p_item);
p_item->index = current_idx++;
+ p_item->char_ofs = current_char_ofs;
+ if (p_item->type == ITEM_TEXT) {
+ ItemText *t = (ItemText *)p_item;
+ current_char_ofs += t->text.length();
+ } else if (p_item->type == ITEM_IMAGE) {
+ current_char_ofs++;
+ }
if (p_enter) {
current = p_item;
@@ -1686,7 +2233,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
}
}
-void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color) {
+void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, VAlign p_align) {
if (current->type == ITEM_TABLE) {
return;
}
@@ -1696,6 +2243,7 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
item->image = p_image;
item->color = p_color;
+ item->inline_align = p_align;
if (p_width > 0) {
// custom width
@@ -1764,7 +2312,7 @@ bool RichTextLabel::remove_line(const int p_line) {
main->lines.write[0].from = main;
}
- main->first_invalid_line = 0;
+ main->first_invalid_line = 0; // p_line ???
return true;
}
@@ -1813,6 +2361,30 @@ void RichTextLabel::push_mono() {
push_font(mono_font);
}
+void RichTextLabel::push_font_size(int p_font_size) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemFontSize *item = memnew(ItemFontSize);
+
+ item->font_size = p_font_size;
+ _add_item(item, true);
+}
+
+void RichTextLabel::push_font_features(const Dictionary &p_features) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemFontFeatures *item = memnew(ItemFontFeatures);
+
+ item->opentype_features = p_features;
+ _add_item(item, true);
+}
+
+void RichTextLabel::push_outline_size(int p_font_size) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemOutlineSize *item = memnew(ItemOutlineSize);
+
+ item->outline_size = p_font_size;
+ _add_item(item, true);
+}
+
void RichTextLabel::push_color(const Color &p_color) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemColor *item = memnew(ItemColor);
@@ -1821,6 +2393,14 @@ void RichTextLabel::push_color(const Color &p_color) {
_add_item(item, true);
}
+void RichTextLabel::push_outline_color(const Color &p_color) {
+ ERR_FAIL_COND(current->type == ITEM_TABLE);
+ ItemOutlineColor *item = memnew(ItemOutlineColor);
+
+ item->color = p_color;
+ _add_item(item, true);
+}
+
void RichTextLabel::push_underline() {
ERR_FAIL_COND(current->type == ITEM_TABLE);
ItemUnderline *item = memnew(ItemUnderline);
@@ -1835,11 +2415,14 @@ void RichTextLabel::push_strikethrough() {
_add_item(item, true);
}
-void RichTextLabel::push_align(Align p_align) {
+void RichTextLabel::push_paragraph(Align p_align, Control::TextDirection p_direction, const String &p_language, Control::StructuredTextParser p_st_parser) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
- ItemAlign *item = memnew(ItemAlign);
+ ItemParagraph *item = memnew(ItemParagraph);
item->align = p_align;
+ item->direction = p_direction;
+ item->language = p_language;
+ item->st_parser = p_st_parser;
_add_item(item, true, true);
}
@@ -1852,13 +2435,15 @@ void RichTextLabel::push_indent(int p_level) {
_add_item(item, true, true);
}
-void RichTextLabel::push_list(ListType p_list) {
+void RichTextLabel::push_list(int p_level, ListType p_list, bool p_capitalize) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
- ERR_FAIL_INDEX(p_list, 3);
+ ERR_FAIL_COND(p_level < 0);
ItemList *item = memnew(ItemList);
item->list_type = p_list;
+ item->level = p_level;
+ item->capitalize = p_capitalize;
_add_item(item, true, true);
}
@@ -1870,17 +2455,18 @@ void RichTextLabel::push_meta(const Variant &p_meta) {
_add_item(item, true);
}
-void RichTextLabel::push_table(int p_columns) {
+void RichTextLabel::push_table(int p_columns, VAlign p_align) {
ERR_FAIL_COND(p_columns < 1);
ItemTable *item = memnew(ItemTable);
item->columns.resize(p_columns);
item->total_width = 0;
+ item->inline_align = p_align;
for (int i = 0; i < item->columns.size(); i++) {
item->columns.write[i].expand = false;
item->columns.write[i].expand_ratio = 1;
}
- _add_item(item, true, true);
+ _add_item(item, true, false);
}
void RichTextLabel::push_fade(int p_start_index, int p_length) {
@@ -1934,6 +2520,36 @@ void RichTextLabel::set_table_column_expand(int p_column, bool p_expand, int p_r
table->columns.write[p_column].expand_ratio = p_ratio;
}
+void RichTextLabel::set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg) {
+ ERR_FAIL_COND(current->type != ITEM_FRAME);
+ ItemFrame *cell = static_cast<ItemFrame *>(current);
+ ERR_FAIL_COND(!cell->cell);
+ cell->odd_row_bg = p_odd_row_bg;
+ cell->even_row_bg = p_even_row_bg;
+}
+
+void RichTextLabel::set_cell_border_color(const Color &p_color) {
+ ERR_FAIL_COND(current->type != ITEM_FRAME);
+ ItemFrame *cell = static_cast<ItemFrame *>(current);
+ ERR_FAIL_COND(!cell->cell);
+ cell->border = p_color;
+}
+
+void RichTextLabel::set_cell_size_override(const Size2 &p_min_size, const Size2 &p_max_size) {
+ ERR_FAIL_COND(current->type != ITEM_FRAME);
+ ItemFrame *cell = static_cast<ItemFrame *>(current);
+ ERR_FAIL_COND(!cell->cell);
+ cell->min_size_over = p_min_size;
+ cell->max_size_over = p_max_size;
+}
+
+void RichTextLabel::set_cell_padding(const Rect2 &p_padding) {
+ ERR_FAIL_COND(current->type != ITEM_FRAME);
+ ItemFrame *cell = static_cast<ItemFrame *>(current);
+ ERR_FAIL_COND(!cell->cell);
+ cell->padding = p_padding;
+}
+
void RichTextLabel::push_cell() {
ERR_FAIL_COND(current->type != ITEM_TABLE);
@@ -1942,10 +2558,9 @@ void RichTextLabel::push_cell() {
_add_item(item, true);
current_frame = item;
item->cell = true;
- item->parent_line = item->parent_frame->lines.size() - 1;
item->lines.resize(1);
item->lines.write[0].from = nullptr;
- item->first_invalid_line = 0;
+ item->first_invalid_line = 0; // parent frame last line ???
}
int RichTextLabel::get_current_table_column() const {
@@ -1972,9 +2587,13 @@ void RichTextLabel::clear() {
main->lines.resize(1);
main->first_invalid_line = 0;
update();
- selection.click = nullptr;
+
+ selection.click_frame = nullptr;
+ selection.click_item = nullptr;
selection.active = false;
+
current_idx = 1;
+ current_char_ofs = 0;
if (scroll_follow) {
scroll_following = true;
}
@@ -1986,7 +2605,7 @@ void RichTextLabel::clear() {
void RichTextLabel::set_tab_size(int p_spaces) {
tab_size = p_spaces;
- main->first_invalid_line = 0;
+ main->first_resized_line = 0;
update();
}
@@ -2135,7 +2754,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
if (tag_stack.front()->get() == "i") {
in_italics = false;
}
- if (tag_stack.front()->get() == "indent") {
+ if ((tag_stack.front()->get() == "indent") || (tag_stack.front()->get() == "ol") || (tag_stack.front()->get() == "ul")) {
indent_level--;
}
@@ -2177,12 +2796,24 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag.begins_with("table=")) {
- int columns = tag.substr(6, tag.length()).to_int();
+ Vector<String> subtag = tag.substr(6, tag.length()).split(",");
+ int columns = subtag[0].to_int();
if (columns < 1) {
columns = 1;
}
- push_table(columns);
+ VAlign align = VALIGN_TOP;
+ if (subtag.size() > 1) {
+ if (subtag[1] == "top" || subtag[1] == "t") {
+ align = VALIGN_TOP;
+ } else if (subtag[1] == "center" || subtag[1] == "c") {
+ align = VALIGN_CENTER;
+ } else if (subtag[1] == "bottom" || subtag[1] == "b") {
+ align = VALIGN_BOTTOM;
+ }
+ }
+
+ push_table(columns, align);
pos = brk_end + 1;
tag_stack.push_front("table");
} else if (tag == "cell") {
@@ -2197,6 +2828,42 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
set_table_column_expand(get_current_table_column(), true, ratio);
push_cell();
+
+ pos = brk_end + 1;
+ tag_stack.push_front("cell");
+ } else if (tag.begins_with("cell ")) {
+ Vector<String> subtag = tag.substr(5, tag.length()).split(" ");
+
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ if (subtag_a[0] == "expand") {
+ int ratio = subtag_a[1].to_int();
+ if (ratio < 1) {
+ ratio = 1;
+ }
+ set_table_column_expand(get_current_table_column(), true, ratio);
+ }
+ }
+ }
+ push_cell();
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ if (subtag_a[0] == "border") {
+ Color color = _get_color_from_string(subtag_a[1], Color(0, 0, 0, 0));
+ set_cell_border_color(color);
+ } else if (subtag_a[0] == "bg") {
+ Vector<String> subtag_b = subtag_a[1].split(",");
+ if (subtag_b.size() == 2) {
+ Color color1 = _get_color_from_string(subtag_b[0], Color(0, 0, 0, 0));
+ Color color2 = _get_color_from_string(subtag_b[1], Color(0, 0, 0, 0));
+ set_cell_row_background_color(color1, color2);
+ }
+ }
+ }
+ }
+
pos = brk_end + 1;
tag_stack.push_front("cell");
} else if (tag == "u") {
@@ -2209,32 +2876,156 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
push_strikethrough();
pos = brk_end + 1;
tag_stack.push_front(tag);
+ } else if (tag == "lrm") {
+ add_text(String::chr(0x200E));
+ pos = brk_end + 1;
+ } else if (tag == "rlm") {
+ add_text(String::chr(0x200F));
+ pos = brk_end + 1;
+ } else if (tag == "lre") {
+ add_text(String::chr(0x202A));
+ pos = brk_end + 1;
+ } else if (tag == "rle") {
+ add_text(String::chr(0x202B));
+ pos = brk_end + 1;
+ } else if (tag == "lro") {
+ add_text(String::chr(0x202D));
+ pos = brk_end + 1;
+ } else if (tag == "rlo") {
+ add_text(String::chr(0x202E));
+ pos = brk_end + 1;
+ } else if (tag == "pdf") {
+ add_text(String::chr(0x202C));
+ pos = brk_end + 1;
+ } else if (tag == "alm") {
+ add_text(String::chr(0x061c));
+ pos = brk_end + 1;
+ } else if (tag == "lri") {
+ add_text(String::chr(0x2066));
+ pos = brk_end + 1;
+ } else if (tag == "rli") {
+ add_text(String::chr(0x2027));
+ pos = brk_end + 1;
+ } else if (tag == "fsi") {
+ add_text(String::chr(0x2068));
+ pos = brk_end + 1;
+ } else if (tag == "pdi") {
+ add_text(String::chr(0x2069));
+ pos = brk_end + 1;
+ } else if (tag == "zwj") {
+ add_text(String::chr(0x200D));
+ pos = brk_end + 1;
+ } else if (tag == "zwnj") {
+ add_text(String::chr(0x200C));
+ pos = brk_end + 1;
+ } else if (tag == "wj") {
+ add_text(String::chr(0x2060));
+ pos = brk_end + 1;
+ } else if (tag == "shy") {
+ add_text(String::chr(0x00AD));
+ pos = brk_end + 1;
} else if (tag == "center") {
- push_align(ALIGN_CENTER);
+ push_paragraph(ALIGN_CENTER);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "fill") {
- push_align(ALIGN_FILL);
+ push_paragraph(ALIGN_FILL);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "right") {
- push_align(ALIGN_RIGHT);
+ push_paragraph(ALIGN_RIGHT);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "ul") {
- push_list(LIST_DOTS);
+ indent_level++;
+ push_list(indent_level, LIST_DOTS, false);
pos = brk_end + 1;
tag_stack.push_front(tag);
- } else if (tag == "ol") {
- push_list(LIST_NUMBERS);
+ } else if ((tag == "ol") || (tag == "ol type=1")) {
+ indent_level++;
+ push_list(indent_level, LIST_NUMBERS, false);
pos = brk_end + 1;
tag_stack.push_front(tag);
+ } else if (tag == "ol type=a") {
+ indent_level++;
+ push_list(indent_level, LIST_LETTERS, false);
+ pos = brk_end + 1;
+ tag_stack.push_front("ol");
+ } else if (tag == "ol type=A") {
+ indent_level++;
+ push_list(indent_level, LIST_LETTERS, true);
+ pos = brk_end + 1;
+ tag_stack.push_front("ol");
+ } else if (tag == "ol type=i") {
+ indent_level++;
+ push_list(indent_level, LIST_ROMAN, false);
+ pos = brk_end + 1;
+ tag_stack.push_front("ol");
+ } else if (tag == "ol type=I") {
+ indent_level++;
+ push_list(indent_level, LIST_ROMAN, true);
+ pos = brk_end + 1;
+ tag_stack.push_front("ol");
} else if (tag == "indent") {
indent_level++;
push_indent(indent_level);
pos = brk_end + 1;
tag_stack.push_front(tag);
-
+ } else if (tag == "p") {
+ push_paragraph(ALIGN_LEFT);
+ pos = brk_end + 1;
+ tag_stack.push_front("p");
+ } else if (tag.begins_with("p ")) {
+ Vector<String> subtag = tag.substr(2, tag.length()).split(" ");
+ Align align = ALIGN_LEFT;
+ Control::TextDirection dir = Control::TEXT_DIRECTION_INHERITED;
+ String lang;
+ Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ if (subtag_a[0] == "align") {
+ if (subtag_a[1] == "l" || subtag_a[1] == "left") {
+ align = ALIGN_LEFT;
+ } else if (subtag_a[1] == "c" || subtag_a[1] == "center") {
+ align = ALIGN_CENTER;
+ } else if (subtag_a[1] == "r" || subtag_a[1] == "right") {
+ align = ALIGN_RIGHT;
+ } else if (subtag_a[1] == "f" || subtag_a[1] == "fill") {
+ align = ALIGN_FILL;
+ }
+ } else if (subtag_a[0] == "dir" || subtag_a[0] == "direction") {
+ if (subtag_a[1] == "a" || subtag_a[1] == "auto") {
+ dir = Control::TEXT_DIRECTION_AUTO;
+ } else if (subtag_a[1] == "l" || subtag_a[1] == "ltr") {
+ dir = Control::TEXT_DIRECTION_LTR;
+ } else if (subtag_a[1] == "r" || subtag_a[1] == "rtl") {
+ dir = Control::TEXT_DIRECTION_RTL;
+ }
+ } else if (subtag_a[0] == "lang" || subtag_a[0] == "language") {
+ lang = subtag_a[1];
+ } else if (subtag_a[0] == "st" || subtag_a[0] == "bidi_override") {
+ if (subtag_a[1] == "d" || subtag_a[1] == "default") {
+ st_parser = STRUCTURED_TEXT_DEFAULT;
+ } else if (subtag_a[1] == "u" || subtag_a[1] == "uri") {
+ st_parser = STRUCTURED_TEXT_URI;
+ } else if (subtag_a[1] == "f" || subtag_a[1] == "file") {
+ st_parser = STRUCTURED_TEXT_FILE;
+ } else if (subtag_a[1] == "e" || subtag_a[1] == "email") {
+ st_parser = STRUCTURED_TEXT_EMAIL;
+ } else if (subtag_a[1] == "l" || subtag_a[1] == "list") {
+ st_parser = STRUCTURED_TEXT_LIST;
+ } else if (subtag_a[1] == "n" || subtag_a[1] == "none") {
+ st_parser = STRUCTURED_TEXT_NONE;
+ } else if (subtag_a[1] == "c" || subtag_a[1] == "custom") {
+ st_parser = STRUCTURED_TEXT_CUSTOM;
+ }
+ }
+ }
+ }
+ push_paragraph(align, dir, lang, st_parser);
+ pos = brk_end + 1;
+ tag_stack.push_front("p");
} else if (tag == "url") {
int end = p_bbcode.find("[", brk_end);
if (end == -1) {
@@ -2251,7 +3042,19 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
push_meta(url);
pos = brk_end + 1;
tag_stack.push_front("url");
- } else if (bbcode_name == "img") {
+ } else if (tag.begins_with("img")) {
+ VAlign align = VALIGN_TOP;
+ if (tag.begins_with("img=")) {
+ String al = tag.substr(4, tag.length());
+ if (al == "top" || al == "t") {
+ align = VALIGN_TOP;
+ } else if (al == "center" || al == "c") {
+ align = VALIGN_CENTER;
+ } else if (al == "bottom" || al == "b") {
+ align = VALIGN_BOTTOM;
+ }
+ }
+
int end = p_bbcode.find("[", brk_end);
if (end == -1) {
end = p_bbcode.length();
@@ -2289,7 +3092,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
}
}
- add_image(texture, width, height, color);
+ add_image(texture, width, height, color, align);
}
pos = end;
@@ -2301,6 +3104,13 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front("color");
+ } else if (tag.begins_with("outline_color=")) {
+ String color_str = tag.substr(14, tag.length());
+ Color color = _get_color_from_string(color_str, base_color);
+ push_outline_color(color);
+ pos = brk_end + 1;
+ tag_stack.push_front("outline_color");
+
} else if (tag.begins_with("font=")) {
String fnt = tag.substr(5, tag.length());
@@ -2313,6 +3123,54 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front("font");
+ } else if (tag.begins_with("font_size=")) {
+ int fnt_size = tag.substr(10, tag.length()).to_int();
+ push_font_size(fnt_size);
+ pos = brk_end + 1;
+ tag_stack.push_front("font_size");
+ } else if (tag.begins_with("opentype_features=")) {
+ String fnt_ftr = tag.substr(18, tag.length());
+ Vector<String> subtag = fnt_ftr.split(",");
+ Dictionary ftrs;
+ for (int i = 0; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=");
+ if (subtag_a.size() == 2) {
+ ftrs[TS->name_to_tag(subtag_a[0])] = subtag_a[1].to_int();
+ } else if (subtag_a.size() == 1) {
+ ftrs[TS->name_to_tag(subtag_a[0])] = 1;
+ }
+ }
+ push_font_features(ftrs);
+ pos = brk_end + 1;
+ tag_stack.push_front("opentype_features");
+ } else if (tag.begins_with("font ")) {
+ Vector<String> subtag = tag.substr(2, tag.length()).split(" ");
+
+ for (int i = 1; i < subtag.size(); i++) {
+ Vector<String> subtag_a = subtag[i].split("=", true, 2);
+ if (subtag_a.size() == 2) {
+ if (subtag_a[0] == "name" || subtag_a[0] == "n") {
+ String fnt = subtag_a[1];
+ Ref<Font> font = ResourceLoader::load(fnt, "Font");
+ if (font.is_valid()) {
+ push_font(font);
+ } else {
+ push_font(normal_font);
+ }
+ } else if (subtag_a[0] == "size" || subtag_a[0] == "s") {
+ int fnt_size = subtag_a[1].to_int();
+ push_font_size(fnt_size);
+ }
+ }
+ }
+
+ pos = brk_end + 1;
+ tag_stack.push_front("font");
+ } else if (tag.begins_with("outline_size=")) {
+ int fnt_size = tag.substr(13, tag.length()).to_int();
+ push_outline_size(fnt_size);
+ pos = brk_end + 1;
+ tag_stack.push_front("outline_size");
} else if (bbcode_name == "fade") {
int start_index = 0;
@@ -2445,7 +3303,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
void RichTextLabel::scroll_to_line(int p_line) {
ERR_FAIL_INDEX(p_line, main->lines.size());
_validate_line_caches(main);
- vscroll->set_value(main->lines[p_line].height_accum_cache - main->lines[p_line].height_cache);
+ vscroll->set_value(main->lines[p_line].offset.y);
}
int RichTextLabel::get_line_count() const {
@@ -2472,95 +3330,160 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) {
}
}
-bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
- ERR_FAIL_COND_V(!selection.enabled, false);
- Item *it = main;
- int charidx = 0;
-
- if (p_from_selection && selection.active) {
- it = selection.to;
- charidx = selection.to_char + 1;
- }
-
- while (it) {
- if (it->type == ITEM_TEXT) {
- ItemText *t = static_cast<ItemText *>(it);
- int sp = t->text.findn(p_string, charidx);
- if (sp != -1) {
- selection.from = it;
- selection.from_char = sp;
- selection.to = it;
- selection.to_char = sp + p_string.length() - 1;
- selection.active = true;
- update();
-
- _validate_line_caches(main);
+bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to) {
+ ERR_FAIL_COND_V(p_frame == nullptr, false);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), false);
- int fh = _find_font(t).is_valid() ? _find_font(t)->get_height() : get_theme_font("normal_font")->get_height();
+ Line &l = p_frame->lines.write[p_line];
- float offset = 0;
+ String text;
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ switch (it->type) {
+ case ITEM_NEWLINE: {
+ text += "\n";
+ } break;
+ case ITEM_TEXT: {
+ ItemText *t = (ItemText *)it;
+ text += t->text;
+ } break;
+ case ITEM_IMAGE: {
+ text += " ";
+ } break;
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ int idx = 0;
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
- int line = t->line;
- Item *item = t;
- while (item) {
- if (item->type == ITEM_FRAME) {
- ItemFrame *frame = static_cast<ItemFrame *>(item);
- if (line >= 0 && line < frame->lines.size()) {
- offset += frame->lines[line].height_accum_cache - frame->lines[line].height_cache;
- line = frame->line;
+ for (int i = 0; i < frame->lines.size(); i++) {
+ if (_search_line(frame, i, p_string, p_from, p_to)) {
+ return true;
}
}
- item = item->parent;
+ idx++;
}
- vscroll->set_value(offset - fh);
+ } break;
+ default:
+ break;
+ }
+ }
+ int sp = text.findn(p_string, 0);
+ if (sp != -1) {
+ selection.from_frame = p_frame;
+ selection.from_line = p_line;
+ selection.from_item = _get_item_at_pos(l.from, it_to, sp);
+ selection.from_char = sp;
+ selection.to_frame = p_frame;
+ selection.to_line = p_line;
+ selection.to_item = _get_item_at_pos(l.from, it_to, sp + p_string.length() - 1);
+ selection.to_char = sp + p_string.length() - 1;
+ selection.active = true;
+ return true;
+ }
+
+ return false;
+}
+bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
+ ERR_FAIL_COND_V(!selection.enabled, false);
+
+ if (p_from_selection && selection.active) {
+ for (int i = 0; i < main->lines.size(); i++) {
+ if (_search_line(main, i, p_string, selection.from_item, selection.to_item)) {
+ update();
return true;
}
}
-
- if (p_search_previous) {
- it = _get_prev_item(it, true);
- } else {
- it = _get_next_item(it, true);
+ } else {
+ for (int i = 0; i < main->lines.size(); i++) {
+ if (_search_line(main, i, p_string, nullptr, nullptr)) {
+ update();
+ return true;
+ }
}
- charidx = 0;
}
return false;
}
-String RichTextLabel::get_selected_text() {
- if (!selection.active || !selection.enabled) {
- return "";
- }
-
+String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) {
String text;
+ ERR_FAIL_COND_V(p_frame == nullptr, text);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), text);
- RichTextLabel::Item *item = selection.from;
-
- while (item) {
- if (item->type == ITEM_TEXT) {
- String itext = static_cast<ItemText *>(item)->text;
- if (item == selection.from && item == selection.to) {
- text += itext.substr(selection.from_char, selection.to_char - selection.from_char + 1);
- } else if (item == selection.from) {
- text += itext.substr(selection.from_char, itext.size());
- } else if (item == selection.to) {
- text += itext.substr(0, selection.to_char + 1);
- } else {
- text += itext;
- }
+ Line &l = p_frame->lines.write[p_line];
- } else if (item->type == ITEM_NEWLINE) {
- text += "\n";
+ Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+ int end_idx = 0;
+ if (it_to != nullptr) {
+ end_idx = it_to->index;
+ } else {
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ end_idx = it->index + 1;
+ }
+ }
+ for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
+ if ((p_selection.to_item != nullptr) && (p_selection.to_item->index < l.from->index)) {
+ break;
}
- if (item == selection.to) {
+ if ((p_selection.from_item != nullptr) && (p_selection.from_item->index >= end_idx)) {
break;
}
+ switch (it->type) {
+ case ITEM_NEWLINE: {
+ text += "\n";
+ } break;
+ case ITEM_TEXT: {
+ ItemText *t = (ItemText *)it;
+ text += t->text;
+ } break;
+ case ITEM_IMAGE: {
+ text += " ";
+ } break;
+ case ITEM_TABLE: {
+ ItemTable *table = static_cast<ItemTable *>(it);
+ int idx = 0;
+ int col_count = table->columns.size();
+ for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
+ ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+ int column = idx % col_count;
+
+ for (int i = 0; i < frame->lines.size(); i++) {
+ text += _get_line_text(frame, i, p_selection);
+ }
+ if (column == col_count - 1) {
+ text += "\n";
+ } else {
+ text += " ";
+ }
+ idx++;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+ if ((l.from != nullptr) && (p_frame == p_selection.to_frame) && (p_selection.to_item != nullptr) && (p_selection.to_item->index >= l.from->index) && (p_selection.to_item->index < end_idx)) {
+ text = text.substr(0, p_selection.to_char);
+ }
+ if ((l.from != nullptr) && (p_frame == p_selection.from_frame) && (p_selection.from_item != nullptr) && (p_selection.from_item->index >= l.from->index) && (p_selection.from_item->index < end_idx)) {
+ text = text.substr(p_selection.from_char, -1);
+ }
+ return text;
+}
- item = _get_next_item(item, true);
+String RichTextLabel::get_selected_text() {
+ if (!selection.active || !selection.enabled) {
+ return "";
}
+ String text;
+ for (int i = 0; i < main->lines.size(); i++) {
+ text += _get_line_text(main, i, selection);
+ }
return text;
}
@@ -2611,7 +3534,7 @@ String RichTextLabel::get_text() {
text += t->text;
} else if (it->type == ITEM_NEWLINE) {
text += "\n";
- } else if (it->type == ITEM_INDENT) {
+ } else if (it->type == ITEM_INDENT || it->type == ITEM_LIST) {
text += "\t";
}
it = _get_next_item(it, true);
@@ -2624,18 +3547,73 @@ void RichTextLabel::set_text(const String &p_string) {
add_text(p_string);
}
-void RichTextLabel::set_percent_visible(float p_percent) {
- if (p_percent < 0 || p_percent >= 1) {
- visible_characters = -1;
- percent_visible = 1;
+void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction) {
+ ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
+ if (text_direction != p_text_direction) {
+ text_direction = p_text_direction;
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
+ }
+}
- } else {
- visible_characters = get_total_character_count() * p_percent;
- percent_visible = p_percent;
+void RichTextLabel::set_structured_text_bidi_override(Control::StructuredTextParser p_parser) {
+ if (st_parser != p_parser) {
+ st_parser = p_parser;
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
}
+}
+
+Control::StructuredTextParser RichTextLabel::get_structured_text_bidi_override() const {
+ return st_parser;
+}
+
+void RichTextLabel::set_structured_text_bidi_override_options(Array p_args) {
+ st_args = p_args;
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
update();
}
+Array RichTextLabel::get_structured_text_bidi_override_options() const {
+ return st_args;
+}
+
+Control::TextDirection RichTextLabel::get_text_direction() const {
+ return text_direction;
+}
+
+void RichTextLabel::set_language(const String &p_language) {
+ if (language != p_language) {
+ language = p_language;
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
+ }
+}
+
+String RichTextLabel::get_language() const {
+ return language;
+}
+
+void RichTextLabel::set_percent_visible(float p_percent) {
+ if (percent_visible != p_percent) {
+ if (p_percent < 0 || p_percent >= 1) {
+ visible_characters = -1;
+ percent_visible = 1;
+
+ } else {
+ visible_characters = get_total_character_count() * p_percent;
+ percent_visible = p_percent;
+ }
+ main->first_invalid_line = 0; //invalidate ALL
+ _validate_line_caches(main);
+ update();
+ }
+}
+
float RichTextLabel::get_percent_visible() const {
return percent_visible;
}
@@ -2671,7 +3649,7 @@ void RichTextLabel::install_effect(const Variant effect) {
int RichTextLabel::get_content_height() const {
int total_height = 0;
if (main->lines.size()) {
- total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height;
+ total_height = main->lines[main->lines.size() - 1].offset.y + main->lines[main->lines.size() - 1].text_buf->get_size().y + get_theme_stylebox("normal")->get_minimum_size().height;
}
return total_height;
}
@@ -2681,29 +3659,46 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
- ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)));
+ ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(VALIGN_TOP));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font);
+ ClassDB::bind_method(D_METHOD("push_font_size", "font_size"), &RichTextLabel::push_font_size);
+ ClassDB::bind_method(D_METHOD("push_font_features", "opentype_features"), &RichTextLabel::push_font_features);
ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal);
ClassDB::bind_method(D_METHOD("push_bold"), &RichTextLabel::push_bold);
ClassDB::bind_method(D_METHOD("push_bold_italics"), &RichTextLabel::push_bold_italics);
ClassDB::bind_method(D_METHOD("push_italics"), &RichTextLabel::push_italics);
ClassDB::bind_method(D_METHOD("push_mono"), &RichTextLabel::push_mono);
ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color);
- ClassDB::bind_method(D_METHOD("push_align", "align"), &RichTextLabel::push_align);
+ ClassDB::bind_method(D_METHOD("push_outline_size", "outline_size"), &RichTextLabel::push_outline_size);
+ ClassDB::bind_method(D_METHOD("push_outline_color", "color"), &RichTextLabel::push_outline_color);
+ ClassDB::bind_method(D_METHOD("push_paragraph", "align", "base_direction", "language", "st_parser"), &RichTextLabel::push_paragraph, DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(""), DEFVAL(STRUCTURED_TEXT_DEFAULT));
ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent);
- ClassDB::bind_method(D_METHOD("push_list", "type"), &RichTextLabel::push_list);
+ ClassDB::bind_method(D_METHOD("push_list", "level", "type", "capitalize"), &RichTextLabel::push_list);
ClassDB::bind_method(D_METHOD("push_meta", "data"), &RichTextLabel::push_meta);
ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline);
ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough);
- ClassDB::bind_method(D_METHOD("push_table", "columns"), &RichTextLabel::push_table);
+ ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(VALIGN_TOP));
ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand);
+ ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color);
+ ClassDB::bind_method(D_METHOD("set_cell_border_color", "color"), &RichTextLabel::set_cell_border_color);
+ ClassDB::bind_method(D_METHOD("set_cell_size_override", "min_size", "max_size"), &RichTextLabel::set_cell_size_override);
+ ClassDB::bind_method(D_METHOD("set_cell_padding", "padding"), &RichTextLabel::set_cell_padding);
ClassDB::bind_method(D_METHOD("push_cell"), &RichTextLabel::push_cell);
ClassDB::bind_method(D_METHOD("pop"), &RichTextLabel::pop);
ClassDB::bind_method(D_METHOD("clear"), &RichTextLabel::clear);
+ ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "parser"), &RichTextLabel::set_structured_text_bidi_override);
+ ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override"), &RichTextLabel::get_structured_text_bidi_override);
+ ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override_options", "args"), &RichTextLabel::set_structured_text_bidi_override_options);
+ ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override_options"), &RichTextLabel::get_structured_text_bidi_override_options);
+ ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &RichTextLabel::set_text_direction);
+ ClassDB::bind_method(D_METHOD("get_text_direction"), &RichTextLabel::get_text_direction);
+ ClassDB::bind_method(D_METHOD("set_language", "language"), &RichTextLabel::set_language);
+ ClassDB::bind_method(D_METHOD("get_language"), &RichTextLabel::get_language);
+
ClassDB::bind_method(D_METHOD("set_meta_underline", "enable"), &RichTextLabel::set_meta_underline);
ClassDB::bind_method(D_METHOD("is_meta_underlined"), &RichTextLabel::is_meta_underlined);
@@ -2778,6 +3773,13 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, "RichTextEffect", (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
+
+ ADD_GROUP("Structured Text", "structured_text_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
+
ADD_SIGNAL(MethodInfo("meta_clicked", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
ADD_SIGNAL(MethodInfo("meta_hover_started", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
ADD_SIGNAL(MethodInfo("meta_hover_ended", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
@@ -2789,6 +3791,7 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(LIST_NUMBERS);
BIND_ENUM_CONSTANT(LIST_LETTERS);
+ BIND_ENUM_CONSTANT(LIST_ROMAN);
BIND_ENUM_CONSTANT(LIST_DOTS);
BIND_ENUM_CONSTANT(ITEM_FRAME);
@@ -2796,10 +3799,14 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(ITEM_IMAGE);
BIND_ENUM_CONSTANT(ITEM_NEWLINE);
BIND_ENUM_CONSTANT(ITEM_FONT);
+ BIND_ENUM_CONSTANT(ITEM_FONT_SIZE);
+ BIND_ENUM_CONSTANT(ITEM_FONT_FEATURES);
BIND_ENUM_CONSTANT(ITEM_COLOR);
+ BIND_ENUM_CONSTANT(ITEM_OUTLINE_SIZE);
+ BIND_ENUM_CONSTANT(ITEM_OUTLINE_COLOR);
BIND_ENUM_CONSTANT(ITEM_UNDERLINE);
BIND_ENUM_CONSTANT(ITEM_STRIKETHROUGH);
- BIND_ENUM_CONSTANT(ITEM_ALIGN);
+ BIND_ENUM_CONSTANT(ITEM_PARAGRAPH);
BIND_ENUM_CONSTANT(ITEM_INDENT);
BIND_ENUM_CONSTANT(ITEM_LIST);
BIND_ENUM_CONSTANT(ITEM_TABLE);
@@ -2929,6 +3936,7 @@ RichTextLabel::RichTextLabel() {
main->lines.resize(1);
main->lines.write[0].from = main;
main->first_invalid_line = 0;
+ main->first_resized_line = 0;
current_frame = main;
tab_size = 4;
default_align = ALIGN_LEFT;
@@ -2954,10 +3962,10 @@ RichTextLabel::RichTextLabel() {
vscroll->connect("value_changed", callable_mp(this, &RichTextLabel::_scroll_changed));
vscroll->set_step(1);
vscroll->hide();
- current_idx = 1;
use_bbcode = false;
- selection.click = nullptr;
+ selection.click_frame = nullptr;
+ selection.click_item = nullptr;
selection.active = false;
selection.enabled = false;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 67a3f466a6..93e48dd449 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -33,6 +33,7 @@
#include "rich_text_effect.h"
#include "scene/gui/scroll_bar.h"
+#include "scene/resources/text_paragraph.h"
class RichTextLabel : public Control {
GDCLASS(RichTextLabel, Control);
@@ -48,6 +49,7 @@ public:
enum ListType {
LIST_NUMBERS,
LIST_LETTERS,
+ LIST_ROMAN,
LIST_DOTS
};
@@ -57,10 +59,14 @@ public:
ITEM_IMAGE,
ITEM_NEWLINE,
ITEM_FONT,
+ ITEM_FONT_SIZE,
+ ITEM_FONT_FEATURES,
ITEM_COLOR,
+ ITEM_OUTLINE_SIZE,
+ ITEM_OUTLINE_COLOR,
ITEM_UNDERLINE,
ITEM_STRIKETHROUGH,
- ITEM_ALIGN,
+ ITEM_PARAGRAPH,
ITEM_INDENT,
ITEM_LIST,
ITEM_TABLE,
@@ -80,31 +86,25 @@ private:
struct Item;
struct Line {
- Item *from;
- Vector<int> offset_caches;
- Vector<int> height_caches;
- Vector<int> ascent_caches;
- Vector<int> descent_caches;
- Vector<int> space_caches;
- int height_cache;
- int height_accum_cache;
- int char_count;
- int minimum_width;
- int maximum_width;
-
- Line() {
- from = nullptr;
- char_count = 0;
- }
+ Item *from = nullptr;
+
+ Ref<TextParagraph> text_buf;
+
+ Vector2 offset;
+ int char_offset = 0;
+ int char_count = 0;
+
+ Line() { text_buf.instance(); }
};
struct Item {
- int index;
- Item *parent;
- ItemType type;
+ int index = 0;
+ int char_ofs = 0;
+ Item *parent = nullptr;
+ ItemType type = ITEM_FRAME;
List<Item *> subitems;
- List<Item *>::Element *E;
- int line;
+ List<Item *>::Element *E = nullptr;
+ int line = 0;
void _clear_children() {
while (subitems.size()) {
@@ -113,29 +113,26 @@ private:
}
}
- Item() {
- parent = nullptr;
- E = nullptr;
- line = 0;
- index = 0;
- type = ITEM_FRAME;
- }
virtual ~Item() { _clear_children(); }
};
struct ItemFrame : public Item {
- int parent_line;
- bool cell;
+ bool cell = false;
+
Vector<Line> lines;
- int first_invalid_line;
- ItemFrame *parent_frame;
-
- ItemFrame() {
- type = ITEM_FRAME;
- parent_frame = nullptr;
- cell = false;
- parent_line = 0;
- }
+ int first_invalid_line = 0;
+ int first_resized_line = 0;
+
+ ItemFrame *parent_frame = nullptr;
+
+ Color odd_row_bg = Color(0, 0, 0, 0);
+ Color even_row_bg = Color(0, 0, 0, 0);
+ Color border = Color(0, 0, 0, 0);
+ Size2 min_size_over = Size2(-1, -1);
+ Size2 max_size_over = Size2(-1, -1);
+ Rect2 padding;
+
+ ItemFrame() { type = ITEM_FRAME; }
};
struct ItemText : public Item {
@@ -145,6 +142,7 @@ private:
struct ItemImage : public Item {
Ref<Texture2D> image;
+ VAlign inline_align = VALIGN_TOP;
Size2 size;
Color color;
ItemImage() { type = ITEM_IMAGE; }
@@ -155,11 +153,31 @@ private:
ItemFont() { type = ITEM_FONT; }
};
+ struct ItemFontSize : public Item {
+ int font_size = 16;
+ ItemFontSize() { type = ITEM_FONT_SIZE; }
+ };
+
+ struct ItemFontFeatures : public Item {
+ Dictionary opentype_features;
+ ItemFontFeatures() { type = ITEM_FONT_FEATURES; }
+ };
+
struct ItemColor : public Item {
Color color;
ItemColor() { type = ITEM_COLOR; }
};
+ struct ItemOutlineSize : public Item {
+ int outline_size = 0;
+ ItemOutlineSize() { type = ITEM_OUTLINE_SIZE; }
+ };
+
+ struct ItemOutlineColor : public Item {
+ Color color;
+ ItemOutlineColor() { type = ITEM_OUTLINE_COLOR; }
+ };
+
struct ItemUnderline : public Item {
ItemUnderline() { type = ITEM_UNDERLINE; }
};
@@ -173,18 +191,23 @@ private:
ItemMeta() { type = ITEM_META; }
};
- struct ItemAlign : public Item {
- Align align;
- ItemAlign() { type = ITEM_ALIGN; }
+ struct ItemParagraph : public Item {
+ Align align = ALIGN_LEFT;
+ String language;
+ Control::TextDirection direction = Control::TEXT_DIRECTION_AUTO;
+ Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+ ItemParagraph() { type = ITEM_PARAGRAPH; }
};
struct ItemIndent : public Item {
- int level;
+ int level = 0;
ItemIndent() { type = ITEM_INDENT; }
};
struct ItemList : public Item {
- ListType list_type;
+ ListType list_type = LIST_DOTS;
+ bool capitalize = false;
+ int level = 0;
ItemList() { type = ITEM_LIST; }
};
@@ -202,37 +225,32 @@ private:
};
Vector<Column> columns;
- int total_width;
+ Vector<float> rows;
+
+ int total_width = 0;
+ int total_height = 0;
+ VAlign inline_align = VALIGN_TOP;
ItemTable() { type = ITEM_TABLE; }
};
struct ItemFade : public Item {
- int starting_index;
- int length;
+ int starting_index = 0;
+ int length = 0;
ItemFade() { type = ITEM_FADE; }
};
struct ItemFX : public Item {
- float elapsed_time;
-
- ItemFX() {
- elapsed_time = 0.0f;
- }
+ float elapsed_time = 0.f;
};
struct ItemShake : public ItemFX {
- int strength;
- float rate;
- uint64_t _current_rng;
- uint64_t _previous_rng;
-
- ItemShake() {
- strength = 0;
- rate = 0.0f;
- _current_rng = 0;
- type = ITEM_SHAKE;
- }
+ int strength = 0;
+ float rate = 0.0f;
+ uint64_t _current_rng = 0;
+ uint64_t _previous_rng = 0;
+
+ ItemShake() { type = ITEM_SHAKE; }
void reroll_random() {
_previous_rng = _current_rng;
@@ -251,38 +269,25 @@ private:
};
struct ItemWave : public ItemFX {
- float frequency;
- float amplitude;
+ float frequency = 1.0f;
+ float amplitude = 1.0f;
- ItemWave() {
- frequency = 1.0f;
- amplitude = 1.0f;
- type = ITEM_WAVE;
- }
+ ItemWave() { type = ITEM_WAVE; }
};
struct ItemTornado : public ItemFX {
- float radius;
- float frequency;
+ float radius = 1.0f;
+ float frequency = 1.0f;
- ItemTornado() {
- radius = 1.0f;
- frequency = 1.0f;
- type = ITEM_TORNADO;
- }
+ ItemTornado() { type = ITEM_TORNADO; }
};
struct ItemRainbow : public ItemFX {
- float saturation;
- float value;
- float frequency;
-
- ItemRainbow() {
- saturation = 0.8f;
- value = 0.8f;
- frequency = 1.0f;
- type = ITEM_RAINBOW;
- }
+ float saturation = 0.8f;
+ float value = 0.8f;
+ float frequency = 1.0f;
+
+ ItemRainbow() { type = ITEM_RAINBOW; }
};
struct ItemCustomFX : public ItemFX {
@@ -291,7 +296,6 @@ private:
ItemCustomFX() {
type = ITEM_CUSTOMFX;
-
char_fx_transform.instance();
}
@@ -316,7 +320,8 @@ private:
int scroll_w;
bool scroll_updated;
bool updating_scroll;
- int current_idx;
+ int current_idx = 1;
+ int current_char_ofs = 0;
int visible_line_count;
int tab_size;
@@ -336,23 +341,25 @@ private:
void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false);
void _remove_item(Item *p_item, const int p_line, const int p_subitem_line);
- struct ProcessState {
- int line_width;
- };
-
- enum ProcessMode {
- PROCESS_CACHE,
- PROCESS_DRAW,
- PROCESS_POINTER
- };
+ String language;
+ TextDirection text_direction = TEXT_DIRECTION_AUTO;
+ Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+ Array st_args;
struct Selection {
- Item *click;
+ ItemFrame *click_frame;
+ int click_line;
+ Item *click_item;
int click_char;
- Item *from;
+ ItemFrame *from_frame;
+ int from_line;
+ Item *from_item;
int from_char;
- Item *to;
+
+ ItemFrame *to_frame;
+ int to_line;
+ Item *to_item;
int to_char;
bool active; // anything selected? i.e. from, to, etc. valid?
@@ -364,18 +371,38 @@ private:
int visible_characters;
float percent_visible;
- int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr, int p_char_count = 0);
- void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
+ void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
+
+ String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel);
+ bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to);
+
+ void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
+ void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width);
+ float _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs);
+ float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr);
+
+ String _roman(int p_num, bool p_capitalize) const;
+ String _letters(int p_num, bool p_capitalize) const;
+ Item *_get_item_at_pos(Item *p_item_from, Item *p_item_to, int p_position);
+ void _find_frame(Item *p_item, ItemFrame **r_frame, int *r_line);
Ref<Font> _find_font(Item *p_item);
- int _find_margin(Item *p_item, const Ref<Font> &p_base_font);
+ int _find_font_size(Item *p_item);
+ Dictionary _find_font_features(Item *p_item);
+ int _find_outline_size(Item *p_item);
+ ItemList *_find_list_item(Item *p_item);
+ int _find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list);
+ int _find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size);
Align _find_align(Item *p_item);
+ TextServer::Direction _find_direction(Item *p_item);
+ Control::StructuredTextParser _find_stt(Item *p_item);
+ String _find_language(Item *p_item);
Color _find_color(Item *p_item, const Color &p_default_color);
+ Color _find_outline_color(Item *p_item, const Color &p_default_color);
bool _find_underline(Item *p_item);
bool _find_strikethrough(Item *p_item);
bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = nullptr);
bool _find_layout_subitem(Item *from, Item *to);
- bool _find_by_type(Item *p_item, ItemType p_type);
void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack);
static Color _get_color_from_string(const String &p_color_str, const Color &p_default_color);
@@ -395,8 +422,6 @@ private:
bool use_bbcode;
String bbcode;
- void _update_all_lines();
-
int fixed_width;
bool fit_content_height;
@@ -407,23 +432,27 @@ protected:
public:
String get_text();
void add_text(const String &p_text);
- void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0));
+ void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), VAlign p_align = VALIGN_TOP);
void add_newline();
bool remove_line(const int p_line);
void push_font(const Ref<Font> &p_font);
+ void push_font_size(int p_font_size);
+ void push_font_features(const Dictionary &p_features);
+ void push_outline_size(int p_font_size);
void push_normal();
void push_bold();
void push_bold_italics();
void push_italics();
void push_mono();
void push_color(const Color &p_color);
+ void push_outline_color(const Color &p_color);
void push_underline();
void push_strikethrough();
- void push_align(Align p_align);
+ void push_paragraph(Align p_align, Control::TextDirection p_direction = Control::TEXT_DIRECTION_INHERITED, const String &p_language = "", Control::StructuredTextParser p_st_parser = STRUCTURED_TEXT_DEFAULT);
void push_indent(int p_level);
- void push_list(ListType p_list);
+ void push_list(int p_level, ListType p_list, bool p_capitalize);
void push_meta(const Variant &p_meta);
- void push_table(int p_columns);
+ void push_table(int p_columns, VAlign p_align = VALIGN_TOP);
void push_fade(int p_start_index, int p_length);
void push_shake(int p_strength, float p_rate);
void push_wave(float p_frequency, float p_amplitude);
@@ -431,6 +460,10 @@ public:
void push_rainbow(float p_saturation, float p_value, float p_frequency);
void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment);
void set_table_column_expand(int p_column, bool p_expand, int p_ratio = 1);
+ void set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg);
+ void set_cell_border_color(const Color &p_color);
+ void set_cell_size_override(const Size2 &p_min_size, const Size2 &p_max_size);
+ void set_cell_padding(const Rect2 &p_padding);
int get_current_table_column() const;
void push_cell();
void pop();
@@ -485,6 +518,18 @@ public:
void set_text(const String &p_string);
+ void set_text_direction(TextDirection p_text_direction);
+ TextDirection get_text_direction() const;
+
+ void set_language(const String &p_language);
+ String get_language() const;
+
+ void set_structured_text_bidi_override(Control::StructuredTextParser p_parser);
+ Control::StructuredTextParser get_structured_text_bidi_override() const;
+
+ void set_structured_text_bidi_override_options(Array p_args);
+ Array get_structured_text_bidi_override_options() const;
+
void set_visible_characters(int p_visible);
int get_visible_characters() const;
int get_total_character_count() const;
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 9340d98ede..70de63fd40 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -449,18 +449,6 @@ double ScrollBar::get_area_offset() const {
return ofs;
}
-double ScrollBar::get_click_pos(const Point2 &p_pos) const {
- float pos = (orientation == VERTICAL) ? p_pos.y : p_pos.x;
- pos -= get_area_offset();
-
- float area = get_area_size();
- if (area == 0) {
- return 0;
- } else {
- return pos / area;
- }
-}
-
double ScrollBar::get_grabber_offset() const {
return (get_area_size()) * get_as_ratio();
}
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index 75f5ad1647..358ed74965 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -61,7 +61,6 @@ class ScrollBar : public Range {
double get_grabber_min_size() const;
double get_area_size() const;
double get_area_offset() const;
- double get_click_pos(const Point2 &p_pos) const;
double get_grabber_offset() const;
static void set_can_focus_by_default(bool p_can_focus);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 62ccd55e89..3a54ac7443 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -431,6 +431,7 @@ void ScrollContainer::update_scrollbars() {
v_scroll->set_max(min.height);
if (hide_scroll_v) {
+ v_scroll->set_page(size.height);
v_scroll->hide();
scroll.y = 0;
} else {
@@ -446,6 +447,7 @@ void ScrollContainer::update_scrollbars() {
h_scroll->set_max(min.width);
if (hide_scroll_h) {
+ h_scroll->set_page(size.width);
h_scroll->hide();
scroll.x = 0;
} else {
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index d7ca2f66ea..01c1a15b79 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -415,6 +415,11 @@ void TabContainer::_notification(int p_what) {
break;
}
+ if (all_tabs_in_front) {
+ // Draw the tab area.
+ panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
+ }
+
// Draw unselected tabs in back
int x = 0;
int x_current = 0;
@@ -446,8 +451,10 @@ void TabContainer::_notification(int p_what) {
last_tab_cache = index;
}
- // Draw the tab area.
- panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
+ if (!all_tabs_in_front) {
+ // Draw the tab area.
+ panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
+ }
// Draw selected tab in front. only draw selected tab when it's in visible range.
if (tabs.size() > 0 && current - first_tab_cache < tab_widths.size() && current >= first_tab_cache) {
@@ -1017,6 +1024,20 @@ bool TabContainer::are_tabs_visible() const {
return tabs_visible;
}
+void TabContainer::set_all_tabs_in_front(bool p_in_front) {
+ if (p_in_front == all_tabs_in_front) {
+ return;
+ }
+
+ all_tabs_in_front = p_in_front;
+
+ update();
+}
+
+bool TabContainer::is_all_tabs_in_front() const {
+ return all_tabs_in_front;
+}
+
Control *TabContainer::_get_tab(int p_idx) const {
return get_tab_control(p_idx);
}
@@ -1208,6 +1229,8 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tab_align"), &TabContainer::get_tab_align);
ClassDB::bind_method(D_METHOD("set_tabs_visible", "visible"), &TabContainer::set_tabs_visible);
ClassDB::bind_method(D_METHOD("are_tabs_visible"), &TabContainer::are_tabs_visible);
+ ClassDB::bind_method(D_METHOD("set_all_tabs_in_front", "is_front"), &TabContainer::set_all_tabs_in_front);
+ ClassDB::bind_method(D_METHOD("is_all_tabs_in_front"), &TabContainer::is_all_tabs_in_front);
ClassDB::bind_method(D_METHOD("set_tab_title", "tab_idx", "title"), &TabContainer::set_tab_title);
ClassDB::bind_method(D_METHOD("get_tab_title", "tab_idx"), &TabContainer::get_tab_title);
ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabContainer::set_tab_icon);
@@ -1234,6 +1257,7 @@ void TabContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "all_tabs_in_front"), "set_all_tabs_in_front", "is_all_tabs_in_front");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size");
@@ -1253,6 +1277,7 @@ TabContainer::TabContainer() {
previous = 0;
align = ALIGN_CENTER;
tabs_visible = true;
+ all_tabs_in_front = false;
drag_to_rearrange_enabled = false;
tabs_rearrange_group = -1;
use_hidden_tabs_for_min_size = false;
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 2fef606551..91153e5fc3 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -52,6 +52,7 @@ private:
int current;
int previous;
bool tabs_visible;
+ bool all_tabs_in_front;
bool buttons_visible_cache;
bool menu_hovered;
int highlight_arrow;
@@ -94,6 +95,9 @@ public:
void set_tabs_visible(bool p_visible);
bool are_tabs_visible() const;
+ void set_all_tabs_in_front(bool p_is_front);
+ bool is_all_tabs_in_front() const;
+
void set_tab_title(int p_tab, const String &p_title);
String get_tab_title(int p_tab) const;
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 06e55deacb..5b26428e45 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -153,7 +153,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
if (cb_hover != -1) {
//pressed
- emit_signal("tab_close", cb_hover);
+ emit_signal("tab_closed", cb_hover);
}
cb_pressing = false;
@@ -641,7 +641,7 @@ void Tabs::_update_hover() {
}
if (hover != hover_now) {
hover = hover_now;
- emit_signal("tab_hover", hover);
+ emit_signal("tab_hovered", hover);
}
if (hover_buttons == -1) { // no hover
@@ -1114,8 +1114,8 @@ void Tabs::_bind_methods() {
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("right_button_pressed", PropertyInfo(Variant::INT, "tab")));
- ADD_SIGNAL(MethodInfo("tab_close", PropertyInfo(Variant::INT, "tab")));
- ADD_SIGNAL(MethodInfo("tab_hover", PropertyInfo(Variant::INT, "tab")));
+ ADD_SIGNAL(MethodInfo("tab_closed", PropertyInfo(Variant::INT, "tab")));
+ ADD_SIGNAL(MethodInfo("tab_hovered", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("reposition_active_tab_request", PropertyInfo(Variant::INT, "idx_to")));
ADD_SIGNAL(MethodInfo("tab_clicked", PropertyInfo(Variant::INT, "tab")));
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index b9818e139f..f3569f9ce3 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1141,7 +1141,7 @@ void TextEdit::_notification(int p_what) {
// Draw line.
RID rid = ldata->get_line_rid(line_wrap_index);
- float text_height = TS->shaped_text_get_size(rid).y;
+ float text_height = TS->shaped_text_get_size(rid).y + cache.font->get_spacing(Font::SPACING_TOP) + cache.font->get_spacing(Font::SPACING_BOTTOM);
if (rtl) {
char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x;
@@ -1240,10 +1240,13 @@ void TextEdit::_notification(int p_what) {
ofs_y += (row_height - text_height) / 2;
- const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(rid);
+ const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid);
+ const TextServer::Glyph *glyphs = visual.ptr();
+ int gl_size = visual.size();
+
ofs_y += ldata->get_line_ascent(line_wrap_index);
float char_ofs = 0.f;
- for (int j = 0; j < glyphs.size(); j++) {
+ for (int j = 0; j < gl_size; j++) {
if (color_map.has(glyphs[j].start)) {
current_color = color_map[glyphs[j].start].get("color");
if (readonly && current_color.a > cache.font_color_readonly.a) {
@@ -1647,20 +1650,23 @@ void TextEdit::_notification(int p_what) {
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + _get_cursor_pixel_pos(), get_viewport()->get_window_id());
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + _get_cursor_pixel_pos(false), get_viewport()->get_window_id());
}
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
- String text = _base_get_text(0, 0, selection.selecting_line, selection.selecting_column);
- int cursor_start = text.length();
+ int cursor_start = -1;
int cursor_end = -1;
- if (selection.active) {
- String selected_text = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ if (!selection.active) {
+ String full_text = _base_get_text(0, 0, cursor.line, cursor.column);
- if (selected_text.length() > 0) {
- cursor_end = cursor_start + selected_text.length();
- }
+ cursor_start = full_text.length();
+ } else {
+ String pre_text = _base_get_text(0, 0, selection.from_line, selection.from_column);
+ String post_text = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+
+ cursor_start = pre_text.length();
+ cursor_end = cursor_start + post_text.length();
}
DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true, -1, cursor_start, cursor_end);
@@ -2069,8 +2075,10 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
r_col = col;
}
-Vector2i TextEdit::_get_cursor_pixel_pos() {
- adjust_viewport_to_cursor();
+Vector2i TextEdit::_get_cursor_pixel_pos(bool p_adjust_viewport) {
+ if (p_adjust_viewport) {
+ adjust_viewport_to_cursor();
+ }
int row = 1;
for (int i = get_first_visible_line(); i < cursor.line; i++) {
if (!is_line_hidden(i)) {
@@ -6616,8 +6624,8 @@ void TextEdit::set_line_length_guideline_hard_column(int p_column) {
}
void TextEdit::set_draw_minimap(bool p_draw) {
- draw_minimap = p_draw;
if (draw_minimap != p_draw) {
+ draw_minimap = p_draw;
_update_wrap_at();
}
update();
@@ -6628,8 +6636,8 @@ bool TextEdit::is_drawing_minimap() const {
}
void TextEdit::set_minimap_width(int p_minimap_width) {
- minimap_width = p_minimap_width;
if (minimap_width != p_minimap_width) {
+ minimap_width = p_minimap_width;
_update_wrap_at();
}
update();
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index c2fe4afec5..3f16ed1366 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -700,7 +700,7 @@ public:
int cursor_get_column() const;
int cursor_get_line() const;
- Vector2i _get_cursor_pixel_pos();
+ Vector2i _get_cursor_pixel_pos(bool p_adjust_viewport = true);
bool cursor_get_blink_enabled() const;
void cursor_set_blink_enabled(const bool p_enabled);
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress_bar.cpp
index e0d98d1c22..b5115690ac 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* texture_progress.cpp */
+/* texture_progress_bar.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,21 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "texture_progress.h"
+#include "texture_progress_bar.h"
#include "core/config/engine.h"
-void TextureProgress::set_under_texture(const Ref<Texture2D> &p_texture) {
+void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) {
under = p_texture;
update();
minimum_size_changed();
}
-Ref<Texture2D> TextureProgress::get_under_texture() const {
+Ref<Texture2D> TextureProgressBar::get_under_texture() const {
return under;
}
-void TextureProgress::set_over_texture(const Ref<Texture2D> &p_texture) {
+void TextureProgressBar::set_over_texture(const Ref<Texture2D> &p_texture) {
over = p_texture;
update();
if (under.is_null()) {
@@ -50,33 +50,33 @@ void TextureProgress::set_over_texture(const Ref<Texture2D> &p_texture) {
}
}
-Ref<Texture2D> TextureProgress::get_over_texture() const {
+Ref<Texture2D> TextureProgressBar::get_over_texture() const {
return over;
}
-void TextureProgress::set_stretch_margin(Margin p_margin, int p_size) {
+void TextureProgressBar::set_stretch_margin(Margin p_margin, int p_size) {
ERR_FAIL_INDEX((int)p_margin, 4);
stretch_margin[p_margin] = p_size;
update();
minimum_size_changed();
}
-int TextureProgress::get_stretch_margin(Margin p_margin) const {
+int TextureProgressBar::get_stretch_margin(Margin p_margin) const {
ERR_FAIL_INDEX_V((int)p_margin, 4, 0);
return stretch_margin[p_margin];
}
-void TextureProgress::set_nine_patch_stretch(bool p_stretch) {
+void TextureProgressBar::set_nine_patch_stretch(bool p_stretch) {
nine_patch_stretch = p_stretch;
update();
minimum_size_changed();
}
-bool TextureProgress::get_nine_patch_stretch() const {
+bool TextureProgressBar::get_nine_patch_stretch() const {
return nine_patch_stretch;
}
-Size2 TextureProgress::get_minimum_size() const {
+Size2 TextureProgressBar::get_minimum_size() const {
if (nine_patch_stretch) {
return Size2(stretch_margin[MARGIN_LEFT] + stretch_margin[MARGIN_RIGHT], stretch_margin[MARGIN_TOP] + stretch_margin[MARGIN_BOTTOM]);
} else if (under.is_valid()) {
@@ -90,44 +90,44 @@ Size2 TextureProgress::get_minimum_size() const {
return Size2(1, 1);
}
-void TextureProgress::set_progress_texture(const Ref<Texture2D> &p_texture) {
+void TextureProgressBar::set_progress_texture(const Ref<Texture2D> &p_texture) {
progress = p_texture;
update();
minimum_size_changed();
}
-Ref<Texture2D> TextureProgress::get_progress_texture() const {
+Ref<Texture2D> TextureProgressBar::get_progress_texture() const {
return progress;
}
-void TextureProgress::set_tint_under(const Color &p_tint) {
+void TextureProgressBar::set_tint_under(const Color &p_tint) {
tint_under = p_tint;
update();
}
-Color TextureProgress::get_tint_under() const {
+Color TextureProgressBar::get_tint_under() const {
return tint_under;
}
-void TextureProgress::set_tint_progress(const Color &p_tint) {
+void TextureProgressBar::set_tint_progress(const Color &p_tint) {
tint_progress = p_tint;
update();
}
-Color TextureProgress::get_tint_progress() const {
+Color TextureProgressBar::get_tint_progress() const {
return tint_progress;
}
-void TextureProgress::set_tint_over(const Color &p_tint) {
+void TextureProgressBar::set_tint_over(const Color &p_tint) {
tint_over = p_tint;
update();
}
-Color TextureProgress::get_tint_over() const {
+Color TextureProgressBar::get_tint_over() const {
return tint_over;
}
-Point2 TextureProgress::unit_val_to_uv(float val) {
+Point2 TextureProgressBar::unit_val_to_uv(float val) {
if (progress.is_null()) {
return Point2();
}
@@ -191,7 +191,7 @@ Point2 TextureProgress::unit_val_to_uv(float val) {
return (p + t1 * dir);
}
-Point2 TextureProgress::get_relative_center() {
+Point2 TextureProgressBar::get_relative_center() {
if (progress.is_null()) {
return Point2();
}
@@ -204,7 +204,7 @@ Point2 TextureProgress::get_relative_center() {
return p;
}
-void TextureProgress::draw_nine_patch_stretched(const Ref<Texture2D> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate) {
+void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate) {
Vector2 texture_size = p_texture->get_size();
Vector2 topleft = Vector2(stretch_margin[MARGIN_LEFT], stretch_margin[MARGIN_TOP]);
Vector2 bottomright = Vector2(stretch_margin[MARGIN_RIGHT], stretch_margin[MARGIN_BOTTOM]);
@@ -306,7 +306,7 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture2D> &p_texture,
RS::get_singleton()->canvas_item_add_nine_patch(ci, dst_rect, src_rect, p_texture->get_rid(), topleft, bottomright, RS::NINE_PATCH_STRETCH, RS::NINE_PATCH_STRETCH, true, p_modulate);
}
-void TextureProgress::_notification(int p_what) {
+void TextureProgressBar::_notification(int p_what) {
const float corners[12] = { -0.125, -0.375, -0.625, -0.875, 0.125, 0.375, 0.625, 0.875, 1.125, 1.375, 1.625, 1.875 };
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -428,17 +428,17 @@ void TextureProgress::_notification(int p_what) {
}
}
-void TextureProgress::set_fill_mode(int p_fill) {
+void TextureProgressBar::set_fill_mode(int p_fill) {
ERR_FAIL_INDEX(p_fill, 9);
mode = (FillMode)p_fill;
update();
}
-int TextureProgress::get_fill_mode() {
+int TextureProgressBar::get_fill_mode() {
return mode;
}
-void TextureProgress::set_radial_initial_angle(float p_angle) {
+void TextureProgressBar::set_radial_initial_angle(float p_angle) {
while (p_angle > 360) {
p_angle -= 360;
}
@@ -449,64 +449,64 @@ void TextureProgress::set_radial_initial_angle(float p_angle) {
update();
}
-float TextureProgress::get_radial_initial_angle() {
+float TextureProgressBar::get_radial_initial_angle() {
return rad_init_angle;
}
-void TextureProgress::set_fill_degrees(float p_angle) {
+void TextureProgressBar::set_fill_degrees(float p_angle) {
rad_max_degrees = CLAMP(p_angle, 0, 360);
update();
}
-float TextureProgress::get_fill_degrees() {
+float TextureProgressBar::get_fill_degrees() {
return rad_max_degrees;
}
-void TextureProgress::set_radial_center_offset(const Point2 &p_off) {
+void TextureProgressBar::set_radial_center_offset(const Point2 &p_off) {
rad_center_off = p_off;
update();
}
-Point2 TextureProgress::get_radial_center_offset() {
+Point2 TextureProgressBar::get_radial_center_offset() {
return rad_center_off;
}
-void TextureProgress::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_under_texture", "tex"), &TextureProgress::set_under_texture);
- ClassDB::bind_method(D_METHOD("get_under_texture"), &TextureProgress::get_under_texture);
+void TextureProgressBar::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_under_texture", "tex"), &TextureProgressBar::set_under_texture);
+ ClassDB::bind_method(D_METHOD("get_under_texture"), &TextureProgressBar::get_under_texture);
- ClassDB::bind_method(D_METHOD("set_progress_texture", "tex"), &TextureProgress::set_progress_texture);
- ClassDB::bind_method(D_METHOD("get_progress_texture"), &TextureProgress::get_progress_texture);
+ ClassDB::bind_method(D_METHOD("set_progress_texture", "tex"), &TextureProgressBar::set_progress_texture);
+ ClassDB::bind_method(D_METHOD("get_progress_texture"), &TextureProgressBar::get_progress_texture);
- ClassDB::bind_method(D_METHOD("set_over_texture", "tex"), &TextureProgress::set_over_texture);
- ClassDB::bind_method(D_METHOD("get_over_texture"), &TextureProgress::get_over_texture);
+ ClassDB::bind_method(D_METHOD("set_over_texture", "tex"), &TextureProgressBar::set_over_texture);
+ ClassDB::bind_method(D_METHOD("get_over_texture"), &TextureProgressBar::get_over_texture);
- ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &TextureProgress::set_fill_mode);
- ClassDB::bind_method(D_METHOD("get_fill_mode"), &TextureProgress::get_fill_mode);
+ ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &TextureProgressBar::set_fill_mode);
+ ClassDB::bind_method(D_METHOD("get_fill_mode"), &TextureProgressBar::get_fill_mode);
- ClassDB::bind_method(D_METHOD("set_tint_under", "tint"), &TextureProgress::set_tint_under);
- ClassDB::bind_method(D_METHOD("get_tint_under"), &TextureProgress::get_tint_under);
+ ClassDB::bind_method(D_METHOD("set_tint_under", "tint"), &TextureProgressBar::set_tint_under);
+ ClassDB::bind_method(D_METHOD("get_tint_under"), &TextureProgressBar::get_tint_under);
- ClassDB::bind_method(D_METHOD("set_tint_progress", "tint"), &TextureProgress::set_tint_progress);
- ClassDB::bind_method(D_METHOD("get_tint_progress"), &TextureProgress::get_tint_progress);
+ ClassDB::bind_method(D_METHOD("set_tint_progress", "tint"), &TextureProgressBar::set_tint_progress);
+ ClassDB::bind_method(D_METHOD("get_tint_progress"), &TextureProgressBar::get_tint_progress);
- ClassDB::bind_method(D_METHOD("set_tint_over", "tint"), &TextureProgress::set_tint_over);
- ClassDB::bind_method(D_METHOD("get_tint_over"), &TextureProgress::get_tint_over);
+ ClassDB::bind_method(D_METHOD("set_tint_over", "tint"), &TextureProgressBar::set_tint_over);
+ ClassDB::bind_method(D_METHOD("get_tint_over"), &TextureProgressBar::get_tint_over);
- ClassDB::bind_method(D_METHOD("set_radial_initial_angle", "mode"), &TextureProgress::set_radial_initial_angle);
- ClassDB::bind_method(D_METHOD("get_radial_initial_angle"), &TextureProgress::get_radial_initial_angle);
+ ClassDB::bind_method(D_METHOD("set_radial_initial_angle", "mode"), &TextureProgressBar::set_radial_initial_angle);
+ ClassDB::bind_method(D_METHOD("get_radial_initial_angle"), &TextureProgressBar::get_radial_initial_angle);
- ClassDB::bind_method(D_METHOD("set_radial_center_offset", "mode"), &TextureProgress::set_radial_center_offset);
- ClassDB::bind_method(D_METHOD("get_radial_center_offset"), &TextureProgress::get_radial_center_offset);
+ ClassDB::bind_method(D_METHOD("set_radial_center_offset", "mode"), &TextureProgressBar::set_radial_center_offset);
+ ClassDB::bind_method(D_METHOD("get_radial_center_offset"), &TextureProgressBar::get_radial_center_offset);
- ClassDB::bind_method(D_METHOD("set_fill_degrees", "mode"), &TextureProgress::set_fill_degrees);
- ClassDB::bind_method(D_METHOD("get_fill_degrees"), &TextureProgress::get_fill_degrees);
+ ClassDB::bind_method(D_METHOD("set_fill_degrees", "mode"), &TextureProgressBar::set_fill_degrees);
+ ClassDB::bind_method(D_METHOD("get_fill_degrees"), &TextureProgressBar::get_fill_degrees);
- ClassDB::bind_method(D_METHOD("set_stretch_margin", "margin", "value"), &TextureProgress::set_stretch_margin);
- ClassDB::bind_method(D_METHOD("get_stretch_margin", "margin"), &TextureProgress::get_stretch_margin);
+ ClassDB::bind_method(D_METHOD("set_stretch_margin", "margin", "value"), &TextureProgressBar::set_stretch_margin);
+ ClassDB::bind_method(D_METHOD("get_stretch_margin", "margin"), &TextureProgressBar::get_stretch_margin);
- ClassDB::bind_method(D_METHOD("set_nine_patch_stretch", "stretch"), &TextureProgress::set_nine_patch_stretch);
- ClassDB::bind_method(D_METHOD("get_nine_patch_stretch"), &TextureProgress::get_nine_patch_stretch);
+ ClassDB::bind_method(D_METHOD("set_nine_patch_stretch", "stretch"), &TextureProgressBar::set_nine_patch_stretch);
+ ClassDB::bind_method(D_METHOD("get_nine_patch_stretch"), &TextureProgressBar::get_nine_patch_stretch);
ADD_GROUP("Textures", "texture_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_under_texture", "get_under_texture");
@@ -539,7 +539,7 @@ void TextureProgress::_bind_methods() {
BIND_ENUM_CONSTANT(FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE);
}
-TextureProgress::TextureProgress() {
+TextureProgressBar::TextureProgressBar() {
mode = FILL_LEFT_TO_RIGHT;
rad_init_angle = 0;
rad_center_off = Point2();
diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress_bar.h
index 5e29fca21f..342e719a59 100644
--- a/scene/gui/texture_progress.h
+++ b/scene/gui/texture_progress_bar.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* texture_progress.h */
+/* texture_progress_bar.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TEXTURE_PROGRESS_H
-#define TEXTURE_PROGRESS_H
+#ifndef TEXTURE_PROGRESS_BAR_H
+#define TEXTURE_PROGRESS_BAR_H
#include "scene/gui/range.h"
-class TextureProgress : public Range {
- GDCLASS(TextureProgress, Range);
+class TextureProgressBar : public Range {
+ GDCLASS(TextureProgressBar, Range);
Ref<Texture2D> under;
Ref<Texture2D> progress;
@@ -95,7 +95,7 @@ public:
Size2 get_minimum_size() const override;
- TextureProgress();
+ TextureProgressBar();
private:
FillMode mode;
@@ -111,6 +111,6 @@ private:
void draw_nine_patch_stretched(const Ref<Texture2D> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate);
};
-VARIANT_ENUM_CAST(TextureProgress::FillMode);
+VARIANT_ENUM_CAST(TextureProgressBar::FillMode);
-#endif // TEXTURE_PROGRESS_H
+#endif // TEXTURE_PROGRESS_BAR_H
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 6bd8003ef0..063a5e7ac1 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -597,12 +597,6 @@ String TreeItem::get_button_tooltip(int p_column, int p_idx) const {
return cells[p_column].buttons[p_idx].tooltip;
}
-int TreeItem::get_button_id(int p_column, int p_idx) const {
- ERR_FAIL_INDEX_V(p_column, cells.size(), -1);
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), -1);
- return cells[p_column].buttons[p_idx].id;
-}
-
void TreeItem::erase_button(int p_column, int p_idx) {
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
@@ -4081,10 +4075,6 @@ void Tree::set_cursor_can_exit_tree(bool p_enable) {
cursor_can_exit_tree = p_enable;
}
-bool Tree::can_cursor_exit_tree() const {
- return cursor_can_exit_tree;
-}
-
void Tree::set_hide_folding(bool p_hide) {
hide_folding = p_hide;
update();
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 4c3d03c91a..82422b8be3 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -227,7 +227,6 @@ public:
int get_button_count(int p_column) const;
String get_button_tooltip(int p_column, int p_idx) const;
Ref<Texture2D> get_button(int p_column, int p_idx) const;
- int get_button_id(int p_column, int p_idx) const;
void erase_button(int p_column, int p_idx);
int get_button_by_id(int p_column, int p_id) const;
void set_button(int p_column, int p_idx, const Ref<Texture2D> &p_button);
@@ -633,7 +632,6 @@ public:
void scroll_to_item(TreeItem *p_item);
void set_cursor_can_exit_tree(bool p_enable);
- bool can_cursor_exit_tree() const;
VScrollBar *get_vscroll_bar() { return v_scroll; }
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 6806a55151..43350fae37 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -364,7 +364,7 @@ void CanvasItem::_propagate_visibility_changed(bool p_visible) {
if (p_visible) {
update(); //todo optimize
} else {
- emit_signal(SceneStringNames::get_singleton()->hide);
+ emit_signal(SceneStringNames::get_singleton()->hidden);
}
_block();
@@ -1227,7 +1227,7 @@ void CanvasItem::_bind_methods() {
ADD_SIGNAL(MethodInfo("draw"));
ADD_SIGNAL(MethodInfo("visibility_changed"));
- ADD_SIGNAL(MethodInfo("hide"));
+ ADD_SIGNAL(MethodInfo("hidden"));
ADD_SIGNAL(MethodInfo("item_rect_changed"));
BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
diff --git a/scene/main/node.h b/scene/main/node.h
index 873c27bc13..024d036fd3 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -74,9 +74,8 @@ public:
private:
struct GroupData {
- bool persistent;
- SceneTree::Group *group;
- GroupData() { persistent = false; }
+ bool persistent = false;
+ SceneTree::Group *group = nullptr;
};
struct NetData {
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 9e396d4030..1df61daa2c 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1391,6 +1391,10 @@ SceneTree::SceneTree() {
const bool use_debanding = GLOBAL_DEF("rendering/quality/screen_filters/use_debanding", false);
root->set_use_debanding(use_debanding);
+ float lod_threshold = GLOBAL_DEF("rendering/quality/mesh_lod/threshold_pixels", 1.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/mesh_lod/threshold_pixels", PropertyInfo(Variant::FLOAT, "rendering/quality/mesh_lod/threshold_pixels", PROPERTY_HINT_RANGE, "0,1024,0.1"));
+ root->set_lod_threshold(lod_threshold);
+
bool snap_2d_transforms = GLOBAL_DEF("rendering/quality/2d/snap_2d_transforms_to_pixel", false);
root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 6350777a3d..c96dd4ad35 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2392,19 +2392,19 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) {
- next = from->_get_focus_neighbour(MARGIN_TOP);
+ next = from->_get_focus_neighbor(MARGIN_TOP);
}
if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) {
- next = from->_get_focus_neighbour(MARGIN_LEFT);
+ next = from->_get_focus_neighbor(MARGIN_LEFT);
}
if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) {
- next = from->_get_focus_neighbour(MARGIN_RIGHT);
+ next = from->_get_focus_neighbor(MARGIN_RIGHT);
}
if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) {
- next = from->_get_focus_neighbour(MARGIN_BOTTOM);
+ next = from->_get_focus_neighbor(MARGIN_BOTTOM);
}
if (next) {
@@ -3192,6 +3192,14 @@ bool Viewport::is_using_debanding() const {
return use_debanding;
}
+void Viewport::set_lod_threshold(float p_pixels) {
+ lod_threshold = p_pixels;
+ RS::get_singleton()->viewport_set_lod_threshold(viewport, lod_threshold);
+}
+float Viewport::get_lod_threshold() const {
+ return lod_threshold;
+}
+
void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
debug_draw = p_debug_draw;
RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
@@ -3505,6 +3513,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sdf_scale", "scale"), &Viewport::set_sdf_scale);
ClassDB::bind_method(D_METHOD("get_sdf_scale"), &Viewport::get_sdf_scale);
+ ClassDB::bind_method(D_METHOD("set_lod_threshold", "pixels"), &Viewport::set_lod_threshold);
+ ClassDB::bind_method(D_METHOD("get_lod_threshold"), &Viewport::get_lod_threshold);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
@@ -3516,6 +3527,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa");
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Canvas Items", "canvas_item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
@@ -3590,6 +3602,7 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_SDFGI);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SDFGI_PROBES);
BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_BUFFER);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLE_LOD);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
@@ -3652,6 +3665,8 @@ Viewport::Viewport() {
set_shadow_atlas_quadrant_subdiv(2, SHADOW_ATLAS_QUADRANT_SUBDIV_16);
set_shadow_atlas_quadrant_subdiv(3, SHADOW_ATLAS_QUADRANT_SUBDIV_64);
+ set_lod_threshold(lod_threshold);
+
String id = itos(get_instance_id());
input_group = "_vp_input" + id;
gui_input_group = "_vp_gui_input" + id;
@@ -3824,7 +3839,7 @@ void SubViewport::_bind_methods() {
BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);
BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER);
- BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
+ BIND_ENUM_CONSTANT(CLEAR_MODE_ONCE);
BIND_ENUM_CONSTANT(UPDATE_DISABLED);
BIND_ENUM_CONSTANT(UPDATE_ONCE);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 7ce202d27c..ffbc3c782a 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -142,6 +142,7 @@ public:
DEBUG_DRAW_SDFGI,
DEBUG_DRAW_SDFGI_PROBES,
DEBUG_DRAW_GI_BUFFER,
+ DEBUG_DRAW_DISABLE_LOD,
};
enum DefaultCanvasItemTextureFilter {
@@ -297,6 +298,8 @@ private:
MSAA msaa;
ScreenSpaceAA screen_space_aa;
bool use_debanding = false;
+ float lod_threshold = 1.0;
+
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
@@ -542,6 +545,9 @@ public:
void set_use_debanding(bool p_use_debanding);
bool is_using_debanding() const;
+ void set_lod_threshold(float p_pixels);
+ float get_lod_threshold() const;
+
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
@@ -624,7 +630,7 @@ public:
enum ClearMode {
CLEAR_MODE_ALWAYS,
CLEAR_MODE_NEVER,
- CLEAR_MODE_ONLY_NEXT_FRAME
+ CLEAR_MODE_ONCE
};
enum UpdateMode {
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index d88c8fb3af..ad87139332 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -1167,11 +1167,6 @@ Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName
return Control::get_icons(theme_owner, theme_owner_window, p_name, type);
}
-Ref<Shader> Window::get_theme_shader(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_shaders(theme_owner, theme_owner_window, p_name, type);
-}
-
Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
StringName type = p_type ? p_type : get_class_name();
return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, type);
@@ -1202,11 +1197,6 @@ bool Window::has_theme_icon(const StringName &p_name, const StringName &p_type)
return Control::has_icons(theme_owner, theme_owner_window, p_name, type);
}
-bool Window::has_theme_shader(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_shaders(theme_owner, theme_owner_window, p_name, type);
-}
-
bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
StringName type = p_type ? p_type : get_class_name();
return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, type);
diff --git a/scene/main/window.h b/scene/main/window.h
index a9a17ab9ba..20f8309952 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -253,7 +253,6 @@ public:
Rect2i get_usable_parent_rect() const;
Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
- Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
int get_theme_font_size(const StringName &p_name, const StringName &p_type = StringName()) const;
@@ -261,7 +260,6 @@ public:
int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
bool has_theme_font_size(const StringName &p_name, const StringName &p_type = StringName()) const;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 7082d70ae9..30077aa642 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -118,7 +118,7 @@
#include "scene/gui/tabs.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/texture_button.h"
-#include "scene/gui/texture_progress.h"
+#include "scene/gui/texture_progress_bar.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
#include "scene/gui/video_player.h"
@@ -234,6 +234,10 @@ static Ref<ResourceFormatLoaderText> resource_loader_text;
static Ref<ResourceFormatLoaderFont> resource_loader_font;
+#ifndef DISABLE_DEPRECATED
+static Ref<ResourceFormatLoaderCompatFont> resource_loader_compat_font;
+#endif /* DISABLE_DEPRECATED */
+
static Ref<ResourceFormatLoaderStreamTexture2D> resource_loader_stream_texture;
static Ref<ResourceFormatLoaderStreamTextureLayered> resource_loader_texture_layered;
static Ref<ResourceFormatLoaderStreamTexture3D> resource_loader_texture_3d;
@@ -251,6 +255,11 @@ void register_scene_types() {
resource_loader_font.instance();
ResourceLoader::add_resource_format_loader(resource_loader_font);
+#ifndef DISABLE_DEPRECATED
+ resource_loader_compat_font.instance();
+ ResourceLoader::add_resource_format_loader(resource_loader_compat_font);
+#endif /* DISABLE_DEPRECATED */
+
resource_loader_stream_texture.instance();
ResourceLoader::add_resource_format_loader(resource_loader_stream_texture);
@@ -340,7 +349,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- ClassDB::register_class<TextureProgress>();
+ ClassDB::register_class<TextureProgressBar>();
ClassDB::register_class<ItemList>();
ClassDB::register_class<LineEdit>();
@@ -670,8 +679,8 @@ void register_scene_types() {
#ifndef _3D_DISABLED
ClassDB::register_virtual_class<PrimitiveMesh>();
+ ClassDB::register_class<BoxMesh>();
ClassDB::register_class<CapsuleMesh>();
- ClassDB::register_class<CubeMesh>();
ClassDB::register_class<CylinderMesh>();
ClassDB::register_class<PlaneMesh>();
ClassDB::register_class<PrismMesh>();
@@ -799,6 +808,9 @@ void register_scene_types() {
#ifndef DISABLE_DEPRECATED
// Dropped in 4.0, near approximation.
ClassDB::add_compatibility_class("AnimationTreePlayer", "AnimationTree");
+ ClassDB::add_compatibility_class("BitmapFont", "Font");
+ ClassDB::add_compatibility_class("DynamicFont", "Font");
+ ClassDB::add_compatibility_class("DynamicFontData", "FontData");
ClassDB::add_compatibility_class("ToolButton", "Button");
// Renamed in 4.0.
@@ -835,6 +847,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("CSGShape", "CSGShape3D");
ClassDB::add_compatibility_class("CSGSphere", "CSGSphere3D");
ClassDB::add_compatibility_class("CSGTorus", "CSGTorus3D");
+ ClassDB::add_compatibility_class("CubeMesh", "BoxMesh");
ClassDB::add_compatibility_class("CylinderShape", "CylinderShape3D");
ClassDB::add_compatibility_class("DirectionalLight", "DirectionalLight3D");
ClassDB::add_compatibility_class("EditorSpatialGizmo", "EditorNode3DGizmo");
@@ -902,6 +915,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("SpringArm", "SpringArm3D");
ClassDB::add_compatibility_class("Sprite", "Sprite2D");
ClassDB::add_compatibility_class("StaticBody", "StaticBody3D");
+ ClassDB::add_compatibility_class("TextureProgress", "TextureProgressBar");
ClassDB::add_compatibility_class("VehicleBody", "VehicleBody3D");
ClassDB::add_compatibility_class("VehicleWheel", "VehicleWheel3D");
ClassDB::add_compatibility_class("ViewportContainer", "SubViewportContainer");
@@ -917,7 +931,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("StreamTexture", "StreamTexture2D");
ClassDB::add_compatibility_class("Light2D", "PointLight2D");
-#endif
+#endif /* DISABLE_DEPRECATED */
OS::get_singleton()->yield(); //may take time to init
@@ -969,6 +983,11 @@ void unregister_scene_types() {
ResourceLoader::remove_resource_format_loader(resource_loader_font);
resource_loader_font.unref();
+#ifndef DISABLE_DEPRECATED
+ ResourceLoader::remove_resource_format_loader(resource_loader_compat_font);
+ resource_loader_compat_font.unref();
+#endif /* DISABLE_DEPRECATED */
+
ResourceLoader::remove_resource_format_loader(resource_loader_texture_layered);
resource_loader_texture_layered.unref();
diff --git a/scene/resources/SCsub b/scene/resources/SCsub
index 3a86b22835..f4dc7a46fb 100644
--- a/scene/resources/SCsub
+++ b/scene/resources/SCsub
@@ -2,6 +2,25 @@
Import("env")
-env.add_source_files(env.scene_sources, "*.cpp")
+# Thirdparty code
+
+thirdparty_obj = []
+
+thirdparty_sources = "#thirdparty/misc/mikktspace.c"
+
+env_thirdparty = env.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.scene_sources += thirdparty_obj
+
+# Godot source files
+
+scene_obj = []
+
+env.add_source_files(scene_obj, "*.cpp")
+env.scene_sources += scene_obj
+
+# Needed to force rebuilding the scene files when the thirdparty code is updated.
+env.Depends(scene_obj, thirdparty_obj)
SConscript("default_theme/SCsub")
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index b2aad97d3b..a7a02361a9 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -810,8 +810,8 @@ int Animation::transform_track_insert_key(int p_track, float p_time, const Vecto
return ret;
}
-void Animation::track_remove_key_at_position(int p_track, float p_pos) {
- int idx = track_find_key(p_track, p_pos, true);
+void Animation::track_remove_key_at_time(int p_track, float p_time) {
+ int idx = track_find_key(p_track, p_time, true);
ERR_FAIL_COND(idx < 0);
track_remove_key(p_track, idx);
}
@@ -2608,7 +2608,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("transform_track_insert_key", "track_idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key);
ClassDB::bind_method(D_METHOD("track_insert_key", "track_idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1));
ClassDB::bind_method(D_METHOD("track_remove_key", "track_idx", "key_idx"), &Animation::track_remove_key);
- ClassDB::bind_method(D_METHOD("track_remove_key_at_position", "track_idx", "position"), &Animation::track_remove_key_at_position);
+ ClassDB::bind_method(D_METHOD("track_remove_key_at_time", "track_idx", "time"), &Animation::track_remove_key_at_time);
ClassDB::bind_method(D_METHOD("track_set_key_value", "track_idx", "key", "value"), &Animation::track_set_key_value);
ClassDB::bind_method(D_METHOD("track_set_key_transition", "track_idx", "key_idx", "transition"), &Animation::track_set_key_transition);
ClassDB::bind_method(D_METHOD("track_set_key_time", "track_idx", "key_idx", "time"), &Animation::track_set_key_time);
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index c52431f5f6..060d1fe2d9 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -293,7 +293,7 @@ public:
void track_set_key_time(int p_track, int p_key_idx, float p_time);
int track_find_key(int p_track, float p_time, bool p_exact = false) const;
void track_remove_key(int p_track, int p_idx);
- void track_remove_key_at_position(int p_track, float p_pos);
+ void track_remove_key_at_time(int p_track, float p_time);
int track_get_key_count(int p_track) const;
Variant track_get_key_value(int p_track, int p_key_idx) const;
float track_get_key_time(int p_track, int p_key_idx) const;
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 1d92ed4830..2de28b5e5c 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -77,6 +77,17 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, fl
return style;
}
+static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
+ Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
+ style->set_bg_color(p_color);
+ style->set_default_margin(MARGIN_LEFT, p_margin_left * scale);
+ style->set_default_margin(MARGIN_RIGHT, p_margin_right * scale);
+ style->set_default_margin(MARGIN_BOTTOM, p_margin_bottom * scale);
+ style->set_default_margin(MARGIN_TOP, p_margin_top * scale);
+
+ return style;
+}
+
static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox, float p_left, float p_top, float p_right, float p_botton) {
p_sbox->set_expand_margin_size(MARGIN_LEFT, p_left * scale);
p_sbox->set_expand_margin_size(MARGIN_TOP, p_top * scale);
@@ -97,6 +108,25 @@ static Ref<Texture2D> make_icon(T p_src) {
return texture;
}
+static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, bool p_flip_x = false) {
+ if (!p_flip_y && !p_flip_x) {
+ return p_texture;
+ }
+
+ Ref<ImageTexture> texture(memnew(ImageTexture));
+ Ref<Image> img = p_texture->get_data();
+
+ if (p_flip_y) {
+ img->flip_y();
+ }
+ if (p_flip_x) {
+ img->flip_x();
+ }
+
+ texture->create_from_image(img);
+ return texture;
+}
+
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_botton = -1) {
Ref<StyleBox> style(memnew(StyleBoxEmpty));
@@ -571,6 +601,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color_accel", "PopupMenu", Color(0.7, 0.7, 0.7, 0.8));
theme->set_color("font_color_disabled", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8));
theme->set_color("font_color_hover", "PopupMenu", control_font_color);
+ theme->set_color("font_color_separator", "PopupMenu", control_font_color);
theme->set_constant("hseparation", "PopupMenu", 4 * scale);
theme->set_constant("vseparation", "PopupMenu", 4 * scale);
@@ -802,6 +833,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font("bold_italics_font", "RichTextLabel", Ref<Font>());
theme->set_font("mono_font", "RichTextLabel", Ref<Font>());
+ theme->set_font_size("normal_font_size", "RichTextLabel", -1);
+ theme->set_font_size("bold_font_size", "RichTextLabel", -1);
+ theme->set_font_size("italics_font_size", "RichTextLabel", -1);
+ theme->set_font_size("bold_italics_font_size", "RichTextLabel", -1);
+ theme->set_font_size("mono_font_size", "RichTextLabel", -1);
+
theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1));
theme->set_color("font_color_selected", "RichTextLabel", font_color_selection);
theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8));
@@ -816,6 +853,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale);
theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale);
+ theme->set_color("table_odd_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
+ theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
+ theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
// Containers
theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1));
@@ -844,6 +884,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("reset", "GraphEdit", make_icon(icon_zoom_reset_png));
theme->set_icon("more", "GraphEdit", make_icon(icon_zoom_more_png));
theme->set_icon("snap", "GraphEdit", make_icon(icon_snap_grid_png));
+ theme->set_icon("minimap", "GraphEdit", make_icon(icon_grid_minimap_png));
theme->set_stylebox("bg", "GraphEdit", make_stylebox(tree_bg_png, 4, 4, 4, 5));
theme->set_color("grid_minor", "GraphEdit", Color(1, 1, 1, 0.05));
theme->set_color("grid_major", "GraphEdit", Color(1, 1, 1, 0.2));
@@ -857,6 +898,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale);
theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale);
+ theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
+ Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0);
+ style_minimap_camera->set_border_color(Color(0.65, 0.65, 0.65, 0.45));
+ style_minimap_camera->set_border_width_all(1);
+ theme->set_stylebox("camera", "GraphEditMinimap", style_minimap_camera);
+ Ref<StyleBoxFlat> style_minimap_node = make_flat_stylebox(Color(1, 1, 1), 0, 0, 0, 0);
+ style_minimap_node->set_corner_radius_all(2);
+ theme->set_stylebox("node", "GraphEditMinimap", style_minimap_node);
+
+ Ref<Texture2D> resizer_icon = make_icon(window_resizer_png);
+ theme->set_icon("resizer", "GraphEditMinimap", flip_icon(resizer_icon, true, true));
+ theme->set_color("resizer_color", "GraphEditMinimap", Color(1, 1, 1, 0.85));
+
// Theme
default_icon = make_icon(error_icon_png);
diff --git a/scene/resources/default_theme/icon_grid_minimap.png b/scene/resources/default_theme/icon_grid_minimap.png
new file mode 100644
index 0000000000..00a6179d5e
--- /dev/null
+++ b/scene/resources/default_theme/icon_grid_minimap.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 7765348f80..b905c9db69 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -166,6 +166,10 @@ static const unsigned char icon_folder_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x6, 0x78, 0x70, 0xf4, 0xc1, 0x7f, 0x24, 0x78, 0x18, 0x53, 0xc1, 0x7f, 0x54, 0x48, 0x50, 0xc1, 0x43, 0x1b, 0xbc, 0xa, 0x50, 0xad, 0x23, 0xa4, 0xe0, 0xff, 0x70, 0x52, 0x70, 0x18, 0x97, 0xf4, 0xfd, 0x43, 0xd4, 0x88, 0x4a, 0x0, 0x5a, 0xcb, 0x18, 0xab, 0x5e, 0xd9, 0x1a, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char icon_grid_minimap_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x2, 0xd, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x75, 0x93, 0x31, 0x68, 0x14, 0x51, 0x10, 0x86, 0xbf, 0xd9, 0xd, 0xbb, 0xde, 0x76, 0x82, 0x21, 0xf8, 0xe0, 0xbc, 0x5d, 0x8b, 0x80, 0x69, 0x6c, 0xd2, 0x5a, 0x6a, 0x91, 0xc3, 0xd2, 0x46, 0x22, 0x8, 0x9, 0x89, 0x70, 0x85, 0x10, 0x41, 0xd, 0x24, 0x45, 0xb0, 0xb, 0x68, 0x11, 0x14, 0x24, 0x10, 0x22, 0x62, 0x21, 0x41, 0xe, 0x4b, 0x21, 0xa4, 0xb7, 0x49, 0x17, 0xb1, 0x8, 0xb9, 0xdd, 0xc7, 0x86, 0x33, 0x21, 0xe1, 0x3a, 0x8f, 0x64, 0x61, 0x6f, 0x2c, 0xbc, 0x3b, 0x36, 0xb9, 0xdc, 0xc0, 0x2b, 0xde, 0xcc, 0xfc, 0xf3, 0xff, 0xfc, 0xcc, 0x48, 0xa3, 0xd1, 0x78, 0x20, 0x22, 0x13, 0xbe, 0xef, 0xaf, 0xdf, 0xac, 0xd7, 0x1f, 0xe1, 0x38, 0xd3, 0xa8, 0x2a, 0xf0, 0x45, 0x6a, 0xb5, 0xcf, 0x5c, 0x11, 0xcd, 0x66, 0x33, 0x38, 0x3f, 0x3f, 0x9f, 0x13, 0x91, 0x7d, 0xb1, 0xd6, 0x6e, 0xaa, 0xea, 0xd3, 0xe0, 0xe8, 0xe8, 0xde, 0xe8, 0xee, 0xee, 0x37, 0xc0, 0xe9, 0xf6, 0x75, 0xf0, 0xfd, 0x9, 0x99, 0x9d, 0x6d, 0x15, 0x81, 0x59, 0x96, 0x3d, 0x3, 0x5e, 0x2, 0x63, 0x22, 0xf2, 0x69, 0xa4, 0x57, 0x1c, 0xdd, 0xdb, 0xfb, 0x5b, 0x0, 0x3, 0x38, 0x67, 0x41, 0x30, 0x11, 0xc7, 0xf1, 0x13, 0x0, 0x11, 0x71, 0xb2, 0x2c, 0x7b, 0xd8, 0xad, 0xad, 0x2, 0x6f, 0xb9, 0x0, 0x38, 0x3c, 0xfc, 0x5, 0x9c, 0xf6, 0xff, 0x22, 0x27, 0x27, 0xe3, 0xe3, 0x7f, 0xa, 0x3, 0x67, 0x45, 0xe4, 0xbb, 0xe7, 0x79, 0xb7, 0xc3, 0x30, 0x7c, 0xd7, 0x67, 0xe9, 0xe3, 0x67, 0x66, 0x5c, 0x60, 0x1, 0x50, 0x40, 0x51, 0x7d, 0x71, 0x6b, 0x72, 0xf2, 0x20, 0x8a, 0xa2, 0xf9, 0x28, 0x8a, 0xe6, 0x1, 0x3a, 0x9d, 0xce, 0x4f, 0x63, 0x4c, 0x3b, 0x4d, 0xd3, 0xd2, 0xc0, 0x80, 0x3c, 0xcf, 0xf, 0x92, 0xa9, 0xa9, 0x31, 0x60, 0x5, 0x58, 0x91, 0x5a, 0xed, 0xc7, 0x15, 0xfe, 0x95, 0xac, 0xb5, 0xcf, 0xf3, 0x3c, 0x3f, 0xe8, 0x25, 0x46, 0xa, 0xc5, 0xd, 0x11, 0x59, 0xb3, 0xd5, 0xea, 0x1b, 0xa0, 0x95, 0x54, 0xab, 0x5b, 0x97, 0xd1, 0x22, 0xb2, 0xa6, 0xaa, 0x6d, 0x60, 0xd, 0x58, 0xba, 0xa0, 0x20, 0xc, 0xc3, 0x65, 0xd7, 0x75, 0x23, 0xe0, 0x2e, 0xb0, 0x1, 0x5c, 0xbf, 0xf4, 0x0, 0xbe, 0xba, 0xae, 0x1b, 0x85, 0x61, 0xb8, 0x3c, 0xa0, 0x20, 0x4d, 0xd3, 0x52, 0xb9, 0x5c, 0x6e, 0xc5, 0x71, 0xbc, 0x23, 0x22, 0xd3, 0x61, 0x18, 0xde, 0x2f, 0xb2, 0x27, 0x49, 0xa2, 0xaa, 0xba, 0x53, 0x2e, 0x97, 0x5b, 0x69, 0x9a, 0x96, 0xf2, 0x3c, 0x1f, 0xf0, 0xc0, 0x5a, 0x6b, 0x5f, 0x1, 0x25, 0x86, 0x84, 0xe3, 0x38, 0x9e, 0xb5, 0x76, 0x2e, 0xcf, 0xf3, 0xfd, 0x1, 0x5, 0x22, 0xb2, 0xa1, 0xaa, 0x4b, 0x22, 0x72, 0xad, 0xcb, 0x38, 0xe0, 0x81, 0xaa, 0x7e, 0x0, 0xce, 0x44, 0xe4, 0xbd, 0xaa, 0xbe, 0xbe, 0xa0, 0xa0, 0x52, 0xa9, 0x2c, 0x7a, 0x9e, 0x17, 0x1, 0x3d, 0xe0, 0x55, 0x1e, 0x6c, 0x79, 0x9e, 0x17, 0x55, 0x2a, 0x95, 0xc5, 0x1, 0x5, 0xcd, 0x66, 0x33, 0x30, 0xc6, 0x9c, 0xc6, 0x71, 0xbc, 0x2d, 0x22, 0x8f, 0x87, 0x78, 0xb0, 0x6d, 0x8c, 0x39, 0xed, 0xae, 0x74, 0xdf, 0x83, 0x3a, 0x70, 0x9c, 0x65, 0x59, 0x23, 0x49, 0x92, 0x5, 0x11, 0x9, 0x86, 0x79, 0x20, 0x22, 0x41, 0x92, 0x24, 0xb, 0x59, 0x96, 0x35, 0x80, 0x63, 0xa0, 0x2e, 0x3d, 0xf6, 0xc2, 0x91, 0xdc, 0x0, 0x5c, 0x55, 0x5d, 0xbf, 0x4, 0x9e, 0x3, 0x72, 0xfe, 0xaf, 0xfb, 0xaa, 0xe7, 0x79, 0x1f, 0x8d, 0x31, 0x6d, 0x29, 0x36, 0xf5, 0xce, 0x14, 0xb8, 0x33, 0x44, 0xc4, 0x6f, 0xdf, 0xf7, 0xd7, 0x8d, 0x31, 0xed, 0x5e, 0xe2, 0x1f, 0xb, 0x5c, 0xe2, 0xcb, 0xd, 0x9b, 0x69, 0xcb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char icon_parent_folder_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x68, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x33, 0xb8, 0x27, 0xfe, 0xe0, 0xfc, 0x83, 0x73, 0xf7, 0xc4, 0x71, 0x48, 0xdf, 0x11, 0x7b, 0x78, 0xe9, 0xc1, 0x3f, 0x20, 0xbc, 0xfe, 0x40, 0x12, 0x8f, 0x34, 0x4c, 0x9, 0xa6, 0xe1, 0x57, 0x80, 0x12, 0x17, 0x81, 0xf8, 0x2f, 0x58, 0xe1, 0x15, 0x34, 0x8b, 0x1e, 0x9c, 0x5, 0xa, 0x5e, 0xb8, 0x23, 0x6, 0x52, 0x70, 0x5b, 0x14, 0xac, 0xf0, 0xc, 0xaa, 0x82, 0x7d, 0xf, 0x8e, 0xde, 0x14, 0xf9, 0xcf, 0x8, 0x52, 0xc0, 0xc0, 0x70, 0x5b, 0xf4, 0xe1, 0xc9, 0x7, 0x47, 0xb1, 0xb8, 0x3, 0xaa, 0x0, 0xa, 0x48, 0x52, 0x80, 0xb0, 0xea, 0xc8, 0xc3, 0x83, 0xc, 0x83, 0xe, 0x0, 0x0, 0xb8, 0x27, 0x55, 0x4c, 0xbe, 0xc0, 0xd2, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 2ed5953b8f..1eb78a3679 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -591,7 +591,7 @@ void Environment::set_glow_level(int p_level, float p_intensity) {
}
float Environment::get_glow_level(int p_level) const {
- ERR_FAIL_INDEX_V(p_level, RS::MAX_GLOW_LEVELS, false);
+ ERR_FAIL_INDEX_V(p_level, RS::MAX_GLOW_LEVELS, 0.0);
return glow_levels[p_level];
}
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index da35137a09..791f260c0e 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -53,6 +53,11 @@ void FontData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
ClassDB::bind_method(D_METHOD("get_antialiased"), &FontData::get_antialiased);
+ ClassDB::bind_method(D_METHOD("get_variation_list"), &FontData::get_variation_list);
+
+ ClassDB::bind_method(D_METHOD("set_variation", "tag", "value"), &FontData::set_variation);
+ ClassDB::bind_method(D_METHOD("get_variation", "tag"), &FontData::get_variation);
+
ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontData::set_hinting);
ClassDB::bind_method(D_METHOD("get_hinting"), &FontData::get_hinting);
@@ -115,6 +120,11 @@ bool FontData::_set(const StringName &p_name, const Variant &p_value) {
set_script_support_override(scr, p_value);
return true;
}
+ if (str.begins_with("variation/")) {
+ String name = str.get_slicec('/', 1);
+ set_variation(name, p_value);
+ return true;
+ }
return false;
}
@@ -137,6 +147,12 @@ bool FontData::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_script_support_override(scr);
return true;
}
+ if (str.begins_with("variation/")) {
+ String name = str.get_slicec('/', 1);
+
+ r_ret = get_variation(name);
+ return true;
+ }
return false;
}
@@ -153,6 +169,12 @@ void FontData::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE));
}
p_list->push_back(PropertyInfo(Variant::NIL, "script_support_override/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+
+ Dictionary variations = get_variation_list();
+ for (const Variant *ftr = variations.next(nullptr); ftr != nullptr; ftr = variations.next(ftr)) {
+ Vector3i v = variations[*ftr];
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "variation/" + TS->tag_to_name(*ftr), PROPERTY_HINT_RANGE, itos(v.x) + "," + itos(v.y), PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE));
+ }
}
RID FontData::get_rid() const {
@@ -239,6 +261,26 @@ float FontData::get_underline_thickness(int p_size) const {
return TS->font_get_underline_thickness(rid, (p_size < 0) ? base_size : p_size);
}
+Dictionary FontData::get_variation_list() const {
+ if (rid == RID()) {
+ return Dictionary();
+ }
+ return TS->font_get_variation_list(rid);
+}
+
+void FontData::set_variation(const String &p_name, double p_value) {
+ ERR_FAIL_COND(rid == RID());
+ TS->font_set_variation(rid, p_name, p_value);
+ emit_changed();
+}
+
+double FontData::get_variation(const String &p_name) const {
+ if (rid == RID()) {
+ return 0;
+ }
+ return TS->font_get_variation(rid, p_name);
+}
+
void FontData::set_antialiased(bool p_antialiased) {
ERR_FAIL_COND(rid == RID());
TS->font_set_antialiased(rid, p_antialiased);
@@ -472,6 +514,32 @@ void Font::_data_changed() {
bool Font::_set(const StringName &p_name, const Variant &p_value) {
String str = p_name;
+#ifndef DISABLE_DEPRECATED
+ if (str == "font_data") { // Compatibility, DynamicFont main data
+ Ref<FontData> fd = p_value;
+ if (fd.is_valid()) {
+ add_data(fd);
+ return true;
+ }
+ return false;
+ } else if (str.begins_with("fallback/")) { // Compatibility, DynamicFont fallback data
+ Ref<FontData> fd = p_value;
+ if (fd.is_valid()) {
+ add_data(fd);
+ return true;
+ }
+ return false;
+ } else if (str == "fallback") { // Compatibility, BitmapFont fallback
+ Ref<Font> f = p_value;
+ if (f.is_valid()) {
+ for (int i = 0; i < f->get_data_count(); i++) {
+ add_data(f->get_data(i));
+ }
+ return true;
+ }
+ return false;
+ }
+#endif /* DISABLE_DEPRECATED */
if (str.begins_with("data/")) {
int idx = str.get_slicec('/', 1).to_int();
Ref<FontData> fd = p_value;
@@ -595,41 +663,41 @@ Dictionary Font::get_feature_list() const {
float Font::get_height(int p_size) const {
float ret = 0.f;
for (int i = 0; i < data.size(); i++) {
- ret += data[i]->get_height(p_size);
+ ret = MAX(ret, data[i]->get_height(p_size));
}
- return (ret / data.size()) + spacing_top + spacing_bottom;
+ return ret + spacing_top + spacing_bottom;
}
float Font::get_ascent(int p_size) const {
float ret = 0.f;
for (int i = 0; i < data.size(); i++) {
- ret += data[i]->get_ascent(p_size);
+ ret = MAX(ret, data[i]->get_ascent(p_size));
}
- return (ret / data.size()) + spacing_top;
+ return ret + spacing_top;
}
float Font::get_descent(int p_size) const {
float ret = 0.f;
for (int i = 0; i < data.size(); i++) {
- ret += data[i]->get_descent(p_size);
+ ret = MAX(ret, data[i]->get_descent(p_size));
}
- return (ret / data.size()) + spacing_bottom;
+ return ret + spacing_bottom;
}
float Font::get_underline_position(int p_size) const {
float ret = 0.f;
for (int i = 0; i < data.size(); i++) {
- ret += data[i]->get_underline_position(p_size);
+ ret = MAX(ret, data[i]->get_underline_position(p_size));
}
- return (ret / data.size());
+ return ret;
}
float Font::get_underline_thickness(int p_size) const {
float ret = 0.f;
for (int i = 0; i < data.size(); i++) {
- ret += data[i]->get_underline_thickness(p_size);
+ ret = MAX(ret, data[i]->get_underline_thickness(p_size));
}
- return (ret / data.size());
+ return ret;
}
int Font::get_spacing(int p_type) const {
@@ -899,6 +967,23 @@ RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_origina
return dfont;
}
+void ResourceFormatLoaderFont::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
+#ifndef DISABLE_DEPRECATED
+ if (p_type == "DynamicFontData") {
+ p_extensions->push_back("ttf");
+ p_extensions->push_back("otf");
+ p_extensions->push_back("woff");
+ return;
+ }
+ if (p_type == "BitmapFont") { // BitmapFont (*.font, *fnt) is handled by ResourceFormatLoaderCompatFont
+ return;
+ }
+#endif /* DISABLE_DEPRECATED */
+ if (p_type == "" || handles_type(p_type)) {
+ get_recognized_extensions(p_extensions);
+ }
+}
+
void ResourceFormatLoaderFont::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("ttf");
p_extensions->push_back("otf");
@@ -918,3 +1003,45 @@ String ResourceFormatLoaderFont::get_resource_type(const String &p_path) const {
}
return "";
}
+
+#ifndef DISABLE_DEPRECATED
+
+RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+ if (r_error) {
+ *r_error = ERR_FILE_CANT_OPEN;
+ }
+
+ Ref<FontData> dfont;
+ dfont.instance();
+ dfont->load_resource(p_path);
+
+ Ref<Font> font;
+ font.instance();
+ font->add_data(dfont);
+
+ if (r_error) {
+ *r_error = OK;
+ }
+
+ return font;
+}
+
+void ResourceFormatLoaderCompatFont::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
+ if (p_type == "BitmapFont") {
+ p_extensions->push_back("font");
+ p_extensions->push_back("fnt");
+ }
+}
+
+void ResourceFormatLoaderCompatFont::get_recognized_extensions(List<String> *p_extensions) const {
+}
+
+bool ResourceFormatLoaderCompatFont::handles_type(const String &p_type) const {
+ return (p_type == "Font");
+}
+
+String ResourceFormatLoaderCompatFont::get_resource_type(const String &p_path) const {
+ return "";
+}
+
+#endif /* DISABLE_DEPRECATED */
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 226979c4a0..fe28e1aea5 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -68,6 +68,10 @@ public:
float get_descent(int p_size) const;
Dictionary get_feature_list() const;
+ Dictionary get_variation_list() const;
+
+ void set_variation(const String &p_name, double p_value);
+ double get_variation(const String &p_name) const;
float get_underline_position(int p_size) const;
float get_underline_thickness(int p_size) const;
@@ -198,9 +202,23 @@ VARIANT_ENUM_CAST(Font::SpacingType);
class ResourceFormatLoaderFont : public ResourceFormatLoader {
public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+#ifndef DISABLE_DEPRECATED
+
+class ResourceFormatLoaderCompatFont : public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
};
-#endif
+#endif /* DISABLE_DEPRECATED */
+
+#endif /* FONT_H */
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 35c967ce27..6e08af23f5 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -2417,10 +2417,10 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Height", "heightmap_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "heightmap_enabled"), "set_feature", "get_feature", FEATURE_HEIGHT_MAPPING);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "heightmap_scale", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_heightmap_scale", "get_heightmap_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "heightmap_scale", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_heightmap_scale", "get_heightmap_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_deep_parallax"), "set_heightmap_deep_parallax", "is_heightmap_deep_parallax_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_min_layers", PROPERTY_HINT_RANGE, "1,32,1"), "set_heightmap_deep_parallax_min_layers", "get_heightmap_deep_parallax_min_layers");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_max_layers", PROPERTY_HINT_RANGE, "1,32,1"), "set_heightmap_deep_parallax_max_layers", "get_heightmap_deep_parallax_max_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_min_layers", PROPERTY_HINT_RANGE, "1,64,1"), "set_heightmap_deep_parallax_min_layers", "get_heightmap_deep_parallax_min_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "heightmap_max_layers", PROPERTY_HINT_RANGE, "1,64,1"), "set_heightmap_deep_parallax_max_layers", "get_heightmap_deep_parallax_max_layers");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_flip_tangent"), "set_heightmap_deep_parallax_flip_tangent", "get_heightmap_deep_parallax_flip_tangent");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "heightmap_flip_binormal"), "set_heightmap_deep_parallax_flip_binormal", "get_heightmap_deep_parallax_flip_binormal");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "heightmap_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_HEIGHTMAP);
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 97c0c7a81d..f1c05b8014 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -157,7 +157,7 @@ void Mesh::generate_debug_mesh_indices(Vector<Vector3> &r_points) {
bool Mesh::surface_is_softbody_friendly(int p_idx) const {
const uint32_t surface_format = surface_get_format(p_idx);
- return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE && (!(surface_format & Mesh::ARRAY_COMPRESS_NORMAL)));
+ return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE);
}
Vector<Face3> Mesh::get_faces() const {
@@ -480,8 +480,30 @@ void Mesh::_bind_methods() {
BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES);
BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP);
- BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
- BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
+ BIND_ENUM_CONSTANT(ARRAY_VERTEX);
+ BIND_ENUM_CONSTANT(ARRAY_NORMAL);
+ BIND_ENUM_CONSTANT(ARRAY_TANGENT);
+ BIND_ENUM_CONSTANT(ARRAY_COLOR);
+ BIND_ENUM_CONSTANT(ARRAY_TEX_UV);
+ BIND_ENUM_CONSTANT(ARRAY_TEX_UV2);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM0);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM1);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM2);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM3);
+ BIND_ENUM_CONSTANT(ARRAY_BONES);
+ BIND_ENUM_CONSTANT(ARRAY_WEIGHTS);
+ BIND_ENUM_CONSTANT(ARRAY_INDEX);
+ BIND_ENUM_CONSTANT(ARRAY_MAX);
+
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_UNORM);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_SNORM);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_HALF);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_HALF);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_R_FLOAT);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_FLOAT);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGB_FLOAT);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_FLOAT);
+ BIND_ENUM_CONSTANT(ARRAY_CUSTOM_MAX);
BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX);
BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL);
@@ -489,31 +511,31 @@ void Mesh::_bind_methods() {
BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR);
BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV);
BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3);
BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES);
BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS);
BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_BLEND_SHAPE_MASK);
- BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BASE);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0_SHIFT);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1_SHIFT);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2_SHIFT);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3_SHIFT);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_MASK);
+ BIND_ENUM_CONSTANT(ARRAY_COMPRESS_FLAGS_BASE);
- BIND_ENUM_CONSTANT(ARRAY_VERTEX);
- BIND_ENUM_CONSTANT(ARRAY_NORMAL);
- BIND_ENUM_CONSTANT(ARRAY_TANGENT);
- BIND_ENUM_CONSTANT(ARRAY_COLOR);
- BIND_ENUM_CONSTANT(ARRAY_TEX_UV);
- BIND_ENUM_CONSTANT(ARRAY_TEX_UV2);
- BIND_ENUM_CONSTANT(ARRAY_BONES);
- BIND_ENUM_CONSTANT(ARRAY_WEIGHTS);
- BIND_ENUM_CONSTANT(ARRAY_INDEX);
- BIND_ENUM_CONSTANT(ARRAY_MAX);
+ BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
+ BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
+ BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS);
+
+ BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
+ BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
}
void Mesh::clear_cache() const {
@@ -560,11 +582,50 @@ Vector<Ref<Shape3D>> Mesh::convex_decompose() const {
Mesh::Mesh() {
}
+#if 0
static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_format, uint32_t p_elements) {
- bool vertex_16bit = p_format & ((1 << (Mesh::ARRAY_VERTEX + Mesh::ARRAY_COMPRESS_BASE)));
- bool has_bones = (p_format & Mesh::ARRAY_FORMAT_BONES);
- bool bone_8 = has_bones && !(p_format & (Mesh::ARRAY_COMPRESS_INDEX << 2));
- bool weight_32 = has_bones && !(p_format & (Mesh::ARRAY_COMPRESS_TEX_UV2 << 2));
+ enum ArrayType {
+ OLD_ARRAY_VERTEX = 0,
+ OLD_ARRAY_NORMAL = 1,
+ OLD_ARRAY_TANGENT = 2,
+ OLD_ARRAY_COLOR = 3,
+ OLD_ARRAY_TEX_UV = 4,
+ OLD_ARRAY_TEX_UV2 = 5,
+ OLD_ARRAY_BONES = 6,
+ OLD_ARRAY_WEIGHTS = 7,
+ OLD_ARRAY_INDEX = 8,
+ OLD_ARRAY_MAX = 9
+ };
+
+ enum ArrayFormat {
+ /* OLD_ARRAY FORMAT FLAGS */
+ OLD_ARRAY_FORMAT_VERTEX = 1 << OLD_ARRAY_VERTEX, // mandatory
+ OLD_ARRAY_FORMAT_NORMAL = 1 << OLD_ARRAY_NORMAL,
+ OLD_ARRAY_FORMAT_TANGENT = 1 << OLD_ARRAY_TANGENT,
+ OLD_ARRAY_FORMAT_COLOR = 1 << OLD_ARRAY_COLOR,
+ OLD_ARRAY_FORMAT_TEX_UV = 1 << OLD_ARRAY_TEX_UV,
+ OLD_ARRAY_FORMAT_TEX_UV2 = 1 << OLD_ARRAY_TEX_UV2,
+ OLD_ARRAY_FORMAT_BONES = 1 << OLD_ARRAY_BONES,
+ OLD_ARRAY_FORMAT_WEIGHTS = 1 << OLD_ARRAY_WEIGHTS,
+ OLD_ARRAY_FORMAT_INDEX = 1 << OLD_ARRAY_INDEX,
+
+ OLD_ARRAY_COMPRESS_BASE = (OLD_ARRAY_INDEX + 1),
+ OLD_ARRAY_COMPRESS_NORMAL = 1 << (OLD_ARRAY_NORMAL + OLD_ARRAY_COMPRESS_BASE),
+ OLD_ARRAY_COMPRESS_TANGENT = 1 << (OLD_ARRAY_TANGENT + OLD_ARRAY_COMPRESS_BASE),
+ OLD_ARRAY_COMPRESS_COLOR = 1 << (OLD_ARRAY_COLOR + OLD_ARRAY_COMPRESS_BASE),
+ OLD_ARRAY_COMPRESS_TEX_UV = 1 << (OLD_ARRAY_TEX_UV + OLD_ARRAY_COMPRESS_BASE),
+ OLD_ARRAY_COMPRESS_TEX_UV2 = 1 << (OLD_ARRAY_TEX_UV2 + OLD_ARRAY_COMPRESS_BASE),
+ OLD_ARRAY_COMPRESS_INDEX = 1 << (OLD_ARRAY_INDEX + OLD_ARRAY_COMPRESS_BASE),
+ OLD_ARRAY_COMPRESS_DEFAULT = OLD_ARRAY_COMPRESS_NORMAL | OLD_ARRAY_COMPRESS_TANGENT | OLD_ARRAY_COMPRESS_COLOR | OLD_ARRAY_COMPRESS_TEX_UV | OLD_ARRAY_COMPRESS_TEX_UV2,
+
+ OLD_ARRAY_FLAG_USE_2D_VERTICES = OLD_ARRAY_COMPRESS_INDEX << 1,
+ OLD_ARRAY_FLAG_USE_DYNAMIC_UPDATE = OLD_ARRAY_COMPRESS_INDEX << 3,
+ };
+
+ bool vertex_16bit = p_format & ((1 << (OLD_ARRAY_VERTEX + OLD_ARRAY_COMPRESS_BASE)));
+ bool has_bones = (p_format & OLD_ARRAY_FORMAT_BONES);
+ bool bone_8 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_INDEX << 2));
+ bool weight_32 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_TEX_UV2 << 2));
print_line("convert vertex16: " + itos(vertex_16bit) + " convert bone 8 " + itos(bone_8) + " convert weight 32 " + itos(weight_32));
@@ -572,7 +633,7 @@ static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, ui
return p_src;
}
- bool vertex_2d = (p_format & (Mesh::ARRAY_COMPRESS_INDEX << 1));
+ bool vertex_2d = (p_format & (OLD_ARRAY_COMPRESS_INDEX << 1));
uint32_t src_stride = p_src.size() / p_elements;
uint32_t dst_stride = src_stride + (vertex_16bit ? 4 : 0) + (bone_8 ? 4 : 0) - (weight_32 ? 8 : 0);
@@ -671,25 +732,11 @@ static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, ui
return ret;
}
+#endif
bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
String sname = p_name;
- if (p_name == "blend_shape/names") {
- Vector<String> sk = p_value;
- int sz = sk.size();
- const String *r = sk.ptr();
- for (int i = 0; i < sz; i++) {
- add_blend_shape(r[i]);
- }
- return true;
- }
-
- if (p_name == "blend_shape/mode") {
- set_blend_shape_mode(BlendShapeMode(int(p_value)));
- return true;
- }
-
if (sname.begins_with("surface_")) {
int sl = sname.find("/");
if (sl == -1) {
@@ -727,6 +774,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
add_surface_from_arrays(PrimitiveType(int(d["primitive"])), d["arrays"], d["morph_arrays"]);
} else if (d.has("array_data")) {
+#if 0
//print_line("array data (old style");
//older format (3.x)
Vector<uint8_t> array_data = d["array_data"];
@@ -793,6 +841,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
}
add_surface(format, PrimitiveType(primitive), array_data, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb);
+#endif
} else {
ERR_FAIL_V(false);
}
@@ -811,6 +860,28 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
return false;
}
+void ArrayMesh::_set_blend_shape_names(const PackedStringArray &p_names) {
+ ERR_FAIL_COND(surfaces.size() > 0);
+
+ blend_shapes.resize(p_names.size());
+ for (int i = 0; i < p_names.size(); i++) {
+ blend_shapes.write[i] = p_names[i];
+ }
+
+ if (mesh.is_valid()) {
+ RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
+ }
+}
+
+PackedStringArray ArrayMesh::_get_blend_shape_names() const {
+ PackedStringArray sarr;
+ sarr.resize(blend_shapes.size());
+ for (int i = 0; i < blend_shapes.size(); i++) {
+ sarr.write[i] = blend_shapes[i];
+ }
+ return sarr;
+}
+
Array ArrayMesh::_get_surfaces() const {
if (mesh.is_null()) {
return Array();
@@ -824,6 +895,12 @@ Array ArrayMesh::_get_surfaces() const {
data["primitive"] = surface.primitive;
data["vertex_data"] = surface.vertex_data;
data["vertex_count"] = surface.vertex_count;
+ if (surface.skin_data.size()) {
+ data["skin_data"] = surface.skin_data;
+ }
+ if (surface.attribute_data.size()) {
+ data["attribute_data"] = surface.attribute_data;
+ }
data["aabb"] = surface.aabb;
if (surface.index_count) {
data["index_data"] = surface.index_data;
@@ -848,9 +925,8 @@ Array ArrayMesh::_get_surfaces() const {
data["bone_aabbs"] = bone_aabbs;
}
- Array blend_shapes;
- for (int j = 0; j < surface.blend_shapes.size(); j++) {
- blend_shapes.push_back(surface.blend_shapes[j]);
+ if (surface.blend_shape_data.size()) {
+ data["blend_shapes"] = surface.blend_shape_data;
}
if (surfaces[i].material.is_valid()) {
@@ -875,6 +951,7 @@ void ArrayMesh::_create_if_empty() const {
if (!mesh.is_valid()) {
mesh = RS::get_singleton()->mesh_create();
RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode);
+ RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
}
}
@@ -896,6 +973,12 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
surface.primitive = RS::PrimitiveType(int(d["primitive"]));
surface.vertex_data = d["vertex_data"];
surface.vertex_count = d["vertex_count"];
+ if (d.has("attribute_data")) {
+ surface.attribute_data = d["attribute_data"];
+ }
+ if (d.has("skin_data")) {
+ surface.skin_data = d["skin_data"];
+ }
surface.aabb = d["aabb"];
if (d.has("index_data")) {
@@ -923,10 +1006,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
}
if (d.has("blend_shapes")) {
- Array blend_shapes;
- for (int j = 0; j < blend_shapes.size(); j++) {
- surface.blend_shapes.push_back(blend_shapes[j]);
- }
+ surface.blend_shape_data = d["blend_shapes"];
}
Ref<Material> material;
@@ -946,15 +1026,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
if (d.has("2d")) {
_2d = d["2d"];
}
- /*
- print_line("format: " + itos(surface.format));
- print_line("aabb: " + surface.aabb);
- print_line("array size: " + itos(surface.vertex_data.size()));
- print_line("vertex count: " + itos(surface.vertex_count));
- print_line("index size: " + itos(surface.index_data.size()));
- print_line("index count: " + itos(surface.index_count));
- print_line("primitive: " + itos(surface.primitive));
-*/
+
surface_data.push_back(surface);
surface_materials.push_back(material);
surface_names.push_back(name);
@@ -970,7 +1042,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
} else {
// if mesh does not exist (first time this is loaded, most likely),
// we can create it with a single call, which is a lot more efficient and thread friendly
- mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data);
+ mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data, blend_shapes.size());
RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode);
}
@@ -982,7 +1054,6 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
s.aabb = surface_data[i].aabb;
if (i == 0) {
aabb = s.aabb;
- blend_shapes.resize(surface_data[i].blend_shapes.size());
} else {
aabb.merge_with(s.aabb);
}
@@ -1006,18 +1077,7 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
}
String sname = p_name;
-
- if (p_name == "blend_shape/names") {
- Vector<String> sk;
- for (int i = 0; i < blend_shapes.size(); i++) {
- sk.push_back(blend_shapes[i]);
- }
- r_ret = sk;
- return true;
- } else if (p_name == "blend_shape/mode") {
- r_ret = get_blend_shape_mode();
- return true;
- } else if (sname.begins_with("surface_")) {
+ if (sname.begins_with("surface_")) {
int sl = sname.find("/");
if (sl == -1) {
return false;
@@ -1040,11 +1100,6 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const {
return;
}
- if (blend_shapes.size()) {
- p_list->push_back(PropertyInfo(Variant::PACKED_STRING_ARRAY, "blend_shape/names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::INT, "blend_shape/mode", PROPERTY_HINT_ENUM, "Normalized,Relative"));
- }
-
for (int i = 0; i < surfaces.size(); i++) {
p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
if (surfaces[i].is_2d) {
@@ -1070,7 +1125,7 @@ void ArrayMesh::_recompute_aabb() {
#ifndef _MSC_VER
#warning need to add binding to add_surface using future MeshSurfaceData object
#endif
-void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t>> &p_blend_shapes, const Vector<AABB> &p_bone_aabb, const Vector<RS::SurfaceData::LOD> &p_lods) {
+void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) {
_create_if_empty();
Surface s;
@@ -1090,10 +1145,12 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const
sd.aabb = p_aabb;
sd.vertex_count = p_vertex_count;
sd.vertex_data = p_array;
+ sd.attribute_data = p_attribute_array;
+ sd.skin_data = p_skin_array;
sd.index_count = p_index_count;
sd.index_data = p_index_array;
- sd.blend_shapes = p_blend_shapes;
- sd.bone_aabbs = p_bone_aabb;
+ sd.blend_shape_data = p_blend_shape_data;
+ sd.bone_aabbs = p_bone_aabbs;
sd.lods = p_lods;
RenderingServer::get_singleton()->mesh_add_surface(mesh, sd);
@@ -1111,15 +1168,17 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &
Error err = RS::get_singleton()->mesh_create_surface_data_from_arrays(&surface, (RenderingServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_lods, p_flags);
ERR_FAIL_COND(err != OK);
- /* print_line("format: " + itos(surface.format));
+ /* Debug code.
+ print_line("format: " + itos(surface.format));
print_line("aabb: " + surface.aabb);
print_line("array size: " + itos(surface.vertex_data.size()));
print_line("vertex count: " + itos(surface.vertex_count));
print_line("index size: " + itos(surface.index_data.size()));
print_line("index count: " + itos(surface.index_count));
print_line("primitive: " + itos(surface.primitive));
-*/
- add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shapes, surface.bone_aabbs, surface.lods);
+ */
+
+ add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.attribute_data, surface.skin_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shape_data, surface.bone_aabbs, surface.lods);
}
Array ArrayMesh::surface_get_arrays(int p_surface) const {
@@ -1155,7 +1214,10 @@ void ArrayMesh::add_blend_shape(const StringName &p_name) {
}
blend_shapes.push_back(name);
- //RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
+
+ if (mesh.is_valid()) {
+ RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
+ }
}
int ArrayMesh::get_blend_shape_count() const {
@@ -1171,6 +1233,10 @@ void ArrayMesh::clear_blend_shapes() {
ERR_FAIL_COND_MSG(surfaces.size(), "Can't set shape key count if surfaces are already created.");
blend_shapes.clear();
+
+ if (mesh.is_valid()) {
+ RS::get_singleton()->mesh_set_blend_shape_count(mesh, 0);
+ }
}
void ArrayMesh::set_blend_shape_mode(BlendShapeMode p_mode) {
@@ -1308,7 +1374,7 @@ bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_v
struct ArrayMeshLightmapSurface {
Ref<Material> material;
- Vector<SurfaceTool::Vertex> vertices;
+ LocalVector<SurfaceTool::Vertex> vertices;
Mesh::PrimitiveType primitive;
uint32_t format;
};
@@ -1349,7 +1415,7 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
Array arrays = surface_get_arrays(i);
s.material = surface_get_material(i);
- s.vertices = SurfaceTool::create_vertex_array_from_triangle_arrays(arrays);
+ SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices);
Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size();
@@ -1452,29 +1518,29 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_COLOR) {
- surfaces_tools.write[surface]->add_color(v.color);
+ surfaces_tools.write[surface]->set_color(v.color);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TEX_UV) {
- surfaces_tools.write[surface]->add_uv(v.uv);
+ surfaces_tools.write[surface]->set_uv(v.uv);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_NORMAL) {
- surfaces_tools.write[surface]->add_normal(v.normal);
+ surfaces_tools.write[surface]->set_normal(v.normal);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TANGENT) {
Plane t;
t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
- surfaces_tools.write[surface]->add_tangent(t);
+ surfaces_tools.write[surface]->set_tangent(t);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_BONES) {
- surfaces_tools.write[surface]->add_bones(v.bones);
+ surfaces_tools.write[surface]->set_bones(v.bones);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) {
- surfaces_tools.write[surface]->add_weights(v.weights);
+ surfaces_tools.write[surface]->set_weights(v.weights);
}
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
- surfaces_tools.write[surface]->add_uv2(uv2);
+ surfaces_tools.write[surface]->set_uv2(uv2);
surfaces_tools.write[surface]->add_vertex(v.vertex);
}
@@ -1507,7 +1573,7 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ArrayMesh::set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0));
ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces);
ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region);
ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len);
@@ -1530,36 +1596,16 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb);
ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ArrayMesh::get_custom_aabb);
+ ClassDB::bind_method(D_METHOD("_set_blend_shape_names", "blend_shape_names"), &ArrayMesh::_set_blend_shape_names);
+ ClassDB::bind_method(D_METHOD("_get_blend_shape_names"), &ArrayMesh::_get_blend_shape_names);
+
ClassDB::bind_method(D_METHOD("_set_surfaces", "surfaces"), &ArrayMesh::_set_surfaces);
ClassDB::bind_method(D_METHOD("_get_surfaces"), &ArrayMesh::_get_surfaces);
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "_blend_shape_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_blend_shape_names", "_get_blend_shape_names");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces");
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode");
ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
-
- BIND_CONSTANT(NO_INDEX_ARRAY);
- BIND_CONSTANT(ARRAY_WEIGHTS_SIZE);
-
- BIND_ENUM_CONSTANT(ARRAY_VERTEX);
- BIND_ENUM_CONSTANT(ARRAY_NORMAL);
- BIND_ENUM_CONSTANT(ARRAY_TANGENT);
- BIND_ENUM_CONSTANT(ARRAY_COLOR);
- BIND_ENUM_CONSTANT(ARRAY_TEX_UV);
- BIND_ENUM_CONSTANT(ARRAY_TEX_UV2);
- BIND_ENUM_CONSTANT(ARRAY_BONES);
- BIND_ENUM_CONSTANT(ARRAY_WEIGHTS);
- BIND_ENUM_CONSTANT(ARRAY_INDEX);
- BIND_ENUM_CONSTANT(ARRAY_MAX);
-
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_TANGENT);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX);
}
void ArrayMesh::reload_from_file() {
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 642ae7e1b0..b7f60bf814 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -53,7 +53,10 @@ public:
NO_INDEX_ARRAY = RenderingServer::NO_INDEX_ARRAY,
ARRAY_WEIGHTS_SIZE = RenderingServer::ARRAY_WEIGHTS_SIZE
};
-
+ enum BlendShapeMode {
+ BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED,
+ BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE,
+ };
enum ArrayType {
ARRAY_VERTEX = RenderingServer::ARRAY_VERTEX,
ARRAY_NORMAL = RenderingServer::ARRAY_NORMAL,
@@ -61,6 +64,10 @@ public:
ARRAY_COLOR = RenderingServer::ARRAY_COLOR,
ARRAY_TEX_UV = RenderingServer::ARRAY_TEX_UV,
ARRAY_TEX_UV2 = RenderingServer::ARRAY_TEX_UV2,
+ ARRAY_CUSTOM0 = RenderingServer::ARRAY_CUSTOM0,
+ ARRAY_CUSTOM1 = RenderingServer::ARRAY_CUSTOM1,
+ ARRAY_CUSTOM2 = RenderingServer::ARRAY_CUSTOM2,
+ ARRAY_CUSTOM3 = RenderingServer::ARRAY_CUSTOM3,
ARRAY_BONES = RenderingServer::ARRAY_BONES,
ARRAY_WEIGHTS = RenderingServer::ARRAY_WEIGHTS,
ARRAY_INDEX = RenderingServer::ARRAY_INDEX,
@@ -68,30 +75,47 @@ public:
};
+ enum ArrayCustomFormat {
+ ARRAY_CUSTOM_RGBA8_UNORM,
+ ARRAY_CUSTOM_RGBA8_SNORM,
+ ARRAY_CUSTOM_RG_HALF,
+ ARRAY_CUSTOM_RGBA_HALF,
+ ARRAY_CUSTOM_R_FLOAT,
+ ARRAY_CUSTOM_RG_FLOAT,
+ ARRAY_CUSTOM_RGB_FLOAT,
+ ARRAY_CUSTOM_RGBA_FLOAT,
+ ARRAY_CUSTOM_MAX
+ };
+
enum ArrayFormat {
- /* ARRAY FORMAT FLAGS */
- ARRAY_FORMAT_VERTEX = 1 << ARRAY_VERTEX, // mandatory
- ARRAY_FORMAT_NORMAL = 1 << ARRAY_NORMAL,
- ARRAY_FORMAT_TANGENT = 1 << ARRAY_TANGENT,
- ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR,
- ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV,
- ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2,
- ARRAY_FORMAT_BONES = 1 << ARRAY_BONES,
- ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS,
- ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX,
-
- ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1),
- ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE),
-
- ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1,
- ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
-
- ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2
+ ARRAY_FORMAT_VERTEX = RS::ARRAY_FORMAT_VERTEX,
+ ARRAY_FORMAT_NORMAL = RS::ARRAY_FORMAT_NORMAL,
+ ARRAY_FORMAT_TANGENT = RS::ARRAY_FORMAT_TANGENT,
+ ARRAY_FORMAT_COLOR = RS::ARRAY_FORMAT_COLOR,
+ ARRAY_FORMAT_TEX_UV = RS::ARRAY_FORMAT_TEX_UV,
+ ARRAY_FORMAT_TEX_UV2 = RS::ARRAY_FORMAT_TEX_UV2,
+ ARRAY_FORMAT_CUSTOM0 = RS::ARRAY_FORMAT_CUSTOM0,
+ ARRAY_FORMAT_CUSTOM1 = RS::ARRAY_FORMAT_CUSTOM1,
+ ARRAY_FORMAT_CUSTOM2 = RS::ARRAY_FORMAT_CUSTOM2,
+ ARRAY_FORMAT_CUSTOM3 = RS::ARRAY_FORMAT_CUSTOM3,
+ ARRAY_FORMAT_BONES = RS::ARRAY_FORMAT_BONES,
+ ARRAY_FORMAT_WEIGHTS = RS::ARRAY_FORMAT_WEIGHTS,
+ ARRAY_FORMAT_INDEX = RS::ARRAY_FORMAT_INDEX,
+
+ ARRAY_FORMAT_BLEND_SHAPE_MASK = RS::ARRAY_FORMAT_BLEND_SHAPE_MASK,
+
+ ARRAY_FORMAT_CUSTOM_BASE = RS::ARRAY_FORMAT_CUSTOM_BASE,
+ ARRAY_FORMAT_CUSTOM0_SHIFT = RS::ARRAY_FORMAT_CUSTOM0_SHIFT,
+ ARRAY_FORMAT_CUSTOM1_SHIFT = RS::ARRAY_FORMAT_CUSTOM1_SHIFT,
+ ARRAY_FORMAT_CUSTOM2_SHIFT = RS::ARRAY_FORMAT_CUSTOM2_SHIFT,
+ ARRAY_FORMAT_CUSTOM3_SHIFT = RS::ARRAY_FORMAT_CUSTOM3_SHIFT,
+
+ ARRAY_FORMAT_CUSTOM_MASK = RS::ARRAY_FORMAT_CUSTOM_MASK,
+ ARRAY_COMPRESS_FLAGS_BASE = RS::ARRAY_COMPRESS_FLAGS_BASE,
+
+ ARRAY_FLAG_USE_2D_VERTICES = RS::ARRAY_FLAG_USE_2D_VERTICES,
+ ARRAY_FLAG_USE_DYNAMIC_UPDATE = RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE,
+ ARRAY_FLAG_USE_8_BONE_WEIGHTS = RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS,
};
@@ -104,11 +128,6 @@ public:
PRIMITIVE_MAX = RenderingServer::PRIMITIVE_MAX,
};
- enum BlendShapeMode {
- BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED,
- BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE,
- };
-
virtual int get_surface_count() const = 0;
virtual int surface_get_array_len(int p_idx) const = 0;
virtual int surface_get_array_index_len(int p_idx) const = 0;
@@ -152,6 +171,9 @@ class ArrayMesh : public Mesh {
GDCLASS(ArrayMesh, Mesh);
RES_BASE_EXTENSION("mesh");
+ PackedStringArray _get_blend_shape_names() const;
+ void _set_blend_shape_names(const PackedStringArray &p_names);
+
Array _get_surfaces() const;
void _set_surfaces(const Array &p_data);
@@ -187,9 +209,9 @@ protected:
static void _bind_methods();
public:
- void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = ARRAY_COMPRESS_DEFAULT);
+ void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0);
- void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t>> &p_blend_shapes = Vector<Vector<uint8_t>>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
+ void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
Array surface_get_arrays(int p_surface) const override;
Array surface_get_blend_shape_arrays(int p_surface) const override;
@@ -244,6 +266,7 @@ public:
VARIANT_ENUM_CAST(Mesh::ArrayType);
VARIANT_ENUM_CAST(Mesh::ArrayFormat);
+VARIANT_ENUM_CAST(Mesh::ArrayCustomFormat);
VARIANT_ENUM_CAST(Mesh::PrimitiveType);
VARIANT_ENUM_CAST(Mesh::BlendShapeMode);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 5ce253f970..09674f3465 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -1481,16 +1481,6 @@ int SceneState::add_name(const StringName &p_name) {
return names.size() - 1;
}
-int SceneState::find_name(const StringName &p_name) const {
- for (int i = 0; i < names.size(); i++) {
- if (names[i] == p_name) {
- return i;
- }
- }
-
- return -1;
-}
-
int SceneState::add_value(const Variant &p_value) {
variants.push_back(p_value);
return variants.size() - 1;
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index b8b3f84ecc..fce3891507 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -172,7 +172,6 @@ public:
//build API
int add_name(const StringName &p_name);
- int find_name(const StringName &p_name) const;
int add_value(const Variant &p_value);
int add_node_path(const NodePath &p_path);
int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index a286184aee..e2f96c54cb 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -329,7 +329,7 @@ void ParticlesMaterial::_update_shader() {
code += " float tex_linear_velocity = 0.0;\n";
}
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n";
code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n";
@@ -377,7 +377,7 @@ void ParticlesMaterial::_update_shader() {
code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n";
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " mat2 rotm;";
code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n";
code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n";
@@ -398,7 +398,7 @@ void ParticlesMaterial::_update_shader() {
code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " VELOCITY.z = 0.0;\n";
code += " TRANSFORM[3].z = 0.0;\n";
}
@@ -413,7 +413,7 @@ void ParticlesMaterial::_update_shader() {
code += " float tex_linear_velocity = 0.0;\n";
}
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
} else {
@@ -471,7 +471,7 @@ void ParticlesMaterial::_update_shader() {
code += " vec3 force = gravity;\n";
code += " vec3 pos = TRANSFORM[3].xyz;\n";
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " pos.z = 0.0;\n";
}
code += " // apply linear acceleration\n";
@@ -481,7 +481,7 @@ void ParticlesMaterial::_update_shader() {
code += " vec3 diff = pos - org;\n";
code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n";
code += " // apply tangential acceleration;\n";
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
} else {
@@ -495,7 +495,7 @@ void ParticlesMaterial::_update_shader() {
code += " // apply attractor forces\n";
code += " VELOCITY += force * DELTA;\n";
code += " // orbit velocity\n";
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);\n";
code += " if (orbit_amount != 0.0) {\n";
code += " float ang = orbit_amount * DELTA * pi * 2.0;\n";
@@ -562,8 +562,8 @@ void ParticlesMaterial::_update_shader() {
}
code += "\n";
- if (flags[FLAG_DISABLE_Z]) {
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
code += " if (length(VELOCITY) > 0.0) {\n";
code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n";
code += " } else {\n";
@@ -579,7 +579,7 @@ void ParticlesMaterial::_update_shader() {
} else {
// orient particle Y towards velocity
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
code += " if (length(VELOCITY) > 0.0) {\n";
code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n";
code += " } else {\n";
@@ -598,7 +598,7 @@ void ParticlesMaterial::_update_shader() {
code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n";
}
// turn particle by rotation in Y
- if (flags[FLAG_ROTATE_Y]) {
+ if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) {
code += " TRANSFORM = TRANSFORM * mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
}
@@ -611,7 +611,7 @@ void ParticlesMaterial::_update_shader() {
code += " TRANSFORM[0].xyz *= base_scale;\n";
code += " TRANSFORM[1].xyz *= base_scale;\n";
code += " TRANSFORM[2].xyz *= base_scale;\n";
- if (flags[FLAG_DISABLE_Z]) {
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " VELOCITY.z = 0.0;\n";
code += " TRANSFORM[3].z = 0.0;\n";
}
@@ -916,18 +916,18 @@ Ref<Texture2D> ParticlesMaterial::get_color_ramp() const {
return color_ramp;
}
-void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) {
- ERR_FAIL_INDEX(p_flag, FLAG_MAX);
- flags[p_flag] = p_enable;
+void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
+ ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX);
+ particle_flags[p_particle_flag] = p_enable;
_queue_shader_change();
- if (p_flag == FLAG_DISABLE_Z) {
+ if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) {
_change_notify();
}
}
-bool ParticlesMaterial::get_flag(Flags p_flag) const {
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags[p_flag];
+bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const {
+ ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false);
+ return particle_flags[p_particle_flag];
}
void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) {
@@ -1056,7 +1056,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
+ if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
property.usage = 0;
}
}
@@ -1170,8 +1170,8 @@ void ParticlesMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp);
ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp);
- ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag);
- ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag);
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticlesMaterial::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticlesMaterial::get_particle_flag);
ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape);
ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape);
@@ -1238,10 +1238,10 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_normal_texture", "get_emission_normal_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_emission_color_texture", "get_emission_color_texture");
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count");
- ADD_GROUP("Flags", "flag_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_flag", "get_flag", FLAG_DISABLE_Z);
+ ADD_GROUP("ParticleFlags", "particle_flag_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z);
ADD_GROUP("Direction", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
@@ -1327,10 +1327,10 @@ void ParticlesMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
BIND_ENUM_CONSTANT(PARAM_MAX);
- BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
- BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
- BIND_ENUM_CONSTANT(FLAG_DISABLE_Z);
- BIND_ENUM_CONSTANT(FLAG_MAX);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z);
+ BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
@@ -1385,8 +1385,8 @@ ParticlesMaterial::ParticlesMaterial() :
set_param_randomness(Parameter(i), 0);
}
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
+ for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
+ particle_flags[i] = false;
}
set_color(Color(1, 1, 1, 1));
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 12fa53ef29..7e8f05b706 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -61,11 +61,11 @@ public:
PARAM_MAX
};
- enum Flags {
- FLAG_ALIGN_Y_TO_VELOCITY,
- FLAG_ROTATE_Y,
- FLAG_DISABLE_Z,
- FLAG_MAX
+ enum ParticleFlags {
+ PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY,
+ PARTICLE_FLAG_ROTATE_Y,
+ PARTICLE_FLAG_DISABLE_Z,
+ PARTICLE_FLAG_MAX
};
enum EmissionShape {
@@ -90,7 +90,7 @@ private:
struct {
uint32_t texture_mask : 16;
uint32_t texture_color : 1;
- uint32_t flags : 4;
+ uint32_t particle_flags : 4;
uint32_t emission_shape : 2;
uint32_t invalid_key : 1;
uint32_t has_emission_color : 1;
@@ -124,9 +124,9 @@ private:
mk.texture_mask |= (1 << i);
}
}
- for (int i = 0; i < FLAG_MAX; i++) {
- if (flags[i]) {
- mk.flags |= (1 << i);
+ for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
+ if (particle_flags[i]) {
+ mk.particle_flags |= (1 << i);
}
}
@@ -227,7 +227,7 @@ private:
Color color;
Ref<Texture2D> color_ramp;
- bool flags[FLAG_MAX];
+ bool particle_flags[PARTICLE_FLAG_MAX];
EmissionShape emission_shape;
float emission_sphere_radius;
@@ -284,8 +284,8 @@ public:
void set_color_ramp(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_color_ramp() const;
- void set_flag(Flags p_flag, bool p_enable);
- bool get_flag(Flags p_flag) const;
+ void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable);
+ bool get_particle_flag(ParticleFlags p_particle_flag) const;
void set_emission_shape(EmissionShape p_shape);
void set_emission_sphere_radius(float p_radius);
@@ -349,7 +349,7 @@ public:
};
VARIANT_ENUM_CAST(ParticlesMaterial::Parameter)
-VARIANT_ENUM_CAST(ParticlesMaterial::Flags)
+VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags)
VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode)
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 8d9c5f07b2..06e181cb99 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -148,7 +148,7 @@ Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const {
uint32_t PrimitiveMesh::surface_get_format(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, 1, 0);
- return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX | RS::ARRAY_COMPRESS_DEFAULT;
+ return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX;
}
Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const {
@@ -477,10 +477,10 @@ CapsuleMesh::CapsuleMesh() {
}
/**
- CubeMesh
+ BoxMesh
*/
-void CubeMesh::_create_mesh_array(Array &p_arr) const {
+void BoxMesh::_create_mesh_array(Array &p_arr) const {
int i, j, prevrow, thisrow, point;
float x, y, z;
float onethird = 1.0 / 3.0;
@@ -672,16 +672,16 @@ void CubeMesh::_create_mesh_array(Array &p_arr) const {
p_arr[RS::ARRAY_INDEX] = indices;
}
-void CubeMesh::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_size", "size"), &CubeMesh::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &CubeMesh::get_size);
+void BoxMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxMesh::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &BoxMesh::get_size);
- ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &CubeMesh::set_subdivide_width);
- ClassDB::bind_method(D_METHOD("get_subdivide_width"), &CubeMesh::get_subdivide_width);
- ClassDB::bind_method(D_METHOD("set_subdivide_height", "divisions"), &CubeMesh::set_subdivide_height);
- ClassDB::bind_method(D_METHOD("get_subdivide_height"), &CubeMesh::get_subdivide_height);
- ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &CubeMesh::set_subdivide_depth);
- ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth);
+ ClassDB::bind_method(D_METHOD("set_subdivide_width", "subdivide"), &BoxMesh::set_subdivide_width);
+ ClassDB::bind_method(D_METHOD("get_subdivide_width"), &BoxMesh::get_subdivide_width);
+ ClassDB::bind_method(D_METHOD("set_subdivide_height", "divisions"), &BoxMesh::set_subdivide_height);
+ ClassDB::bind_method(D_METHOD("get_subdivide_height"), &BoxMesh::get_subdivide_height);
+ ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &BoxMesh::set_subdivide_depth);
+ ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &BoxMesh::get_subdivide_depth);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
@@ -689,43 +689,43 @@ void CubeMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
}
-void CubeMesh::set_size(const Vector3 &p_size) {
+void BoxMesh::set_size(const Vector3 &p_size) {
size = p_size;
_request_update();
}
-Vector3 CubeMesh::get_size() const {
+Vector3 BoxMesh::get_size() const {
return size;
}
-void CubeMesh::set_subdivide_width(const int p_divisions) {
+void BoxMesh::set_subdivide_width(const int p_divisions) {
subdivide_w = p_divisions > 0 ? p_divisions : 0;
_request_update();
}
-int CubeMesh::get_subdivide_width() const {
+int BoxMesh::get_subdivide_width() const {
return subdivide_w;
}
-void CubeMesh::set_subdivide_height(const int p_divisions) {
+void BoxMesh::set_subdivide_height(const int p_divisions) {
subdivide_h = p_divisions > 0 ? p_divisions : 0;
_request_update();
}
-int CubeMesh::get_subdivide_height() const {
+int BoxMesh::get_subdivide_height() const {
return subdivide_h;
}
-void CubeMesh::set_subdivide_depth(const int p_divisions) {
+void BoxMesh::set_subdivide_depth(const int p_divisions) {
subdivide_d = p_divisions > 0 ? p_divisions : 0;
_request_update();
}
-int CubeMesh::get_subdivide_depth() const {
+int BoxMesh::get_subdivide_depth() const {
return subdivide_d;
}
-CubeMesh::CubeMesh() {
+BoxMesh::BoxMesh() {
// defaults
size = Vector3(2.0, 2.0, 2.0);
subdivide_w = 0;
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index f0ae611b5e..02aea9c5c8 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -130,10 +130,10 @@ public:
};
/**
- Similar to test cube but with subdivision support and different texture coordinates
+ A box
*/
-class CubeMesh : public PrimitiveMesh {
- GDCLASS(CubeMesh, PrimitiveMesh);
+class BoxMesh : public PrimitiveMesh {
+ GDCLASS(BoxMesh, PrimitiveMesh);
private:
Vector3 size;
@@ -158,7 +158,7 @@ public:
void set_subdivide_depth(const int p_divisions);
int get_subdivide_depth() const;
- CubeMesh();
+ BoxMesh();
};
/**
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index cf8be8fe15..58645dbe65 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -704,7 +704,6 @@ ResourceLoaderText::ResourceLoaderText() {
resources_total = 0;
resource_current = 0;
- use_sub_threads = false;
progress = nullptr;
lines = false;
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index 69e8e0b5bd..05bb13a1e0 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -568,7 +568,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() {
code += "\tCOLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));\n";
code += "\tCOLOR *= exposure;\n";
code += "\t// Make optional, eliminates banding\n";
- code += "\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.008 * dither_strength;\n";
+ code += "\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;\n";
code += "}\n";
shader = RS::get_singleton()->shader_create();
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index a8bf44c5c0..14197c6c68 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -404,16 +404,6 @@ void StyleBoxFlat::set_corner_radius_individual(const int radius_top_left, const
emit_changed();
}
-int StyleBoxFlat::get_corner_radius_min() const {
- int smallest = corner_radius[0];
- for (int i = 1; i < 4; i++) {
- if (smallest > corner_radius[i]) {
- smallest = corner_radius[i];
- }
- }
- return smallest;
-}
-
void StyleBoxFlat::set_corner_radius(const Corner p_corner, const int radius) {
ERR_FAIL_INDEX((int)p_corner, 4);
corner_radius[p_corner] = radius;
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index a1237776c6..7dd806e840 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -184,7 +184,6 @@ public:
//CORNER
void set_corner_radius_all(int radius);
void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_botton_right, const int radius_bottom_left);
- int get_corner_radius_min() const;
void set_corner_radius(Corner p_corner, const int radius);
int get_corner_radius(Corner p_corner) const;
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index ff14a5a292..50308d641a 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -33,6 +33,9 @@
#define _VERTEX_SNAP 0.0001
#define EQ_VERTEX_DIST 0.00001
+SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr;
+SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr;
+
bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const {
if (vertex != p_vertex.vertex) {
return false;
@@ -74,6 +77,16 @@ bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const {
}
}
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ if (custom[i] != p_vertex.custom[i]) {
+ return false;
+ }
+ }
+
+ if (smooth_group != p_vertex.smooth_group) {
+ return false;
+ }
+
return true;
}
@@ -87,6 +100,8 @@ uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) {
h = hash_djb2_buffer((const uint8_t *)&p_vtx.color, sizeof(real_t) * 4, h);
h = hash_djb2_buffer((const uint8_t *)p_vtx.bones.ptr(), p_vtx.bones.size() * sizeof(int), h);
h = hash_djb2_buffer((const uint8_t *)p_vtx.weights.ptr(), p_vtx.weights.size() * sizeof(float), h);
+ h = hash_djb2_buffer((const uint8_t *)&p_vtx.custom[0], sizeof(Color) * RS::ARRAY_CUSTOM_COUNT, h);
+ h = hash_djb2_one_32(p_vtx.smooth_group, h);
return h;
}
@@ -111,8 +126,13 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
vtx.bones = last_bones;
vtx.tangent = last_tangent.normal;
vtx.binormal = last_normal.cross(last_tangent.normal).normalized() * last_tangent.d;
+ vtx.smooth_group = last_smooth_group;
+
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ vtx.custom[i] = last_custom[i];
+ }
- const int expected_vertices = 4;
+ const int expected_vertices = skin_weights == SKIN_8_WEIGHTS ? 8 : 4;
if ((format & Mesh::ARRAY_FORMAT_WEIGHTS || format & Mesh::ARRAY_FORMAT_BONES) && (vtx.weights.size() != expected_vertices || vtx.bones.size() != expected_vertices)) {
//ensure vertices are the expected amount
@@ -163,7 +183,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
format |= Mesh::ARRAY_FORMAT_VERTEX;
}
-void SurfaceTool::add_color(Color p_color) {
+void SurfaceTool::set_color(Color p_color) {
ERR_FAIL_COND(!begun);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_COLOR));
@@ -172,7 +192,7 @@ void SurfaceTool::add_color(Color p_color) {
last_color = p_color;
}
-void SurfaceTool::add_normal(const Vector3 &p_normal) {
+void SurfaceTool::set_normal(const Vector3 &p_normal) {
ERR_FAIL_COND(!begun);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_NORMAL));
@@ -181,7 +201,7 @@ void SurfaceTool::add_normal(const Vector3 &p_normal) {
last_normal = p_normal;
}
-void SurfaceTool::add_tangent(const Plane &p_tangent) {
+void SurfaceTool::set_tangent(const Plane &p_tangent) {
ERR_FAIL_COND(!begun);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TANGENT));
@@ -189,7 +209,7 @@ void SurfaceTool::add_tangent(const Plane &p_tangent) {
last_tangent = p_tangent;
}
-void SurfaceTool::add_uv(const Vector2 &p_uv) {
+void SurfaceTool::set_uv(const Vector2 &p_uv) {
ERR_FAIL_COND(!begun);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TEX_UV));
@@ -197,7 +217,7 @@ void SurfaceTool::add_uv(const Vector2 &p_uv) {
last_uv = p_uv;
}
-void SurfaceTool::add_uv2(const Vector2 &p_uv2) {
+void SurfaceTool::set_uv2(const Vector2 &p_uv2) {
ERR_FAIL_COND(!begun);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_TEX_UV2));
@@ -205,29 +225,45 @@ void SurfaceTool::add_uv2(const Vector2 &p_uv2) {
last_uv2 = p_uv2;
}
-void SurfaceTool::add_bones(const Vector<int> &p_bones) {
+void SurfaceTool::set_custom(int p_index, const Color &p_custom) {
+ ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
+ ERR_FAIL_COND(!begun);
+ ERR_FAIL_COND(last_custom_format[p_index] == CUSTOM_MAX);
+ static const uint32_t mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 };
+ static const uint32_t shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
+ ERR_FAIL_COND(!first && !(format & mask[p_index]));
+
+ if (first) {
+ format |= mask[p_index];
+ format |= last_custom_format[p_index] << shift[p_index];
+ }
+ last_custom[p_index] = p_custom;
+}
+
+void SurfaceTool::set_bones(const Vector<int> &p_bones) {
ERR_FAIL_COND(!begun);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_BONES));
format |= Mesh::ARRAY_FORMAT_BONES;
+ if (skin_weights == SKIN_8_WEIGHTS) {
+ format |= Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+ }
last_bones = p_bones;
}
-void SurfaceTool::add_weights(const Vector<float> &p_weights) {
+void SurfaceTool::set_weights(const Vector<float> &p_weights) {
ERR_FAIL_COND(!begun);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_WEIGHTS));
format |= Mesh::ARRAY_FORMAT_WEIGHTS;
+ if (skin_weights == SKIN_8_WEIGHTS) {
+ format |= Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+ }
last_weights = p_weights;
}
-void SurfaceTool::add_smooth_group(bool p_smooth) {
- ERR_FAIL_COND(!begun);
- if (index_array.size()) {
- smooth_groups[index_array.size()] = p_smooth;
- } else {
- smooth_groups[vertex_array.size()] = p_smooth;
- }
+void SurfaceTool::set_smooth_group(uint32_t p_group) {
+ last_smooth_group = p_group;
}
void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<Color> &p_colors, const Vector<Vector2> &p_uv2s, const Vector<Vector3> &p_normals, const Vector<Plane> &p_tangents) {
@@ -238,15 +274,15 @@ void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vect
#define ADD_POINT(n) \
{ \
if (p_colors.size() > n) \
- add_color(p_colors[n]); \
+ set_color(p_colors[n]); \
if (p_uvs.size() > n) \
- add_uv(p_uvs[n]); \
+ set_uv(p_uvs[n]); \
if (p_uv2s.size() > n) \
- add_uv2(p_uv2s[n]); \
+ set_uv2(p_uv2s[n]); \
if (p_normals.size() > n) \
- add_normal(p_normals[n]); \
+ set_normal(p_normals[n]); \
if (p_tangents.size() > n) \
- add_tangent(p_tangents[n]); \
+ set_tangent(p_tangents[n]); \
add_vertex(p_vertices[n]); \
}
@@ -284,9 +320,8 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len);
Vector3 *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
switch (i) {
case Mesh::ARRAY_VERTEX: {
@@ -308,9 +343,8 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len);
Vector2 *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
switch (i) {
case Mesh::ARRAY_TEX_UV: {
@@ -329,9 +363,8 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len * 4);
float *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
w[idx + 0] = v.tangent.x;
w[idx + 1] = v.tangent.y;
@@ -350,27 +383,165 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(varr_len);
Color *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx++) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
w[idx] = v.color;
}
a[i] = array;
} break;
+ case Mesh::ARRAY_CUSTOM0:
+ case Mesh::ARRAY_CUSTOM1:
+ case Mesh::ARRAY_CUSTOM2:
+ case Mesh::ARRAY_CUSTOM3: {
+ int fmt = i - Mesh::ARRAY_CUSTOM0;
+ switch (last_custom_format[fmt]) {
+ case CUSTOM_RGBA8_UNORM: {
+ Vector<uint8_t> array;
+ array.resize(varr_len * 4);
+ uint8_t *w = array.ptrw();
+
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ const Color &c = v.custom[idx];
+ w[idx * 4 + 0] = CLAMP(int32_t(c.r * 255.0), 0, 255);
+ w[idx * 4 + 1] = CLAMP(int32_t(c.g * 255.0), 0, 255);
+ w[idx * 4 + 2] = CLAMP(int32_t(c.b * 255.0), 0, 255);
+ w[idx * 4 + 3] = CLAMP(int32_t(c.a * 255.0), 0, 255);
+ }
+
+ a[i] = array;
+ } break;
+ case CUSTOM_RGBA8_SNORM: {
+ Vector<uint8_t> array;
+ array.resize(varr_len * 4);
+ uint8_t *w = array.ptrw();
+
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ const Color &c = v.custom[idx];
+ w[idx * 4 + 0] = uint8_t(int8_t(CLAMP(int32_t(c.r * 127.0), -128, 127)));
+ w[idx * 4 + 1] = uint8_t(int8_t(CLAMP(int32_t(c.g * 127.0), -128, 127)));
+ w[idx * 4 + 2] = uint8_t(int8_t(CLAMP(int32_t(c.b * 127.0), -128, 127)));
+ w[idx * 4 + 3] = uint8_t(int8_t(CLAMP(int32_t(c.a * 127.0), -128, 127)));
+ }
+
+ a[i] = array;
+ } break;
+ case CUSTOM_RG_HALF: {
+ Vector<uint8_t> array;
+ array.resize(varr_len * 4);
+ uint16_t *w = (uint16_t *)array.ptrw();
+
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ const Color &c = v.custom[idx];
+ w[idx * 2 + 0] = Math::make_half_float(c.r);
+ w[idx * 2 + 1] = Math::make_half_float(c.g);
+ }
+
+ a[i] = array;
+ } break;
+ case CUSTOM_RGBA_HALF: {
+ Vector<uint8_t> array;
+ array.resize(varr_len * 8);
+ uint16_t *w = (uint16_t *)array.ptrw();
+
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ const Color &c = v.custom[idx];
+ w[idx * 4 + 0] = Math::make_half_float(c.r);
+ w[idx * 4 + 1] = Math::make_half_float(c.g);
+ w[idx * 4 + 2] = Math::make_half_float(c.b);
+ w[idx * 4 + 3] = Math::make_half_float(c.a);
+ }
+
+ a[i] = array;
+ } break;
+ case CUSTOM_R_FLOAT: {
+ Vector<float> array;
+ array.resize(varr_len);
+ float *w = (float *)array.ptrw();
+
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ const Color &c = v.custom[idx];
+ w[idx] = c.r;
+ }
+
+ a[i] = array;
+ } break;
+ case CUSTOM_RG_FLOAT: {
+ Vector<float> array;
+ array.resize(varr_len * 2);
+ float *w = (float *)array.ptrw();
+
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ const Color &c = v.custom[idx];
+ w[idx * 2 + 0] = c.r;
+ w[idx * 2 + 1] = c.g;
+ }
+
+ a[i] = array;
+ } break;
+ case CUSTOM_RGB_FLOAT: {
+ Vector<float> array;
+ array.resize(varr_len * 3);
+ float *w = (float *)array.ptrw();
+
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ const Color &c = v.custom[idx];
+ w[idx * 3 + 0] = c.r;
+ w[idx * 3 + 1] = c.g;
+ w[idx * 3 + 2] = c.b;
+ }
+
+ a[i] = array;
+ } break;
+ case CUSTOM_RGBA_FLOAT: {
+ Vector<float> array;
+ array.resize(varr_len * 4);
+ float *w = (float *)array.ptrw();
+
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ const Color &c = v.custom[idx];
+ w[idx * 4 + 0] = c.r;
+ w[idx * 4 + 1] = c.g;
+ w[idx * 4 + 2] = c.b;
+ w[idx * 4 + 3] = c.a;
+ }
+
+ a[i] = array;
+ } break;
+ default: {
+ } //unreachable but compiler warning anyway
+ }
+ } break;
case Mesh::ARRAY_BONES: {
+ int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4;
Vector<int> array;
- array.resize(varr_len * 4);
+ array.resize(varr_len * count);
int *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) {
- const Vertex &v = E->get();
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
- ERR_CONTINUE(v.bones.size() != 4);
+ ERR_CONTINUE(v.bones.size() != count);
- for (int j = 0; j < 4; j++) {
- w[idx + j] = v.bones[j];
+ for (int j = 0; j < count; j++) {
+ w[idx * count + j] = v.bones[j];
}
}
@@ -379,16 +550,18 @@ Array SurfaceTool::commit_to_arrays() {
} break;
case Mesh::ARRAY_WEIGHTS: {
Vector<float> array;
- array.resize(varr_len * 4);
+ int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4;
+
+ array.resize(varr_len * count);
float *w = array.ptrw();
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next(), idx += 4) {
- const Vertex &v = E->get();
- ERR_CONTINUE(v.weights.size() != 4);
+ for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
+ const Vertex &v = vertex_array[idx];
+
+ ERR_CONTINUE(v.weights.size() != count);
- for (int j = 0; j < 4; j++) {
- w[idx + j] = v.weights[j];
+ for (int j = 0; j < count; j++) {
+ w[idx * count + j] = v.weights[j];
}
}
@@ -402,9 +575,8 @@ Array SurfaceTool::commit_to_arrays() {
array.resize(index_array.size());
int *w = array.ptrw();
- int idx = 0;
- for (List<int>::Element *E = index_array.front(); E; E = E->next(), idx++) {
- w[idx] = E->get();
+ for (uint32_t idx = 0; idx < index_array.size(); idx++) {
+ w[idx] = index_array[idx];
}
a[i] = array;
@@ -451,15 +623,16 @@ void SurfaceTool::index() {
}
HashMap<Vertex, int, VertexHasher> indices;
- List<Vertex> new_vertices;
+ LocalVector<Vertex> old_vertex_array = vertex_array;
+ vertex_array.clear();
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) {
- int *idxptr = indices.getptr(E->get());
+ for (uint32_t i = 0; i < old_vertex_array.size(); i++) {
+ int *idxptr = indices.getptr(old_vertex_array[i]);
int idx;
if (!idxptr) {
idx = indices.size();
- new_vertices.push_back(E->get());
- indices[E->get()] = idx;
+ vertex_array.push_back(old_vertex_array[i]);
+ indices[old_vertex_array[i]] = idx;
} else {
idx = *idxptr;
}
@@ -467,9 +640,6 @@ void SurfaceTool::index() {
index_array.push_back(idx);
}
- vertex_array.clear();
- vertex_array = new_vertices;
-
format |= Mesh::ARRAY_FORMAT_INDEX;
}
@@ -477,29 +647,26 @@ void SurfaceTool::deindex() {
if (index_array.size() == 0) {
return; //nothing to deindex
}
- Vector<Vertex> varr;
- varr.resize(vertex_array.size());
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) {
- varr.write[idx++] = E->get();
- }
+
+ LocalVector<Vertex> old_vertex_array = vertex_array;
vertex_array.clear();
- for (List<int>::Element *E = index_array.front(); E; E = E->next()) {
- ERR_FAIL_INDEX(E->get(), varr.size());
- vertex_array.push_back(varr[E->get()]);
+ for (uint32_t i = 0; i < index_array.size(); i++) {
+ uint32_t index = index_array[i];
+ ERR_FAIL_COND(index >= old_vertex_array.size());
+ vertex_array.push_back(old_vertex_array[index]);
}
format &= ~Mesh::ARRAY_FORMAT_INDEX;
index_array.clear();
}
-void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
+void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) {
Array arr = p_existing->surface_get_arrays(p_surface);
ERR_FAIL_COND(arr.size() != RS::ARRAY_MAX);
_create_list_from_arrays(arr, r_vertex, r_index, lformat);
}
-Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays) {
- Vector<SurfaceTool::Vertex> ret;
+void SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector<SurfaceTool::Vertex> &ret, uint32_t *r_format) {
+ ret.clear();
Vector<Vector3> varr = p_arrays[RS::ARRAY_VERTEX];
Vector<Vector3> narr = p_arrays[RS::ARRAY_NORMAL];
@@ -509,10 +676,14 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
Vector<Vector2> uv2arr = p_arrays[RS::ARRAY_TEX_UV2];
Vector<int> barr = p_arrays[RS::ARRAY_BONES];
Vector<float> warr = p_arrays[RS::ARRAY_WEIGHTS];
+ Vector<float> custom_float[RS::ARRAY_CUSTOM_COUNT];
int vc = varr.size();
if (vc == 0) {
- return ret;
+ if (r_format) {
+ *r_format = 0;
+ }
+ return;
}
int lformat = 0;
@@ -534,100 +705,40 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
if (uv2arr.size()) {
lformat |= RS::ARRAY_FORMAT_TEX_UV2;
}
- if (barr.size()) {
+ int wcount = 0;
+ if (barr.size() && warr.size()) {
lformat |= RS::ARRAY_FORMAT_BONES;
- }
- if (warr.size()) {
lformat |= RS::ARRAY_FORMAT_WEIGHTS;
- }
- for (int i = 0; i < vc; i++) {
- Vertex v;
- if (lformat & RS::ARRAY_FORMAT_VERTEX) {
- v.vertex = varr[i];
- }
- if (lformat & RS::ARRAY_FORMAT_NORMAL) {
- v.normal = narr[i];
- }
- if (lformat & RS::ARRAY_FORMAT_TANGENT) {
- Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]);
- v.tangent = p.normal;
- v.binormal = p.normal.cross(v.tangent).normalized() * p.d;
- }
- if (lformat & RS::ARRAY_FORMAT_COLOR) {
- v.color = carr[i];
- }
- if (lformat & RS::ARRAY_FORMAT_TEX_UV) {
- v.uv = uvarr[i];
- }
- if (lformat & RS::ARRAY_FORMAT_TEX_UV2) {
- v.uv2 = uv2arr[i];
+ wcount = barr.size() / varr.size();
+ if (wcount == 8) {
+ lformat |= RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
}
- if (lformat & RS::ARRAY_FORMAT_BONES) {
- Vector<int> b;
- b.resize(4);
- b.write[0] = barr[i * 4 + 0];
- b.write[1] = barr[i * 4 + 1];
- b.write[2] = barr[i * 4 + 2];
- b.write[3] = barr[i * 4 + 3];
- v.bones = b;
- }
- if (lformat & RS::ARRAY_FORMAT_WEIGHTS) {
- Vector<float> w;
- w.resize(4);
- w.write[0] = warr[i * 4 + 0];
- w.write[1] = warr[i * 4 + 1];
- w.write[2] = warr[i * 4 + 2];
- w.write[3] = warr[i * 4 + 3];
- v.weights = w;
- }
-
- ret.push_back(v);
}
- return ret;
-}
-
-void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
- Vector<Vector3> varr = arr[RS::ARRAY_VERTEX];
- Vector<Vector3> narr = arr[RS::ARRAY_NORMAL];
- Vector<float> tarr = arr[RS::ARRAY_TANGENT];
- Vector<Color> carr = arr[RS::ARRAY_COLOR];
- Vector<Vector2> uvarr = arr[RS::ARRAY_TEX_UV];
- Vector<Vector2> uv2arr = arr[RS::ARRAY_TEX_UV2];
- Vector<int> barr = arr[RS::ARRAY_BONES];
- Vector<float> warr = arr[RS::ARRAY_WEIGHTS];
-
- int vc = varr.size();
- if (vc == 0) {
- return;
- }
-
- lformat = 0;
- if (varr.size()) {
- lformat |= RS::ARRAY_FORMAT_VERTEX;
- }
- if (narr.size()) {
- lformat |= RS::ARRAY_FORMAT_NORMAL;
- }
- if (tarr.size()) {
- lformat |= RS::ARRAY_FORMAT_TANGENT;
- }
- if (carr.size()) {
- lformat |= RS::ARRAY_FORMAT_COLOR;
- }
- if (uvarr.size()) {
- lformat |= RS::ARRAY_FORMAT_TEX_UV;
- }
- if (uv2arr.size()) {
- lformat |= RS::ARRAY_FORMAT_TEX_UV2;
- }
- if (barr.size()) {
- lformat |= RS::ARRAY_FORMAT_BONES;
- }
if (warr.size()) {
lformat |= RS::ARRAY_FORMAT_WEIGHTS;
}
+ static const uint32_t custom_mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 };
+ static const uint32_t custom_shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
+
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ ERR_CONTINUE_MSG(p_arrays[RS::ARRAY_CUSTOM0 + i].get_type() == Variant::PACKED_BYTE_ARRAY, "Extracting Byte/Half formats is not supported");
+ if (p_arrays[RS::ARRAY_CUSTOM0 + i].get_type() == Variant::PACKED_FLOAT32_ARRAY) {
+ lformat |= custom_mask[i];
+ custom_float[i] = p_arrays[RS::ARRAY_CUSTOM0 + i];
+ int fmt = custom_float[i].size() / varr.size();
+ if (fmt == 1) {
+ lformat |= CUSTOM_R_FLOAT << custom_shift[i];
+ } else if (fmt == 2) {
+ lformat |= CUSTOM_RG_FLOAT << custom_shift[i];
+ } else if (fmt == 3) {
+ lformat |= CUSTOM_RGB_FLOAT << custom_shift[i];
+ } else if (fmt == 4) {
+ lformat |= CUSTOM_RGBA_FLOAT << custom_shift[i];
+ }
+ }
+ }
for (int i = 0; i < vc; i++) {
Vertex v;
@@ -653,27 +764,44 @@ void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, Li
}
if (lformat & RS::ARRAY_FORMAT_BONES) {
Vector<int> b;
- b.resize(4);
- b.write[0] = barr[i * 4 + 0];
- b.write[1] = barr[i * 4 + 1];
- b.write[2] = barr[i * 4 + 2];
- b.write[3] = barr[i * 4 + 3];
+ b.resize(wcount);
+ for (int j = 0; j < wcount; j++) {
+ b.write[j] = barr[i * wcount + j];
+ }
v.bones = b;
}
if (lformat & RS::ARRAY_FORMAT_WEIGHTS) {
Vector<float> w;
- w.resize(4);
- w.write[0] = warr[i * 4 + 0];
- w.write[1] = warr[i * 4 + 1];
- w.write[2] = warr[i * 4 + 2];
- w.write[3] = warr[i * 4 + 3];
+ w.resize(wcount);
+ for (int j = 0; j < wcount; j++) {
+ w.write[j] = warr[i * wcount + j];
+ }
v.weights = w;
}
- r_vertex->push_back(v);
+ for (int j = 0; j < RS::ARRAY_CUSTOM_COUNT; j++) {
+ if (lformat & custom_mask[j]) {
+ int cc = custom_float[j].size() / varr.size();
+ for (int k = 0; k < cc; k++) {
+ v.custom[j][k] = custom_float[j][i * cc + k];
+ }
+ }
+ }
+
+ ret.push_back(v);
}
+ if (r_format) {
+ *r_format = lformat;
+ }
+}
+
+void SurfaceTool::_create_list_from_arrays(Array arr, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) {
+ create_vertex_array_from_triangle_arrays(arr, *r_vertex, &lformat);
+ ERR_FAIL_COND(r_vertex->size() == 0);
+
//indices
+ r_index->clear();
Vector<int> idx = arr[RS::ARRAY_INDEX];
int is = idx.size();
@@ -725,15 +853,15 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
format = 0;
}
- int nformat;
- List<Vertex> nvertices;
- List<int> nindices;
+ uint32_t nformat;
+ LocalVector<Vertex> nvertices;
+ LocalVector<int> nindices;
_create_list(p_existing, p_surface, &nvertices, &nindices, nformat);
format |= nformat;
int vfrom = vertex_array.size();
- for (List<Vertex>::Element *E = nvertices.front(); E; E = E->next()) {
- Vertex v = E->get();
+ for (uint32_t vi = 0; vi < nvertices.size(); vi++) {
+ Vertex v = nvertices[vi];
v.vertex = p_xform.xform(v.vertex);
if (nformat & RS::ARRAY_FORMAT_NORMAL) {
v.normal = p_xform.basis.xform(v.normal);
@@ -746,8 +874,8 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
vertex_array.push_back(v);
}
- for (List<int>::Element *E = nindices.front(); E; E = E->next()) {
- int dst_index = E->get() + vfrom;
+ for (uint32_t i = 0; i < nindices.size(); i++) {
+ int dst_index = nindices[i] + vfrom;
index_array.push_back(dst_index);
}
if (index_array.size() % 3) {
@@ -758,18 +886,18 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
//mikktspace callbacks
namespace {
struct TangentGenerationContextUserData {
- Vector<List<SurfaceTool::Vertex>::Element *> vertices;
- Vector<List<int>::Element *> indices;
+ LocalVector<SurfaceTool::Vertex> *vertices;
+ LocalVector<int> *indices;
};
} // namespace
int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext *pContext) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
- if (triangle_data.indices.size() > 0) {
- return triangle_data.indices.size() / 3;
+ if (triangle_data.indices->size() > 0) {
+ return triangle_data.indices->size() / 3;
} else {
- return triangle_data.vertices.size() / 3;
+ return triangle_data.vertices->size() / 3;
}
}
@@ -780,13 +908,13 @@ int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, c
void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
Vector3 v;
- if (triangle_data.indices.size() > 0) {
- int index = triangle_data.indices[iFace * 3 + iVert]->get();
- if (index < triangle_data.vertices.size()) {
- v = triangle_data.vertices[index]->get().vertex;
+ if (triangle_data.indices->size() > 0) {
+ uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert);
+ if (index < triangle_data.vertices->size()) {
+ v = triangle_data.vertices->operator[](index).vertex;
}
} else {
- v = triangle_data.vertices[iFace * 3 + iVert]->get().vertex;
+ v = triangle_data.vertices->operator[](iFace * 3 + iVert).vertex;
}
fvPosOut[0] = v.x;
@@ -797,13 +925,13 @@ void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvP
void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
Vector3 v;
- if (triangle_data.indices.size() > 0) {
- int index = triangle_data.indices[iFace * 3 + iVert]->get();
- if (index < triangle_data.vertices.size()) {
- v = triangle_data.vertices[index]->get().normal;
+ if (triangle_data.indices->size() > 0) {
+ uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert);
+ if (index < triangle_data.vertices->size()) {
+ v = triangle_data.vertices->operator[](index).normal;
}
} else {
- v = triangle_data.vertices[iFace * 3 + iVert]->get().normal;
+ v = triangle_data.vertices->operator[](iFace * 3 + iVert).normal;
}
fvNormOut[0] = v.x;
@@ -814,13 +942,13 @@ void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNor
void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
Vector2 v;
- if (triangle_data.indices.size() > 0) {
- int index = triangle_data.indices[iFace * 3 + iVert]->get();
- if (index < triangle_data.vertices.size()) {
- v = triangle_data.vertices[index]->get().uv;
+ if (triangle_data.indices->size() > 0) {
+ uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert);
+ if (index < triangle_data.vertices->size()) {
+ v = triangle_data.vertices->operator[](index).uv;
}
} else {
- v = triangle_data.vertices[iFace * 3 + iVert]->get().uv;
+ v = triangle_data.vertices->operator[](iFace * 3 + iVert).uv;
}
fvTexcOut[0] = v.x;
@@ -831,13 +959,13 @@ void SurfaceTool::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, cons
const tbool bIsOrientationPreserving, const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
Vertex *vtx = nullptr;
- if (triangle_data.indices.size() > 0) {
- int index = triangle_data.indices[iFace * 3 + iVert]->get();
- if (index < triangle_data.vertices.size()) {
- vtx = &triangle_data.vertices[index]->get();
+ if (triangle_data.indices->size() > 0) {
+ uint32_t index = triangle_data.indices->operator[](iFace * 3 + iVert);
+ if (index < triangle_data.vertices->size()) {
+ vtx = &triangle_data.vertices->operator[](index);
}
} else {
- vtx = &triangle_data.vertices[iFace * 3 + iVert]->get();
+ vtx = &triangle_data.vertices->operator[](iFace * 3 + iVert);
}
if (vtx != nullptr) {
@@ -863,18 +991,12 @@ void SurfaceTool::generate_tangents() {
msc.m_pInterface = &mkif;
TangentGenerationContextUserData triangle_data;
- triangle_data.vertices.resize(vertex_array.size());
- int idx = 0;
- for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) {
- triangle_data.vertices.write[idx++] = E;
- E->get().binormal = Vector3();
- E->get().tangent = Vector3();
- }
- triangle_data.indices.resize(index_array.size());
- idx = 0;
- for (List<int>::Element *E = index_array.front(); E; E = E->next()) {
- triangle_data.indices.write[idx++] = E;
+ triangle_data.vertices = &vertex_array;
+ for (uint32_t i = 0; i < vertex_array.size(); i++) {
+ vertex_array[i].binormal = Vector3();
+ vertex_array[i].tangent = Vector3();
}
+ triangle_data.indices = &index_array;
msc.m_pUserData = &triangle_data;
bool res = genTangSpaceDefault(&msc);
@@ -890,66 +1012,36 @@ void SurfaceTool::generate_normals(bool p_flip) {
deindex();
- HashMap<Vertex, Vector3, VertexHasher> vertex_hash;
+ ERR_FAIL_COND((vertex_array.size() % 3) != 0);
- int count = 0;
- bool smooth = false;
- if (smooth_groups.has(0)) {
- smooth = smooth_groups[0];
- }
+ HashMap<Vertex, Vector3, VertexHasher> vertex_hash;
- List<Vertex>::Element *B = vertex_array.front();
- for (List<Vertex>::Element *E = B; E;) {
- List<Vertex>::Element *v[3];
- v[0] = E;
- v[1] = v[0]->next();
- ERR_FAIL_COND(!v[1]);
- v[2] = v[1]->next();
- ERR_FAIL_COND(!v[2]);
- E = v[2]->next();
+ for (uint32_t vi = 0; vi < vertex_array.size(); vi += 3) {
+ Vertex *v = &vertex_array[vi];
Vector3 normal;
if (!p_flip) {
- normal = Plane(v[0]->get().vertex, v[1]->get().vertex, v[2]->get().vertex).normal;
- } else {
- normal = Plane(v[2]->get().vertex, v[1]->get().vertex, v[0]->get().vertex).normal;
- }
-
- if (smooth) {
- for (int i = 0; i < 3; i++) {
- Vector3 *lv = vertex_hash.getptr(v[i]->get());
- if (!lv) {
- vertex_hash.set(v[i]->get(), normal);
- } else {
- (*lv) += normal;
- }
- }
+ normal = Plane(v[0].vertex, v[1].vertex, v[2].vertex).normal;
} else {
- for (int i = 0; i < 3; i++) {
- v[i]->get().normal = normal;
- }
+ normal = Plane(v[2].vertex, v[1].vertex, v[0].vertex).normal;
}
- count += 3;
-
- if (smooth_groups.has(count) || !E) {
- if (vertex_hash.size()) {
- while (B != E) {
- Vector3 *lv = vertex_hash.getptr(B->get());
- if (lv) {
- B->get().normal = lv->normalized();
- }
-
- B = B->next();
- }
+ for (int i = 0; i < 3; i++) {
+ Vector3 *lv = vertex_hash.getptr(v[i]);
+ if (!lv) {
+ vertex_hash.set(v[i], normal);
} else {
- B = E;
+ (*lv) += normal;
}
+ }
+ }
- vertex_hash.clear();
- if (E) {
- smooth = smooth_groups[count];
- }
+ for (uint32_t vi = 0; vi < vertex_array.size(); vi++) {
+ Vector3 *lv = vertex_hash.getptr(vertex_array[vi]);
+ if (!lv) {
+ vertex_array[vi].normal = Vector3();
+ } else {
+ vertex_array[vi].normal = lv->normalized();
}
}
@@ -957,7 +1049,6 @@ void SurfaceTool::generate_normals(bool p_flip) {
if (was_indexed) {
index();
- smooth_groups.clear();
}
}
@@ -973,22 +1064,97 @@ void SurfaceTool::clear() {
last_weights.clear();
index_array.clear();
vertex_array.clear();
- smooth_groups.clear();
material.unref();
+ last_smooth_group = 0;
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ last_custom_format[i] = CUSTOM_MAX;
+ }
+ skin_weights = SKIN_4_WEIGHTS;
+}
+
+void SurfaceTool::set_skin_weight_count(SkinWeightCount p_weights) {
+ ERR_FAIL_COND(begun);
+ skin_weights = p_weights;
+}
+SurfaceTool::SkinWeightCount SurfaceTool::get_skin_weight_count() const {
+ return skin_weights;
+}
+
+void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) {
+ ERR_FAIL_INDEX(p_index, RS::ARRAY_CUSTOM_COUNT);
+ ERR_FAIL_COND(begun);
+ last_custom_format[p_index] = p_format;
+}
+SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
+ return last_custom_format[p_index];
+}
+void SurfaceTool::optimize_indices_for_cache() {
+ ERR_FAIL_COND(optimize_vertex_cache_func == nullptr);
+ ERR_FAIL_COND(index_array.size() == 0);
+
+ LocalVector old_index_array = index_array;
+ zeromem(index_array.ptr(), index_array.size() * sizeof(int));
+ optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size());
+}
+
+float SurfaceTool::get_max_axis_length() const {
+ ERR_FAIL_COND_V(vertex_array.size() == 0, 0);
+
+ AABB aabb;
+ for (uint32_t i = 0; i < vertex_array.size(); i++) {
+ if (i == 0) {
+ aabb.position = vertex_array[i].vertex;
+ } else {
+ aabb.expand_to(vertex_array[i].vertex);
+ }
+ }
+
+ return aabb.get_longest_axis_size();
+}
+Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_count) {
+ Vector<int> lod;
+
+ ERR_FAIL_COND_V(simplify_func == nullptr, lod);
+ ERR_FAIL_COND_V(vertex_array.size() == 0, lod);
+ ERR_FAIL_COND_V(index_array.size() == 0, lod);
+
+ lod.resize(index_array.size());
+ LocalVector<float> vertices; //uses floats
+ vertices.resize(vertex_array.size() * 3);
+ for (uint32_t i = 0; i < vertex_array.size(); i++) {
+ vertices[i * 3 + 0] = vertex_array[i].vertex.x;
+ vertices[i * 3 + 1] = vertex_array[i].vertex.y;
+ vertices[i * 3 + 2] = vertex_array[i].vertex.z;
+ }
+
+ float error;
+ uint32_t index_count = simplify_func((unsigned int *)lod.ptrw(), (unsigned int *)index_array.ptr(), index_array.size(), vertices.ptr(), vertex_array.size(), sizeof(float) * 3, p_target_index_count, p_threshold, &error);
+ ERR_FAIL_COND_V(index_count == 0, lod);
+ lod.resize(index_count);
+
+ return lod;
}
void SurfaceTool::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_skin_weight_count", "count"), &SurfaceTool::set_skin_weight_count);
+ ClassDB::bind_method(D_METHOD("get_skin_weight_count"), &SurfaceTool::get_skin_weight_count);
+
+ ClassDB::bind_method(D_METHOD("set_custom_format", "index", "format"), &SurfaceTool::set_custom_format);
+ ClassDB::bind_method(D_METHOD("get_custom_format", "index"), &SurfaceTool::get_custom_format);
+
ClassDB::bind_method(D_METHOD("begin", "primitive"), &SurfaceTool::begin);
ClassDB::bind_method(D_METHOD("add_vertex", "vertex"), &SurfaceTool::add_vertex);
- ClassDB::bind_method(D_METHOD("add_color", "color"), &SurfaceTool::add_color);
- ClassDB::bind_method(D_METHOD("add_normal", "normal"), &SurfaceTool::add_normal);
- ClassDB::bind_method(D_METHOD("add_tangent", "tangent"), &SurfaceTool::add_tangent);
- ClassDB::bind_method(D_METHOD("add_uv", "uv"), &SurfaceTool::add_uv);
- ClassDB::bind_method(D_METHOD("add_uv2", "uv2"), &SurfaceTool::add_uv2);
- ClassDB::bind_method(D_METHOD("add_bones", "bones"), &SurfaceTool::add_bones);
- ClassDB::bind_method(D_METHOD("add_weights", "weights"), &SurfaceTool::add_weights);
- ClassDB::bind_method(D_METHOD("add_smooth_group", "smooth"), &SurfaceTool::add_smooth_group);
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &SurfaceTool::set_color);
+ ClassDB::bind_method(D_METHOD("set_normal", "normal"), &SurfaceTool::set_normal);
+ ClassDB::bind_method(D_METHOD("set_tangent", "tangent"), &SurfaceTool::set_tangent);
+ ClassDB::bind_method(D_METHOD("set_uv", "uv"), &SurfaceTool::set_uv);
+ ClassDB::bind_method(D_METHOD("set_uv2", "uv2"), &SurfaceTool::set_uv2);
+ ClassDB::bind_method(D_METHOD("set_bones", "bones"), &SurfaceTool::set_bones);
+ ClassDB::bind_method(D_METHOD("set_weights", "weights"), &SurfaceTool::set_weights);
+ ClassDB::bind_method(D_METHOD("set_custom", "index", "custom"), &SurfaceTool::set_custom);
+ ClassDB::bind_method(D_METHOD("set_smooth_group", "index"), &SurfaceTool::set_smooth_group);
ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertices", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>()));
@@ -999,6 +1165,11 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_normals", "flip"), &SurfaceTool::generate_normals, DEFVAL(false));
ClassDB::bind_method(D_METHOD("generate_tangents"), &SurfaceTool::generate_tangents);
+ ClassDB::bind_method(D_METHOD("optimize_indices_for_cache"), &SurfaceTool::optimize_indices_for_cache);
+
+ ClassDB::bind_method(D_METHOD("get_max_axis_length"), &SurfaceTool::get_max_axis_length);
+ ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3));
+
ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material);
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
@@ -1006,13 +1177,29 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from);
ClassDB::bind_method(D_METHOD("create_from_blend_shape", "existing", "surface", "blend_shape"), &SurfaceTool::create_from_blend_shape);
ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from);
- ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(0));
ClassDB::bind_method(D_METHOD("commit_to_arrays"), &SurfaceTool::commit_to_arrays);
+
+ BIND_ENUM_CONSTANT(CUSTOM_RGBA8_UNORM);
+ BIND_ENUM_CONSTANT(CUSTOM_RGBA8_SNORM);
+ BIND_ENUM_CONSTANT(CUSTOM_RG_HALF);
+ BIND_ENUM_CONSTANT(CUSTOM_RGBA_HALF);
+ BIND_ENUM_CONSTANT(CUSTOM_R_FLOAT);
+ BIND_ENUM_CONSTANT(CUSTOM_RG_FLOAT);
+ BIND_ENUM_CONSTANT(CUSTOM_RGB_FLOAT);
+ BIND_ENUM_CONSTANT(CUSTOM_RGBA_FLOAT);
+ BIND_ENUM_CONSTANT(CUSTOM_MAX);
+ BIND_ENUM_CONSTANT(SKIN_4_WEIGHTS);
+ BIND_ENUM_CONSTANT(SKIN_8_WEIGHTS);
}
SurfaceTool::SurfaceTool() {
first = false;
begun = false;
+ for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
+ last_custom_format[i] = CUSTOM_MAX;
+ }
primitive = Mesh::PRIMITIVE_LINES;
+ skin_weights = SKIN_4_WEIGHTS;
format = 0;
}
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index d7b255e695..0e60bfe389 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -31,8 +31,8 @@
#ifndef SURFACE_TOOL_H
#define SURFACE_TOOL_H
+#include "core/templates/local_vector.h"
#include "scene/resources/mesh.h"
-
#include "thirdparty/misc/mikktspace.h"
class SurfaceTool : public Reference {
@@ -49,12 +49,36 @@ public:
Vector2 uv2;
Vector<int> bones;
Vector<float> weights;
+ Color custom[RS::ARRAY_CUSTOM_COUNT];
+ uint32_t smooth_group = 0;
bool operator==(const Vertex &p_vertex) const;
Vertex() {}
};
+ enum CustomFormat {
+ CUSTOM_RGBA8_UNORM = RS::ARRAY_CUSTOM_RGBA8_UNORM,
+ CUSTOM_RGBA8_SNORM = RS::ARRAY_CUSTOM_RGBA8_SNORM,
+ CUSTOM_RG_HALF = RS::ARRAY_CUSTOM_RG_HALF,
+ CUSTOM_RGBA_HALF = RS::ARRAY_CUSTOM_RGBA_HALF,
+ CUSTOM_R_FLOAT = RS::ARRAY_CUSTOM_R_FLOAT,
+ CUSTOM_RG_FLOAT = RS::ARRAY_CUSTOM_RG_FLOAT,
+ CUSTOM_RGB_FLOAT = RS::ARRAY_CUSTOM_RGB_FLOAT,
+ CUSTOM_RGBA_FLOAT = RS::ARRAY_CUSTOM_RGBA_FLOAT,
+ CUSTOM_MAX = RS::ARRAY_CUSTOM_MAX
+ };
+
+ enum SkinWeightCount {
+ SKIN_4_WEIGHTS,
+ SKIN_8_WEIGHTS
+ };
+
+ 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, float *r_error);
+ static SimplifyFunc simplify_func;
+
private:
struct VertexHasher {
static _FORCE_INLINE_ uint32_t hash(const Vertex &p_vtx);
@@ -71,12 +95,11 @@ private:
bool begun;
bool first;
Mesh::PrimitiveType primitive;
- int format;
+ uint32_t format;
Ref<Material> material;
//arrays
- List<Vertex> vertex_array;
- List<int> index_array;
- Map<int, bool> smooth_groups;
+ LocalVector<Vertex> vertex_array;
+ LocalVector<int> index_array;
//memory
Color last_color;
@@ -86,9 +109,16 @@ private:
Vector<int> last_bones;
Vector<float> last_weights;
Plane last_tangent;
+ uint32_t last_smooth_group = 0;
+
+ SkinWeightCount skin_weights;
- void _create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat);
- void _create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat);
+ Color last_custom[RS::ARRAY_CUSTOM_COUNT];
+
+ CustomFormat last_custom_format[RS::ARRAY_CUSTOM_COUNT];
+
+ void _create_list_from_arrays(Array arr, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat);
+ void _create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat);
//mikktspace callbacks
static int mikktGetNumFaces(const SMikkTSpaceContext *pContext);
@@ -103,17 +133,25 @@ protected:
static void _bind_methods();
public:
+ void set_skin_weight_count(SkinWeightCount p_weights);
+ SkinWeightCount get_skin_weight_count() const;
+
+ void set_custom_format(int p_index, CustomFormat p_format);
+ CustomFormat get_custom_format(int p_index) const;
+
void begin(Mesh::PrimitiveType p_primitive);
+ void set_color(Color p_color);
+ void set_normal(const Vector3 &p_normal);
+ void set_tangent(const Plane &p_tangent);
+ void set_uv(const Vector2 &p_uv);
+ void set_uv2(const Vector2 &p_uv2);
+ void set_custom(int p_index, const Color &p_custom);
+ void set_bones(const Vector<int> &p_bones);
+ void set_weights(const Vector<float> &p_weights);
+ void set_smooth_group(uint32_t p_group);
+
void add_vertex(const Vector3 &p_vertex);
- void add_color(Color p_color);
- void add_normal(const Vector3 &p_normal);
- void add_tangent(const Plane &p_tangent);
- void add_uv(const Vector2 &p_uv);
- void add_uv2(const Vector2 &p_uv2);
- void add_bones(const Vector<int> &p_bones);
- void add_weights(const Vector<float> &p_weights);
- void add_smooth_group(bool p_smooth);
void add_triangle_fan(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs = Vector<Vector2>(), const Vector<Color> &p_colors = Vector<Color>(), const Vector<Vector2> &p_uv2s = Vector<Vector2>(), const Vector<Vector3> &p_normals = Vector<Vector3>(), const Vector<Plane> &p_tangents = Vector<Plane>());
@@ -124,21 +162,28 @@ public:
void generate_normals(bool p_flip = false);
void generate_tangents();
+ void optimize_indices_for_cache();
+ float get_max_axis_length() const;
+ Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3);
+
void set_material(const Ref<Material> &p_material);
void clear();
- List<Vertex> &get_vertex_array() { return vertex_array; }
+ LocalVector<Vertex> &get_vertex_array() { return vertex_array; }
void create_from_triangle_arrays(const Array &p_arrays);
- static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays);
+ static void create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector<Vertex> &ret, uint32_t *r_format = nullptr);
Array commit_to_arrays();
void create_from(const Ref<Mesh> &p_existing, int p_surface);
void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name);
void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform);
- Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT);
+ Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = 0);
SurfaceTool();
};
+VARIANT_ENUM_CAST(SurfaceTool::CustomFormat)
+VARIANT_ENUM_CAST(SurfaceTool::SkinWeightCount)
+
#endif
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index 5a419bb232..cc9b6758b6 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -113,6 +113,8 @@ RID TextLine::get_rid() const {
void TextLine::clear() {
TS->shaped_text_clear(rid);
+ spacing_top = 0;
+ spacing_bottom = 0;
}
void TextLine::set_preserve_invalid(bool p_enabled) {
@@ -166,6 +168,8 @@ void TextLine::set_bidi_override(const Vector<Vector2i> &p_override) {
bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
+ spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
+ spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
dirty = true;
return res;
}
@@ -233,17 +237,21 @@ float TextLine::get_width() const {
Size2 TextLine::get_size() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_size(rid);
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
+ } else {
+ return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y);
+ }
}
float TextLine::get_line_ascent() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_ascent(rid);
+ return TS->shaped_text_get_ascent(rid) + spacing_top;
}
float TextLine::get_line_descent() const {
const_cast<TextLine *>(this)->_shape();
- return TS->shaped_text_get_descent(rid);
+ return TS->shaped_text_get_descent(rid) + spacing_bottom;
}
float TextLine::get_line_width() const {
@@ -291,10 +299,10 @@ void TextLine::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color) co
float clip_l;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(rid);
+ ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top;
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
- ofs.x += TS->shaped_text_get_ascent(rid);
+ ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top;
clip_l = MAX(0, p_pos.y - ofs.y);
}
return TS->shaped_text_draw(rid, p_canvas, ofs, clip_l, clip_l + width, p_color);
@@ -330,10 +338,10 @@ void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_si
float clip_l;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(rid);
+ ofs.y += TS->shaped_text_get_ascent(rid) + spacing_top;
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
- ofs.x += TS->shaped_text_get_ascent(rid);
+ ofs.x += TS->shaped_text_get_ascent(rid) + spacing_top;
clip_l = MAX(0, p_pos.y - ofs.y);
}
return TS->shaped_text_draw_outline(rid, p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color);
@@ -347,6 +355,8 @@ int TextLine::hit_test(float p_coords) const {
TextLine::TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
rid = TS->create_shaped_text(p_direction, p_orientation);
+ spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
+ spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
}
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index ffa06cc5c1..6ed3558bd9 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -40,6 +40,8 @@ class TextLine : public Reference {
GDCLASS(TextLine, Reference);
RID rid;
+ int spacing_top = 0;
+ int spacing_bottom = 0;
bool dirty = true;
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index d4f96ff9e8..fd6dd071eb 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -140,6 +140,8 @@ RID TextParagraph::get_line_rid(int p_line) const {
}
void TextParagraph::clear() {
+ spacing_top = 0;
+ spacing_bottom = 0;
for (int i = 0; i < lines.size(); i++) {
TS->free(lines[i]);
}
@@ -187,6 +189,8 @@ TextServer::Orientation TextParagraph::get_orientation() const {
bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
+ spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
+ spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
dirty_lines = true;
return res;
}
@@ -260,7 +264,11 @@ float TextParagraph::get_width() const {
Size2 TextParagraph::get_non_wraped_size() const {
const_cast<TextParagraph *>(this)->_shape_lines();
- return TS->shaped_text_get_size(rid);
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
+ } else {
+ return Size2(TS->shaped_text_get_size(rid).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(rid).y);
+ }
}
Size2 TextParagraph::get_size() const {
@@ -270,9 +278,9 @@ Size2 TextParagraph::get_size() const {
Size2 lsize = TS->shaped_text_get_size(lines[i]);
if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
size.x = MAX(size.x, lsize.x);
- size.y += lsize.y;
+ size.y += lsize.y + spacing_top + spacing_bottom;
} else {
- size.x += lsize.x;
+ size.x += lsize.x + spacing_top + spacing_bottom;
size.y = MAX(size.y, lsize.y);
}
}
@@ -297,9 +305,9 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
for (int i = 0; i < p_line; i++) {
Size2 lsize = TS->shaped_text_get_size(lines[i]);
if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- xrect.position.y += lsize.y;
+ xrect.position.y += lsize.y + spacing_top + spacing_bottom;
} else {
- xrect.position.x += lsize.x;
+ xrect.position.x += lsize.x + spacing_top + spacing_bottom;
}
}
return xrect;
@@ -308,7 +316,11 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
Size2 TextParagraph::get_line_size(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Size2());
- return TS->shaped_text_get_size(lines[p_line]);
+ if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
+ return Size2(TS->shaped_text_get_size(lines[p_line]).x, TS->shaped_text_get_size(lines[p_line]).y + spacing_top + spacing_bottom);
+ } else {
+ return Size2(TS->shaped_text_get_size(lines[p_line]).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(lines[p_line]).y);
+ }
}
Vector2i TextParagraph::get_line_range(int p_line) const {
@@ -320,13 +332,13 @@ Vector2i TextParagraph::get_line_range(int p_line) const {
float TextParagraph::get_line_ascent(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f);
- return TS->shaped_text_get_ascent(lines[p_line]);
+ return TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
}
float TextParagraph::get_line_descent(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f);
- return TS->shaped_text_get_descent(lines[p_line]);
+ return TS->shaped_text_get_descent(lines[p_line]) + spacing_bottom;
}
float TextParagraph::get_line_width(int p_line) const {
@@ -353,10 +365,10 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
for (int i = 0; i < lines.size(); i++) {
if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_ascent(lines[i]);
+ ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top;
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_ascent(lines[i]);
+ ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top;
}
float length = TS->shaped_text_get_width(lines[i]);
if (width > 0) {
@@ -389,10 +401,10 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(lines[i], p_canvas, ofs, clip_l, clip_l + width, p_color);
if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines[i]);
+ ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom;
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines[i]);
+ ofs.x += TS->shaped_text_get_descent(lines[i]) + spacing_bottom;
}
}
}
@@ -403,10 +415,10 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
for (int i = 0; i < lines.size(); i++) {
if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_ascent(lines[i]);
+ ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top;
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_ascent(lines[i]);
+ ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top;
}
float length = TS->shaped_text_get_width(lines[i]);
if (width > 0) {
@@ -439,10 +451,10 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(lines[i], p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color);
if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines[i]);
+ ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom;
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines[i]);
+ ofs.x += TS->shaped_text_get_descent(lines[i]) + spacing_bottom;
}
}
}
@@ -462,10 +474,12 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines[i]).y)) {
return TS->shaped_text_hit_test_position(lines[i], p_coords.x);
}
+ ofs.y += TS->shaped_text_get_size(lines[i]).y + spacing_bottom + spacing_top;
} else {
if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(lines[i]).x)) {
return TS->shaped_text_hit_test_position(lines[i], p_coords.y);
}
+ ofs.y += TS->shaped_text_get_size(lines[i]).x + spacing_bottom + spacing_top;
}
}
return TS->shaped_text_get_range(rid).y;
@@ -477,9 +491,9 @@ void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, co
Vector2 ofs = p_pos;
if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(lines[p_line]);
+ ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
} else {
- ofs.x += TS->shaped_text_get_ascent(lines[p_line]);
+ ofs.x += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
}
return TS->shaped_text_draw(lines[p_line], p_canvas, ofs, -1, -1, p_color);
}
@@ -490,9 +504,9 @@ void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_
Vector2 ofs = p_pos;
if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(lines[p_line]);
+ ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
} else {
- ofs.x += TS->shaped_text_get_ascent(lines[p_line]);
+ ofs.x += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
}
return TS->shaped_text_draw_outline(lines[p_line], p_canvas, ofs, -1, -1, p_outline_size, p_color);
}
@@ -500,8 +514,9 @@ void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_
TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
rid = TS->create_shaped_text(p_direction, p_orientation);
TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
+ spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
+ spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
width = p_width;
- dirty_lines = true;
}
TextParagraph::TextParagraph() {
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 587bb6bfc1..f7f49e9058 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -41,6 +41,8 @@ class TextParagraph : public Reference {
RID rid;
Vector<RID> lines;
+ int spacing_top = 0;
+ int spacing_bottom = 0;
bool dirty_lines = true;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index d130470275..c8bfcdfab4 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -51,6 +51,21 @@ Vector<String> Theme::_get_icon_list(const String &p_node_type) const {
return ilret;
}
+Vector<String> Theme::_get_icon_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_icon_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
Vector<String> Theme::_get_stylebox_list(const String &p_node_type) const {
Vector<String> ilret;
List<StringName> il;
@@ -66,11 +81,11 @@ Vector<String> Theme::_get_stylebox_list(const String &p_node_type) const {
return ilret;
}
-Vector<String> Theme::_get_stylebox_types() const {
+Vector<String> Theme::_get_stylebox_type_list() const {
Vector<String> ilret;
List<StringName> il;
- get_stylebox_types(&il);
+ get_stylebox_type_list(&il);
ilret.resize(il.size());
int i = 0;
@@ -96,6 +111,21 @@ Vector<String> Theme::_get_font_list(const String &p_node_type) const {
return ilret;
}
+Vector<String> Theme::_get_font_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_font_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
Vector<String> Theme::_get_font_size_list(const String &p_node_type) const {
Vector<String> ilret;
List<StringName> il;
@@ -126,6 +156,21 @@ Vector<String> Theme::_get_color_list(const String &p_node_type) const {
return ilret;
}
+Vector<String> Theme::_get_color_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_color_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
Vector<String> Theme::_get_constant_list(const String &p_node_type) const {
Vector<String> ilret;
List<StringName> il;
@@ -141,7 +186,22 @@ Vector<String> Theme::_get_constant_list(const String &p_node_type) const {
return ilret;
}
-Vector<String> Theme::_get_type_list(const String &p_node_type) const {
+Vector<String> Theme::_get_constant_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_constant_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_type_list() const {
Vector<String> ilret;
List<StringName> il;
@@ -421,48 +481,11 @@ void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) cons
}
}
-void Theme::set_shader(const StringName &p_name, const StringName &p_node_type, const Ref<Shader> &p_shader) {
- bool new_value = !shader_map.has(p_node_type) || !shader_map[p_node_type].has(p_name);
-
- shader_map[p_node_type][p_name] = p_shader;
-
- if (new_value) {
- _change_notify();
- emit_changed();
- }
-}
-
-Ref<Shader> Theme::get_shader(const StringName &p_name, const StringName &p_node_type) const {
- if (shader_map.has(p_node_type) && shader_map[p_node_type].has(p_name) && shader_map[p_node_type][p_name].is_valid()) {
- return shader_map[p_node_type][p_name];
- } else {
- return nullptr;
- }
-}
-
-bool Theme::has_shader(const StringName &p_name, const StringName &p_node_type) const {
- return (shader_map.has(p_node_type) && shader_map[p_node_type].has(p_name) && shader_map[p_node_type][p_name].is_valid());
-}
-
-void Theme::clear_shader(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!shader_map.has(p_node_type));
- ERR_FAIL_COND(!shader_map[p_node_type].has(p_name));
-
- shader_map[p_node_type].erase(p_name);
- _change_notify();
- emit_changed();
-}
-
-void Theme::get_shader_list(const StringName &p_node_type, List<StringName> *p_list) const {
+void Theme::get_icon_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- if (!shader_map.has(p_node_type)) {
- return;
- }
-
const StringName *key = nullptr;
-
- while ((key = shader_map[p_node_type].next(key))) {
+ while ((key = icon_map.next(key))) {
p_list->push_back(*key);
}
}
@@ -528,7 +551,7 @@ void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list)
}
}
-void Theme::get_stylebox_types(List<StringName> *p_list) const {
+void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
const StringName *key = nullptr;
@@ -599,6 +622,15 @@ void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) cons
}
}
+void Theme::get_font_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = font_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
void Theme::set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size) {
bool new_value = !font_size_map.has(p_node_type) || !font_size_map[p_node_type].has(p_name);
@@ -693,6 +725,15 @@ void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) con
}
}
+void Theme::get_color_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = color_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
void Theme::set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant) {
bool new_value = !constant_map.has(p_node_type) || !constant_map[p_node_type].has(p_name);
constant_map[p_node_type][p_name] = p_constant;
@@ -738,6 +779,15 @@ void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list)
}
}
+void Theme::get_constant_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = constant_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
void Theme::clear() {
//these need disconnecting
{
@@ -782,7 +832,6 @@ void Theme::clear() {
icon_map.clear();
style_map.clear();
font_map.clear();
- shader_map.clear();
color_map.clear();
constant_map.clear();
@@ -837,7 +886,6 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
color_map = p_other->color_map;
constant_map = p_other->constant_map;
- shader_map = p_other->shader_map;
_change_notify();
emit_changed();
@@ -888,19 +936,21 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_icon", "name", "node_type"), &Theme::has_icon);
ClassDB::bind_method(D_METHOD("clear_icon", "name", "node_type"), &Theme::clear_icon);
ClassDB::bind_method(D_METHOD("get_icon_list", "node_type"), &Theme::_get_icon_list);
+ ClassDB::bind_method(D_METHOD("get_icon_type_list"), &Theme::_get_icon_type_list);
ClassDB::bind_method(D_METHOD("set_stylebox", "name", "node_type", "texture"), &Theme::set_stylebox);
ClassDB::bind_method(D_METHOD("get_stylebox", "name", "node_type"), &Theme::get_stylebox);
ClassDB::bind_method(D_METHOD("has_stylebox", "name", "node_type"), &Theme::has_stylebox);
ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "node_type"), &Theme::clear_stylebox);
ClassDB::bind_method(D_METHOD("get_stylebox_list", "node_type"), &Theme::_get_stylebox_list);
- ClassDB::bind_method(D_METHOD("get_stylebox_types"), &Theme::_get_stylebox_types);
+ ClassDB::bind_method(D_METHOD("get_stylebox_type_list"), &Theme::_get_stylebox_type_list);
ClassDB::bind_method(D_METHOD("set_font", "name", "node_type", "font"), &Theme::set_font);
ClassDB::bind_method(D_METHOD("get_font", "name", "node_type"), &Theme::get_font);
ClassDB::bind_method(D_METHOD("has_font", "name", "node_type"), &Theme::has_font);
ClassDB::bind_method(D_METHOD("clear_font", "name", "node_type"), &Theme::clear_font);
ClassDB::bind_method(D_METHOD("get_font_list", "node_type"), &Theme::_get_font_list);
+ ClassDB::bind_method(D_METHOD("get_font_type_list"), &Theme::_get_font_type_list);
ClassDB::bind_method(D_METHOD("set_font_size", "name", "node_type", "font_size"), &Theme::set_font_size);
ClassDB::bind_method(D_METHOD("get_font_size", "name", "node_type"), &Theme::get_font_size);
@@ -913,12 +963,14 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_color", "name", "node_type"), &Theme::has_color);
ClassDB::bind_method(D_METHOD("clear_color", "name", "node_type"), &Theme::clear_color);
ClassDB::bind_method(D_METHOD("get_color_list", "node_type"), &Theme::_get_color_list);
+ ClassDB::bind_method(D_METHOD("get_color_type_list"), &Theme::_get_color_type_list);
ClassDB::bind_method(D_METHOD("set_constant", "name", "node_type", "constant"), &Theme::set_constant);
ClassDB::bind_method(D_METHOD("get_constant", "name", "node_type"), &Theme::get_constant);
ClassDB::bind_method(D_METHOD("has_constant", "name", "node_type"), &Theme::has_constant);
ClassDB::bind_method(D_METHOD("clear_constant", "name", "node_type"), &Theme::clear_constant);
ClassDB::bind_method(D_METHOD("get_constant_list", "node_type"), &Theme::_get_constant_list);
+ ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list);
ClassDB::bind_method(D_METHOD("clear"), &Theme::clear);
@@ -928,7 +980,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size);
ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size);
- ClassDB::bind_method(D_METHOD("get_type_list", "node_type"), &Theme::_get_type_list);
+ ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list);
ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme);
ClassDB::bind_method(D_METHOD("copy_theme", "other"), &Theme::copy_theme);
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 4175e19112..ad05e0e2f5 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -34,7 +34,6 @@
#include "core/io/resource.h"
#include "core/io/resource_loader.h"
#include "scene/resources/font.h"
-#include "scene/resources/shader.h"
#include "scene/resources/style_box.h"
#include "scene/resources/texture.h"
@@ -48,18 +47,21 @@ class Theme : public Resource {
HashMap<StringName, HashMap<StringName, Ref<StyleBox>>> style_map;
HashMap<StringName, HashMap<StringName, Ref<Font>>> font_map;
HashMap<StringName, HashMap<StringName, int>> font_size_map;
- HashMap<StringName, HashMap<StringName, Ref<Shader>>> shader_map;
HashMap<StringName, HashMap<StringName, Color>> color_map;
HashMap<StringName, HashMap<StringName, int>> constant_map;
Vector<String> _get_icon_list(const String &p_node_type) const;
+ Vector<String> _get_icon_type_list() const;
Vector<String> _get_stylebox_list(const String &p_node_type) const;
- Vector<String> _get_stylebox_types() const;
+ Vector<String> _get_stylebox_type_list() const;
Vector<String> _get_font_list(const String &p_node_type) const;
+ Vector<String> _get_font_type_list() const;
Vector<String> _get_font_size_list(const String &p_node_type) const;
Vector<String> _get_color_list(const String &p_node_type) const;
+ Vector<String> _get_color_type_list() const;
Vector<String> _get_constant_list(const String &p_node_type) const;
- Vector<String> _get_type_list(const String &p_node_type) const;
+ Vector<String> _get_constant_type_list() const;
+ Vector<String> _get_type_list() const;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -101,25 +103,21 @@ public:
bool has_icon(const StringName &p_name, const StringName &p_node_type) const;
void clear_icon(const StringName &p_name, const StringName &p_node_type);
void get_icon_list(StringName p_node_type, List<StringName> *p_list) const;
-
- void set_shader(const StringName &p_name, const StringName &p_node_type, const Ref<Shader> &p_shader);
- Ref<Shader> get_shader(const StringName &p_name, const StringName &p_node_type) const;
- bool has_shader(const StringName &p_name, const StringName &p_node_type) const;
- void clear_shader(const StringName &p_name, const StringName &p_node_type);
- void get_shader_list(const StringName &p_node_type, List<StringName> *p_list) const;
+ void get_icon_type_list(List<StringName> *p_list) const;
void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style);
Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const;
bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const;
void clear_stylebox(const StringName &p_name, const StringName &p_node_type);
void get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const;
- void get_stylebox_types(List<StringName> *p_list) const;
+ void get_stylebox_type_list(List<StringName> *p_list) const;
void set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font);
Ref<Font> get_font(const StringName &p_name, const StringName &p_node_type) const;
bool has_font(const StringName &p_name, const StringName &p_node_type) const;
void clear_font(const StringName &p_name, const StringName &p_node_type);
void get_font_list(StringName p_node_type, List<StringName> *p_list) const;
+ void get_font_type_list(List<StringName> *p_list) const;
void set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size);
int get_font_size(const StringName &p_name, const StringName &p_node_type) const;
@@ -132,12 +130,14 @@ public:
bool has_color(const StringName &p_name, const StringName &p_node_type) const;
void clear_color(const StringName &p_name, const StringName &p_node_type);
void get_color_list(StringName p_node_type, List<StringName> *p_list) const;
+ void get_color_type_list(List<StringName> *p_list) const;
void set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant);
int get_constant(const StringName &p_name, const StringName &p_node_type) const;
bool has_constant(const StringName &p_name, const StringName &p_node_type) const;
void clear_constant(const StringName &p_name, const StringName &p_node_type);
void get_constant_list(StringName p_node_type, List<StringName> *p_list) const;
+ void get_constant_type_list(List<StringName> *p_list) const;
void get_type_list(List<StringName> *p_list) const;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index dd9f64693e..34129e35da 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -811,8 +811,12 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
#define IS_SYMBOL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z') || ((m_d) >= '0' && (m_d) <= '9') || (m_d) == '_')
-String VisualShader::validate_port_name(const String &p_name, const List<String> &p_input_ports, const List<String> &p_output_ports) const {
- String name = p_name;
+String VisualShader::validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const {
+ String name = p_port_name;
+
+ if (name == String()) {
+ return String();
+ }
while (name.length() && !IS_INITIAL_CHAR(name[0])) {
name = name.substr(1, name.length() - 1);
@@ -830,29 +834,28 @@ String VisualShader::validate_port_name(const String &p_name, const List<String>
}
name = valid_name;
+ } else {
+ return String();
}
- String valid_name = name;
- bool is_equal = false;
+ List<String> input_names;
+ List<String> output_names;
- for (int i = 0; i < p_input_ports.size(); i++) {
- if (name == p_input_ports[i]) {
- is_equal = true;
- break;
+ for (int i = 0; i < p_node->get_input_port_count(); i++) {
+ if (!p_output && i == p_port_id) {
+ continue;
}
- }
-
- if (!is_equal) {
- for (int i = 0; i < p_output_ports.size(); i++) {
- if (name == p_output_ports[i]) {
- is_equal = true;
- break;
- }
+ if (name == p_node->get_input_port_name(i)) {
+ return String();
}
}
-
- if (is_equal) {
- name = "";
+ for (int i = 0; i < p_node->get_output_port_count(); i++) {
+ if (p_output && i == p_port_id) {
+ continue;
+ }
+ if (name == p_node->get_output_port_name(i)) {
+ return String();
+ }
}
return name;
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 41c4642ee3..a38c2886e2 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -175,7 +175,7 @@ public:
String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const;
- String validate_port_name(const String &p_name, const List<String> &p_input_ports, const List<String> &p_output_ports) const;
+ String validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const;
String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const;
VisualShader();
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index c1dd59533d..a72066e7a8 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -41,7 +41,7 @@ SceneStringNames::SceneStringNames() {
doubledot = StaticCString::create("..");
draw = StaticCString::create("draw");
_draw = StaticCString::create("_draw");
- hide = StaticCString::create("hide");
+ hidden = StaticCString::create("hidden");
visibility_changed = StaticCString::create("visibility_changed");
input_event = StaticCString::create("input_event");
shader = StaticCString::create("shader");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 80ead560be..b4d2429d7f 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -58,7 +58,7 @@ public:
StringName dot;
StringName doubledot;
StringName draw;
- StringName hide;
+ StringName hidden;
StringName visibility_changed;
StringName input_event;
StringName _input_event;