summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/3d/cpu_particles_3d.cpp4
-rw-r--r--scene/3d/cpu_particles_3d.h1
-rw-r--r--scene/3d/decal.cpp4
-rw-r--r--scene/3d/decal.h1
-rw-r--r--scene/3d/fog_volume.h1
-rw-r--r--scene/3d/gpu_particles_3d.cpp4
-rw-r--r--scene/3d/gpu_particles_3d.h1
-rw-r--r--scene/3d/gpu_particles_collision_3d.h4
-rw-r--r--scene/3d/light_3d.cpp84
-rw-r--r--scene/3d/light_3d.h21
-rw-r--r--scene/3d/lightmap_gi.cpp6
-rw-r--r--scene/3d/lightmap_gi.h1
-rw-r--r--scene/3d/mesh_instance_3d.cpp12
-rw-r--r--scene/3d/mesh_instance_3d.h1
-rw-r--r--scene/3d/multimesh_instance_3d.cpp4
-rw-r--r--scene/3d/multimesh_instance_3d.h2
-rw-r--r--scene/3d/occluder_instance_3d.cpp4
-rw-r--r--scene/3d/occluder_instance_3d.h1
-rw-r--r--scene/3d/physics_body_3d.cpp52
-rw-r--r--scene/3d/physics_body_3d.h14
-rw-r--r--scene/3d/reflection_probe.cpp4
-rw-r--r--scene/3d/reflection_probe.h1
-rw-r--r--scene/3d/sprite_3d.cpp4
-rw-r--r--scene/3d/sprite_3d.h2
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.cpp4
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.h2
-rw-r--r--scene/3d/visual_instance_3d.cpp9
-rw-r--r--scene/3d/visual_instance_3d.h4
-rw-r--r--scene/3d/voxel_gi.cpp4
-rw-r--r--scene/3d/voxel_gi.h1
-rw-r--r--scene/animation/animation_player.cpp63
-rw-r--r--scene/animation/animation_tree.cpp56
-rw-r--r--scene/animation/root_motion_view.cpp4
-rw-r--r--scene/animation/root_motion_view.h1
-rw-r--r--scene/debugger/scene_debugger.cpp33
-rw-r--r--scene/debugger/scene_debugger.h4
-rw-r--r--scene/gui/base_button.cpp4
-rw-r--r--scene/gui/base_button.h2
-rw-r--r--scene/gui/button.cpp2
-rw-r--r--scene/gui/check_button.cpp5
-rw-r--r--scene/gui/check_button.h2
-rw-r--r--scene/gui/color_picker.cpp5
-rw-r--r--scene/gui/color_picker.h2
-rw-r--r--scene/gui/control.cpp57
-rw-r--r--scene/gui/file_dialog.cpp3
-rw-r--r--scene/gui/line_edit.cpp12
-rw-r--r--scene/gui/line_edit.h2
-rw-r--r--scene/gui/link_button.cpp4
-rw-r--r--scene/gui/link_button.h2
-rw-r--r--scene/gui/menu_button.cpp5
-rw-r--r--scene/gui/menu_button.h2
-rw-r--r--scene/gui/option_button.cpp3
-rw-r--r--scene/gui/option_button.h2
-rw-r--r--scene/gui/popup.cpp4
-rw-r--r--scene/gui/popup.h2
-rw-r--r--scene/gui/popup_menu.cpp2
-rw-r--r--scene/gui/range.cpp5
-rw-r--r--scene/gui/range.h4
-rw-r--r--scene/gui/rich_text_label.cpp8
-rw-r--r--scene/gui/rich_text_label.h2
-rw-r--r--scene/gui/spin_box.cpp3
-rw-r--r--scene/gui/spin_box.h2
-rw-r--r--scene/gui/tab_bar.cpp176
-rw-r--r--scene/gui/tab_bar.h11
-rw-r--r--scene/gui/tab_container.cpp1090
-rw-r--r--scene/gui/tab_container.h60
-rw-r--r--scene/gui/text_edit.cpp10
-rw-r--r--scene/gui/text_edit.h2
-rw-r--r--scene/gui/tree.cpp2
-rw-r--r--scene/main/node.cpp68
-rw-r--r--scene/main/node.h28
-rw-r--r--scene/main/scene_tree.cpp51
-rw-r--r--scene/main/scene_tree.h23
-rw-r--r--scene/multiplayer/scene_rpc_interface.cpp6
-rw-r--r--scene/register_scene_types.cpp123
-rw-r--r--scene/resources/animation.cpp4
-rw-r--r--scene/resources/material.cpp36
-rw-r--r--scene/resources/material.h13
-rw-r--r--scene/resources/mesh.cpp131
-rw-r--r--scene/resources/mesh.h63
-rw-r--r--scene/resources/packed_scene.cpp2
-rw-r--r--scene/resources/packed_scene.h2
-rw-r--r--scene/resources/primitive_meshes.cpp12
-rw-r--r--scene/resources/primitive_meshes.h3
-rw-r--r--scene/resources/style_box.cpp33
-rw-r--r--scene/resources/style_box.h10
-rw-r--r--scene/resources/texture.cpp384
-rw-r--r--scene/resources/texture.h120
-rw-r--r--scene/resources/visual_shader.cpp619
-rw-r--r--scene/resources/visual_shader.h170
-rw-r--r--scene/resources/visual_shader_nodes.cpp6
91 files changed, 2333 insertions, 1489 deletions
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index a02b5f48a1..ab28a83806 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -39,10 +39,6 @@ AABB CPUParticles3D::get_aabb() const {
return AABB();
}
-Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_particle_flags) const {
- return Vector<Face3>();
-}
-
void CPUParticles3D::set_emitting(bool p_emitting) {
if (emitting == p_emitting) {
return;
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index bd736bdf24..5eeb5e75d3 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -201,7 +201,6 @@ protected:
public:
AABB get_aabb() const override;
- Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index dfac9055f5..8d0edfd1f3 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -152,10 +152,6 @@ AABB Decal::get_aabb() const {
return aabb;
}
-Vector<Face3> Decal::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
void Decal::_validate_property(PropertyInfo &property) const {
if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_length")) {
property.usage = PROPERTY_USAGE_NO_EDITOR;
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index 740dd2c407..d5990272c6 100644
--- a/scene/3d/decal.h
+++ b/scene/3d/decal.h
@@ -104,7 +104,6 @@ public:
uint32_t get_cull_mask() const;
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
Decal();
~Decal();
diff --git a/scene/3d/fog_volume.h b/scene/3d/fog_volume.h
index 68d5c58169..556a92ad3f 100644
--- a/scene/3d/fog_volume.h
+++ b/scene/3d/fog_volume.h
@@ -62,7 +62,6 @@ public:
Ref<Material> get_material() const;
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); }
TypedArray<String> get_configuration_warnings() const override;
FogVolume();
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 4e35f37291..9fe2210de6 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -36,10 +36,6 @@ AABB GPUParticles3D::get_aabb() const {
return AABB();
}
-Vector<Face3> GPUParticles3D::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
void GPUParticles3D::set_emitting(bool p_emitting) {
RS::get_singleton()->particles_set_emitting(particles, p_emitting);
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 54ae84628a..f3eb52d124 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -98,7 +98,6 @@ protected:
public:
AABB get_aabb() const override;
- Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index b6de1d83fc..fdd2fa4b18 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -50,8 +50,6 @@ public:
void set_cull_mask(uint32_t p_cull_mask);
uint32_t get_cull_mask() const;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); }
-
~GPUParticlesCollision3D();
};
@@ -274,8 +272,6 @@ public:
void set_directionality(real_t p_directionality);
real_t get_directionality() const;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); }
-
~GPUParticlesAttractor3D();
};
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index b2e605a262..e7e164d7da 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -74,6 +74,43 @@ bool Light3D::is_negative() const {
return negative;
}
+void Light3D::set_enable_distance_fade(bool p_enable) {
+ distance_fade_enabled = p_enable;
+ RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length);
+ notify_property_list_changed();
+}
+
+bool Light3D::is_distance_fade_enabled() const {
+ return distance_fade_enabled;
+}
+
+void Light3D::set_distance_fade_begin(real_t p_distance) {
+ distance_fade_begin = p_distance;
+ RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length);
+}
+
+real_t Light3D::get_distance_fade_begin() const {
+ return distance_fade_begin;
+}
+
+void Light3D::set_distance_fade_shadow(real_t p_distance) {
+ distance_fade_shadow = p_distance;
+ RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length);
+}
+
+real_t Light3D::get_distance_fade_shadow() const {
+ return distance_fade_shadow;
+}
+
+void Light3D::set_distance_fade_length(real_t p_length) {
+ distance_fade_length = p_length;
+ RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length);
+}
+
+real_t Light3D::get_distance_fade_length() const {
+ return distance_fade_length;
+}
+
void Light3D::set_cull_mask(uint32_t p_cull_mask) {
cull_mask = p_cull_mask;
RS::get_singleton()->light_set_cull_mask(light, p_cull_mask);
@@ -94,15 +131,6 @@ Color Light3D::get_color() const {
return color;
}
-void Light3D::set_shadow_color(const Color &p_shadow_color) {
- shadow_color = p_shadow_color;
- RS::get_singleton()->light_set_shadow_color(light, p_shadow_color);
-}
-
-Color Light3D::get_shadow_color() const {
- return shadow_color;
-}
-
void Light3D::set_shadow_reverse_cull_face(bool p_enable) {
reverse_cull = p_enable;
RS::get_singleton()->light_set_reverse_cull_face_mode(light, reverse_cull);
@@ -128,10 +156,6 @@ AABB Light3D::get_aabb() const {
return AABB();
}
-Vector<Face3> Light3D::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
void Light3D::set_bake_mode(BakeMode p_mode) {
bake_mode = p_mode;
RS::get_singleton()->light_set_bake_mode(light, RS::LightBakeMode(p_mode));
@@ -195,7 +219,7 @@ bool Light3D::is_editor_only() const {
}
void Light3D::_validate_property(PropertyInfo &property) const {
- if (!shadow && (property.name == "shadow_color" || property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur")) {
+ if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) {
property.usage = PROPERTY_USAGE_NO_EDITOR;
}
@@ -203,6 +227,11 @@ void Light3D::_validate_property(PropertyInfo &property) const {
// Angular distance is only used in DirectionalLight3D.
property.usage = PROPERTY_USAGE_NONE;
}
+
+ if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length")) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
VisualInstance3D::_validate_property(property);
}
@@ -222,15 +251,24 @@ void Light3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cull_mask", "cull_mask"), &Light3D::set_cull_mask);
ClassDB::bind_method(D_METHOD("get_cull_mask"), &Light3D::get_cull_mask);
+ ClassDB::bind_method(D_METHOD("set_enable_distance_fade", "enable"), &Light3D::set_enable_distance_fade);
+ ClassDB::bind_method(D_METHOD("is_distance_fade_enabled"), &Light3D::is_distance_fade_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_distance_fade_begin", "distance"), &Light3D::set_distance_fade_begin);
+ ClassDB::bind_method(D_METHOD("get_distance_fade_begin"), &Light3D::get_distance_fade_begin);
+
+ ClassDB::bind_method(D_METHOD("set_distance_fade_shadow", "distance"), &Light3D::set_distance_fade_shadow);
+ ClassDB::bind_method(D_METHOD("get_distance_fade_shadow"), &Light3D::get_distance_fade_shadow);
+
+ ClassDB::bind_method(D_METHOD("set_distance_fade_length", "distance"), &Light3D::set_distance_fade_length);
+ ClassDB::bind_method(D_METHOD("get_distance_fade_length"), &Light3D::get_distance_fade_length);
+
ClassDB::bind_method(D_METHOD("set_color", "color"), &Light3D::set_color);
ClassDB::bind_method(D_METHOD("get_color"), &Light3D::get_color);
ClassDB::bind_method(D_METHOD("set_shadow_reverse_cull_face", "enable"), &Light3D::set_shadow_reverse_cull_face);
ClassDB::bind_method(D_METHOD("get_shadow_reverse_cull_face"), &Light3D::get_shadow_reverse_cull_face);
- ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light3D::set_shadow_color);
- ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light3D::get_shadow_color);
-
ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light3D::set_bake_mode);
ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light3D::get_bake_mode);
@@ -250,13 +288,17 @@ void Light3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_shadow_color", "get_shadow_color");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR);
+ ADD_GROUP("Distance Fade", "distance_fade_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_begin", "get_distance_fade_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_shadow", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_shadow", "get_distance_fade_shadow");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_length", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_length", "get_distance_fade_length");
ADD_GROUP("Editor", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
ADD_GROUP("", "");
@@ -391,6 +433,12 @@ void DirectionalLight3D::_validate_property(PropertyInfo &property) const {
property.usage = PROPERTY_USAGE_NONE;
}
+ if (property.name == "distance_fade_enabled" || property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length") {
+ // Not relevant for DirectionalLight3D, as the light LOD system only pertains to point lights.
+ // For DirectionalLight3D, `directional_shadow_max_distance` can be used instead.
+ property.usage = PROPERTY_USAGE_NONE;
+ }
+
Light3D::_validate_property(property);
}
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index d5d2aee43d..ed9e0bdfff 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -70,11 +70,14 @@ public:
private:
Color color;
real_t param[PARAM_MAX] = {};
- Color shadow_color;
bool shadow = false;
bool negative = false;
bool reverse_cull = false;
uint32_t cull_mask = 0;
+ bool distance_fade_enabled = false;
+ real_t distance_fade_begin = 40.0;
+ real_t distance_fade_shadow = 50.0;
+ real_t distance_fade_length = 10.0;
RS::LightType type = RenderingServer::LIGHT_DIRECTIONAL;
bool editor_only = false;
void _update_visibility();
@@ -107,15 +110,24 @@ public:
void set_negative(bool p_enable);
bool is_negative() const;
+ void set_enable_distance_fade(bool p_enable);
+ bool is_distance_fade_enabled() const;
+
+ void set_distance_fade_begin(real_t p_distance);
+ real_t get_distance_fade_begin() const;
+
+ void set_distance_fade_shadow(real_t p_distance);
+ real_t get_distance_fade_shadow() const;
+
+ void set_distance_fade_length(real_t p_length);
+ real_t get_distance_fade_length() const;
+
void set_cull_mask(uint32_t p_cull_mask);
uint32_t get_cull_mask() const;
void set_color(const Color &p_color);
Color get_color() const;
- void set_shadow_color(const Color &p_shadow_color);
- Color get_shadow_color() const;
-
void set_shadow_reverse_cull_face(bool p_enable);
bool get_shadow_reverse_cull_face() const;
@@ -126,7 +138,6 @@ public:
Ref<Texture2D> get_projector() const;
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
Light3D();
~Light3D();
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 68d2b91fad..c74654b4bd 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -982,7 +982,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
}
config->set_value("remap", "importer", "2d_array_texture");
- config->set_value("remap", "type", "StreamTexture2DArray");
+ config->set_value("remap", "type", "CompressedTexture2DArray");
if (!config->has_section_key("params", "compress/mode")) {
config->set_value("params", "compress/mode", 2); //user may want another compression, so leave it be
}
@@ -1263,10 +1263,6 @@ AABB LightmapGI::get_aabb() const {
return AABB();
}
-Vector<Face3> LightmapGI::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
void LightmapGI::set_use_denoiser(bool p_enable) {
use_denoiser = p_enable;
}
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 66acf4f487..d29d7a7c28 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -267,7 +267,6 @@ public:
GenerateProbes get_generate_probes() const;
AABB get_aabb() const override;
- Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
BakeError bake(Node *p_from_node, String p_image_data_path = "", Lightmapper::BakeStepFunc p_bake_step = nullptr, void *p_bake_userdata = nullptr);
LightmapGI();
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index fddfa17dbb..31c33a6b61 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -219,18 +219,6 @@ AABB MeshInstance3D::get_aabb() const {
return AABB();
}
-Vector<Face3> MeshInstance3D::get_faces(uint32_t p_usage_flags) const {
- if (!(p_usage_flags & (FACES_SOLID | FACES_ENCLOSING))) {
- return Vector<Face3>();
- }
-
- if (mesh.is_null()) {
- return Vector<Face3>();
- }
-
- return mesh->get_faces();
-}
-
Node *MeshInstance3D::create_trimesh_collision_node() {
if (mesh.is_null()) {
return nullptr;
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index 03ee3cd608..0bf5c32410 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -93,7 +93,6 @@ public:
void create_debug_tangents();
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
MeshInstance3D();
~MeshInstance3D();
diff --git a/scene/3d/multimesh_instance_3d.cpp b/scene/3d/multimesh_instance_3d.cpp
index 34b1e86435..d197388fad 100644
--- a/scene/3d/multimesh_instance_3d.cpp
+++ b/scene/3d/multimesh_instance_3d.cpp
@@ -49,10 +49,6 @@ Ref<MultiMesh> MultiMeshInstance3D::get_multimesh() const {
return multimesh;
}
-Vector<Face3> MultiMeshInstance3D::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
AABB MultiMeshInstance3D::get_aabb() const {
if (multimesh.is_null()) {
return AABB();
diff --git a/scene/3d/multimesh_instance_3d.h b/scene/3d/multimesh_instance_3d.h
index d03b24eb4e..111f1e9c09 100644
--- a/scene/3d/multimesh_instance_3d.h
+++ b/scene/3d/multimesh_instance_3d.h
@@ -44,8 +44,6 @@ protected:
// bind helpers
public:
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
-
void set_multimesh(const Ref<MultiMesh> &p_multimesh);
Ref<MultiMesh> get_multimesh() const;
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 855922c341..b82f05544b 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -433,10 +433,6 @@ AABB OccluderInstance3D::get_aabb() const {
return AABB();
}
-Vector<Face3> OccluderInstance3D::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) {
if (occluder == p_occluder) {
return;
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
index 669ddba775..ed6610074e 100644
--- a/scene/3d/occluder_instance_3d.h
+++ b/scene/3d/occluder_instance_3d.h
@@ -194,7 +194,6 @@ public:
Ref<Occluder3D> get_occluder() const;
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
void set_bake_mask(uint32_t p_mask);
uint32_t get_bake_mask() const;
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 25411e54c0..47baa9e023 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -1425,7 +1425,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
const PhysicsServer3D::MotionCollision &collision = result.collisions[0];
Vector3 slide_motion = result.remainder.slide(collision.normal);
- if (collision_state.floor && !collision_state.wall) {
+ if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_equal_approx(Vector3())) {
// Slide using the intersection between the motion plane and the floor plane,
// in order to keep the direction intact.
real_t motion_length = slide_motion.length();
@@ -2159,6 +2159,37 @@ void PhysicalBone3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_po
PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position);
}
+void PhysicalBone3D::set_linear_velocity(const Vector3 &p_velocity) {
+ linear_velocity = p_velocity;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
+}
+
+Vector3 PhysicalBone3D::get_linear_velocity() const {
+ return linear_velocity;
+}
+
+void PhysicalBone3D::set_angular_velocity(const Vector3 &p_velocity) {
+ angular_velocity = p_velocity;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
+}
+
+Vector3 PhysicalBone3D::get_angular_velocity() const {
+ return angular_velocity;
+}
+
+void PhysicalBone3D::set_use_custom_integrator(bool p_enable) {
+ if (custom_integrator == p_enable) {
+ return;
+ }
+
+ custom_integrator = p_enable;
+ PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
+}
+
+bool PhysicalBone3D::is_using_custom_integrator() {
+ return custom_integrator;
+}
+
void PhysicalBone3D::reset_physics_simulation_state() {
if (simulate_physics) {
_start_physics_simulation();
@@ -2867,6 +2898,11 @@ void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
return;
}
+ linear_velocity = p_state->get_linear_velocity();
+ angular_velocity = p_state->get_angular_velocity();
+
+ GDVIRTUAL_CALL(_integrate_forces, p_state);
+
/// Update bone transform.
Transform3D global_transform(p_state->get_transform());
@@ -2929,9 +2965,20 @@ void PhysicalBone3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &PhysicalBone3D::set_angular_damp);
ClassDB::bind_method(D_METHOD("get_angular_damp"), &PhysicalBone3D::get_angular_damp);
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &PhysicalBone3D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &PhysicalBone3D::get_linear_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &PhysicalBone3D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &PhysicalBone3D::get_angular_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &PhysicalBone3D::set_use_custom_integrator);
+ ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &PhysicalBone3D::is_using_custom_integrator);
+
ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &PhysicalBone3D::set_can_sleep);
ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &PhysicalBone3D::is_able_to_sleep);
+ GDVIRTUAL_BIND(_integrate_forces, "state");
+
ADD_GROUP("Joint", "joint_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset"), "set_joint_offset", "get_joint_offset");
@@ -2943,10 +2990,13 @@ void PhysicalBone3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
BIND_ENUM_CONSTANT(DAMP_MODE_COMBINE);
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 0f753fef76..6ace681021 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -662,9 +662,13 @@ private:
real_t bounce = 0.0;
real_t mass = 1.0;
real_t friction = 1.0;
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
real_t gravity_scale = 1.0;
bool can_sleep = true;
+ bool custom_integrator = false;
+
DampMode linear_damp_mode = DAMP_MODE_COMBINE;
DampMode angular_damp_mode = DAMP_MODE_COMBINE;
@@ -676,6 +680,7 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_what);
+ GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *)
static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
void _body_state_changed(PhysicsDirectBodyState3D *p_state);
@@ -691,6 +696,15 @@ private:
public:
void _on_bone_parent_changed();
+ void set_linear_velocity(const Vector3 &p_velocity);
+ Vector3 get_linear_velocity() const override;
+
+ void set_angular_velocity(const Vector3 &p_velocity);
+ Vector3 get_angular_velocity() const override;
+
+ void set_use_custom_integrator(bool p_enable);
+ bool is_using_custom_integrator();
+
#ifdef TOOLS_ENABLED
void _set_gizmo_move_joint(bool p_move_joint);
virtual Transform3D get_global_gizmo_transform() const override;
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index be655e71db..1bebd8e335 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -178,10 +178,6 @@ AABB ReflectionProbe::get_aabb() const {
return aabb;
}
-Vector<Face3> ReflectionProbe::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
void ReflectionProbe::_validate_property(PropertyInfo &property) const {
if (property.name == "interior/ambient_color" || property.name == "interior/ambient_color_energy") {
if (ambient_mode != AMBIENT_COLOR) {
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index d0643496a4..424976d895 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -113,7 +113,6 @@ public:
UpdateMode get_update_mode() const;
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
ReflectionProbe();
~ReflectionProbe();
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index ce281c79bc..514bd4aba0 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -177,10 +177,6 @@ AABB SpriteBase3D::get_aabb() const {
return aabb;
}
-Vector<Face3> SpriteBase3D::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
if (triangle_mesh.is_valid()) {
return triangle_mesh;
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 985103e190..92dbef0855 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -137,7 +137,7 @@ public:
virtual Rect2 get_item_rect() const = 0;
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
+
Ref<TriangleMesh> generate_triangle_mesh() const;
SpriteBase3D();
diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp
index 11367d7ca9..41cd604a4f 100644
--- a/scene/3d/visible_on_screen_notifier_3d.cpp
+++ b/scene/3d/visible_on_screen_notifier_3d.cpp
@@ -89,10 +89,6 @@ void VisibleOnScreenNotifier3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("screen_exited"));
}
-Vector<Face3> VisibleOnScreenNotifier3D::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
VisibleOnScreenNotifier3D::VisibleOnScreenNotifier3D() {
RID notifier = RS::get_singleton()->visibility_notifier_create();
RS::get_singleton()->visibility_notifier_set_aabb(notifier, aabb);
diff --git a/scene/3d/visible_on_screen_notifier_3d.h b/scene/3d/visible_on_screen_notifier_3d.h
index 852c7e2ed3..fe17f1e444 100644
--- a/scene/3d/visible_on_screen_notifier_3d.h
+++ b/scene/3d/visible_on_screen_notifier_3d.h
@@ -57,8 +57,6 @@ public:
virtual AABB get_aabb() const override;
bool is_on_screen() const;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
-
VisibleOnScreenNotifier3D();
~VisibleOnScreenNotifier3D();
};
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index d8dffe6c7d..b8a68cdca9 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -32,6 +32,14 @@
#include "scene/scene_string_names.h"
+AABB VisualInstance3D::get_aabb() const {
+ AABB ret;
+ if (GDVIRTUAL_CALL(_get_aabb, ret)) {
+ return ret;
+ }
+ return AABB();
+}
+
AABB VisualInstance3D::get_transformed_aabb() const {
return get_global_transform().xform(get_aabb());
}
@@ -115,6 +123,7 @@ void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb);
+ GDVIRTUAL_BIND(_get_aabb);
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask");
}
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 02f62b41e5..1c044ba681 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -49,6 +49,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ GDVIRTUAL0RC(AABB, _get_aabb)
public:
enum GetFacesFlags {
FACES_SOLID = 1, // solid geometry
@@ -58,8 +59,7 @@ public:
};
RID get_instance() const;
- virtual AABB get_aabb() const = 0;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const = 0;
+ virtual AABB get_aabb() const;
virtual AABB get_transformed_aabb() const; // helper
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index bfe3c80a4f..6840d15f78 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -450,10 +450,6 @@ AABB VoxelGI::get_aabb() const {
return AABB(-extents, extents * 2);
}
-Vector<Face3> VoxelGI::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
TypedArray<String> VoxelGI::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h
index 3678bd4f3b..e1a38dd7a0 100644
--- a/scene/3d/voxel_gi.h
+++ b/scene/3d/voxel_gi.h
@@ -149,7 +149,6 @@ public:
void bake(Node *p_from_node = nullptr, bool p_create_visual_debug = false);
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
TypedArray<String> get_configuration_warnings() const override;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index e243915c13..402418e5a9 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -401,6 +401,22 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
}
}
+static void _call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {
+ // Separate function to use alloca() more efficiently
+ const Variant **argptrs = (const Variant **)alloca(sizeof(const Variant **) * p_params.size());
+ const Variant *args = p_params.ptr();
+ uint32_t argcount = p_params.size();
+ for (uint32_t i = 0; i < argcount; i++) {
+ argptrs[i] = &args[i];
+ }
+ if (p_deferred) {
+ MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount);
+ } else {
+ Callable::CallError ce;
+ p_object->callp(p_method, argptrs, argcount, ce);
+ }
+}
+
void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double p_time, double p_delta, float p_interp, bool p_is_current, bool p_seeked, bool p_started, int p_pingponged) {
_ensure_node_caches(p_anim);
ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count());
@@ -677,41 +693,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
StringName method = a->method_track_get_name(i, E);
Vector<Variant> params = a->method_track_get_params(i, E);
- int s = params.size();
-
- ERR_CONTINUE(s > VARIANT_ARG_MAX);
#ifdef DEBUG_ENABLED
if (!nc->node->has_method(method)) {
ERR_PRINT("Invalid method call '" + method + "'. '" + a->get_name() + "' at node '" + get_path() + "'.");
}
#endif
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
if (can_call) {
- if (method_call_mode == ANIMATION_METHOD_CALL_DEFERRED) {
- MessageQueue::get_singleton()->push_call(
- nc->node,
- method,
- s >= 1 ? params[0] : Variant(),
- s >= 2 ? params[1] : Variant(),
- s >= 3 ? params[2] : Variant(),
- s >= 4 ? params[3] : Variant(),
- s >= 5 ? params[4] : Variant(),
- s >= 6 ? params[5] : Variant(),
- s >= 7 ? params[6] : Variant(),
- s >= 8 ? params[7] : Variant());
- } else {
- nc->node->call(
- method,
- s >= 1 ? params[0] : Variant(),
- s >= 2 ? params[1] : Variant(),
- s >= 3 ? params[2] : Variant(),
- s >= 4 ? params[3] : Variant(),
- s >= 5 ? params[4] : Variant(),
- s >= 6 ? params[5] : Variant(),
- s >= 7 ? params[6] : Variant(),
- s >= 8 ? params[7] : Variant());
- }
+ _call_object(nc->node, method, params, method_call_mode == ANIMATION_METHOD_CALL_DEFERRED);
}
}
@@ -754,7 +743,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
if (!stream.is_valid()) {
- nc->node->call("stop");
+ nc->node->call(SNAME("stop"));
nc->audio_playing = false;
playing_caches.erase(nc);
} else {
@@ -764,14 +753,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
float len = stream->get_length();
if (start_ofs > len - end_ofs) {
- nc->node->call("stop");
+ nc->node->call(SNAME("stop"));
nc->audio_playing = false;
playing_caches.erase(nc);
continue;
}
- nc->node->call("set_stream", stream);
- nc->node->call("play", start_ofs);
+ nc->node->call(SNAME("set_stream"), stream);
+ nc->node->call(SNAME("play"), start_ofs);
nc->audio_playing = true;
playing_caches.insert(nc);
@@ -793,7 +782,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
if (!stream.is_valid()) {
- nc->node->call("stop");
+ nc->node->call(SNAME("stop"));
nc->audio_playing = false;
playing_caches.erase(nc);
} else {
@@ -801,8 +790,8 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
float end_ofs = a->audio_track_get_key_end_offset(i, idx);
float len = stream->get_length();
- nc->node->call("set_stream", stream);
- nc->node->call("play", start_ofs);
+ nc->node->call(SNAME("set_stream"), stream);
+ nc->node->call(SNAME("play"), start_ofs);
nc->audio_playing = true;
playing_caches.insert(nc);
@@ -833,7 +822,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (stop) {
//time to stop
- nc->node->call("stop");
+ nc->node->call(SNAME("stop"));
nc->audio_playing = false;
playing_caches.erase(nc);
}
@@ -1544,7 +1533,7 @@ void AnimationPlayer::_animation_changed() {
void AnimationPlayer::_stop_playing_caches() {
for (Set<TrackNodeCache *>::Element *E = playing_caches.front(); E; E = E->next()) {
if (E->get()->node && E->get()->audio_playing) {
- E->get()->node->call("stop");
+ E->get()->node->call(SNAME("stop"));
}
if (E->get()->node && E->get()->animation_playing) {
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(E->get()->node);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index a50618182d..e0e94d8632 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -490,7 +490,7 @@ void AnimationTree::set_active(bool p_active) {
if (!active && is_inside_tree()) {
for (Set<TrackCache *>::Element *E = playing_caches.front(); E; E = E->next()) {
if (ObjectDB::get_instance(E->get()->object_id)) {
- E->get()->object->call("stop");
+ E->get()->object->call(SNAME("stop"));
}
}
@@ -796,6 +796,21 @@ void AnimationTree::_clear_caches() {
cache_valid = false;
}
+static void _call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {
+ // Separate function to use alloca() more efficiently
+ const Variant **argptrs = (const Variant **)alloca(sizeof(const Variant **) * p_params.size());
+ const Variant *args = p_params.ptr();
+ uint32_t argcount = p_params.size();
+ for (uint32_t i = 0; i < argcount; i++) {
+ argptrs[i] = &args[i];
+ }
+ if (p_deferred) {
+ MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount);
+ } else {
+ Callable::CallError ce;
+ p_object->callp(p_method, argptrs, argcount, ce);
+ }
+}
void AnimationTree::_process_graph(double p_delta) {
_update_properties(); //if properties need updating, update them
@@ -1286,25 +1301,10 @@ void AnimationTree::_process_graph(double p_delta) {
for (int &F : indices) {
StringName method = a->method_track_get_name(i, F);
Vector<Variant> params = a->method_track_get_params(i, F);
-
- int s = params.size();
-
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- ERR_CONTINUE(s > VARIANT_ARG_MAX);
if (can_call) {
- t->object->call_deferred(
- method,
- s >= 1 ? params[0] : Variant(),
- s >= 2 ? params[1] : Variant(),
- s >= 3 ? params[2] : Variant(),
- s >= 4 ? params[3] : Variant(),
- s >= 5 ? params[4] : Variant(),
- s >= 6 ? params[5] : Variant(),
- s >= 7 ? params[6] : Variant(),
- s >= 8 ? params[7] : Variant());
+ _call_object(t->object, method, params, true);
}
}
-
} break;
case Animation::TYPE_BEZIER: {
TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
@@ -1331,7 +1331,7 @@ void AnimationTree::_process_graph(double p_delta) {
Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
if (!stream.is_valid()) {
- t->object->call("stop");
+ t->object->call(SNAME("stop"));
t->playing = false;
playing_caches.erase(t);
} else {
@@ -1341,14 +1341,14 @@ void AnimationTree::_process_graph(double p_delta) {
double len = stream->get_length();
if (start_ofs > len - end_ofs) {
- t->object->call("stop");
+ t->object->call(SNAME("stop"));
t->playing = false;
playing_caches.erase(t);
continue;
}
- t->object->call("set_stream", stream);
- t->object->call("play", start_ofs);
+ t->object->call(SNAME("set_stream"), stream);
+ t->object->call(SNAME("play"), start_ofs);
t->playing = true;
playing_caches.insert(t);
@@ -1370,7 +1370,7 @@ void AnimationTree::_process_graph(double p_delta) {
Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
if (!stream.is_valid()) {
- t->object->call("stop");
+ t->object->call(SNAME("stop"));
t->playing = false;
playing_caches.erase(t);
} else {
@@ -1378,8 +1378,8 @@ void AnimationTree::_process_graph(double p_delta) {
double end_ofs = a->audio_track_get_key_end_offset(i, idx);
double len = stream->get_length();
- t->object->call("set_stream", stream);
- t->object->call("play", start_ofs);
+ t->object->call(SNAME("set_stream"), stream);
+ t->object->call(SNAME("play"), start_ofs);
t->playing = true;
playing_caches.insert(t);
@@ -1416,7 +1416,7 @@ void AnimationTree::_process_graph(double p_delta) {
if (stop) {
//time to stop
- t->object->call("stop");
+ t->object->call(SNAME("stop"));
t->playing = false;
playing_caches.erase(t);
}
@@ -1424,10 +1424,10 @@ void AnimationTree::_process_graph(double p_delta) {
}
real_t db = Math::linear2db(MAX(blend, 0.00001));
- if (t->object->has_method("set_unit_db")) {
- t->object->call("set_unit_db", db);
+ if (t->object->has_method(SNAME("set_unit_db"))) {
+ t->object->call(SNAME("set_unit_db"), db);
} else {
- t->object->call("set_volume_db", db);
+ t->object->call(SNAME("set_volume_db"), db);
}
} break;
case Animation::TYPE_ANIMATION: {
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index 46fe832cf5..42adc1ea02 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -166,10 +166,6 @@ AABB RootMotionView::get_aabb() const {
return AABB(Vector3(-radius, 0, -radius), Vector3(radius * 2, 0.001, radius * 2));
}
-Vector<Face3> RootMotionView::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
void RootMotionView::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_animation_path", "path"), &RootMotionView::set_animation_path);
ClassDB::bind_method(D_METHOD("get_animation_path"), &RootMotionView::get_animation_path);
diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h
index e8b141c1fd..8cb8ea8a9a 100644
--- a/scene/animation/root_motion_view.h
+++ b/scene/animation/root_motion_view.h
@@ -71,7 +71,6 @@ public:
bool get_zero_y() const;
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
RootMotionView();
~RootMotionView();
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index e5b81f9d8d..ac0d017a23 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -34,6 +34,7 @@
#include "core/debugger/engine_profiler.h"
#include "core/io/marshalls.h"
#include "core/object/script_language.h"
+#include "core/templates/local_vector.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
@@ -236,12 +237,28 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra
live_editor->_res_set_func(p_args[0], p_args[1], p_args[2]);
} else if (p_msg == "live_node_call") {
- ERR_FAIL_COND_V(p_args.size() < 10, ERR_INVALID_DATA);
- live_editor->_node_call_func(p_args[0], p_args[1], p_args[2], p_args[3], p_args[4], p_args[5], p_args[6], p_args[7], p_args[8], p_args[9]);
+ LocalVector<Variant> args;
+ LocalVector<Variant *> argptrs;
+ args.resize(p_args.size() - 2);
+ argptrs.resize(args.size());
+ for (uint32_t i = 0; i < args.size(); i++) {
+ args[i] = p_args[i + 2];
+ argptrs[i] = &args[i];
+ }
+ live_editor->_node_call_func(p_args[0], p_args[1], (const Variant **)argptrs.ptr(), argptrs.size());
} else if (p_msg == "live_res_call") {
ERR_FAIL_COND_V(p_args.size() < 10, ERR_INVALID_DATA);
- live_editor->_res_call_func(p_args[0], p_args[1], p_args[2], p_args[3], p_args[4], p_args[5], p_args[6], p_args[7], p_args[8], p_args[9]);
+
+ LocalVector<Variant> args;
+ LocalVector<Variant *> argptrs;
+ args.resize(p_args.size() - 2);
+ argptrs.resize(args.size());
+ for (uint32_t i = 0; i < args.size(); i++) {
+ args[i] = p_args[i + 2];
+ argptrs[i] = &args[i];
+ }
+ live_editor->_res_call_func(p_args[0], p_args[1], (const Variant **)argptrs.ptr(), argptrs.size());
} else if (p_msg == "live_create_node") {
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
@@ -636,7 +653,7 @@ void LiveEditor::_node_set_res_func(int p_id, const StringName &p_prop, const St
_node_set_func(p_id, p_prop, r);
}
-void LiveEditor::_node_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
+void LiveEditor::_node_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount) {
SceneTree *scene_tree = SceneTree::get_singleton();
if (!scene_tree) {
return;
@@ -668,7 +685,8 @@ void LiveEditor::_node_call_func(int p_id, const StringName &p_method, VARIANT_A
}
Node *n2 = n->get_node(np);
- n2->call(p_method, VARIANT_ARG_PASS);
+ Callable::CallError ce;
+ n2->callp(p_method, p_args, p_argcount, ce);
}
}
@@ -699,7 +717,7 @@ void LiveEditor::_res_set_res_func(int p_id, const StringName &p_prop, const Str
_res_set_func(p_id, p_prop, r);
}
-void LiveEditor::_res_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
+void LiveEditor::_res_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount) {
if (!live_edit_resource_cache.has(p_id)) {
return;
}
@@ -715,7 +733,8 @@ void LiveEditor::_res_call_func(int p_id, const StringName &p_method, VARIANT_AR
return;
}
- r->call(p_method, VARIANT_ARG_PASS);
+ Callable::CallError ce;
+ r->callp(p_method, p_args, p_argcount, ce);
}
void LiveEditor::_root_func(const NodePath &p_scene_path, const String &p_scene_from) {
diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h
index dd0a17c2dc..29d7da7d11 100644
--- a/scene/debugger/scene_debugger.h
+++ b/scene/debugger/scene_debugger.h
@@ -148,10 +148,10 @@ private:
void _node_set_func(int p_id, const StringName &p_prop, const Variant &p_value);
void _node_set_res_func(int p_id, const StringName &p_prop, const String &p_value);
- void _node_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE);
+ void _node_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount);
void _res_set_func(int p_id, const StringName &p_prop, const Variant &p_value);
void _res_set_res_func(int p_id, const StringName &p_prop, const String &p_value);
- void _res_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE);
+ void _res_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount);
void _root_func(const NodePath &p_scene_path, const String &p_scene_from);
void _create_node_func(const NodePath &p_parent, const String &p_type, const String &p_name);
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 0338326bbe..ab86face7e 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -349,7 +349,7 @@ Ref<Shortcut> BaseButton::get_shortcut() const {
void BaseButton::unhandled_key_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!_is_focus_owner_in_shorcut_context()) {
+ if (!_is_focus_owner_in_shortcut_context()) {
return;
}
@@ -404,7 +404,7 @@ Node *BaseButton::get_shortcut_context() const {
return ctx_node;
}
-bool BaseButton::_is_focus_owner_in_shorcut_context() const {
+bool BaseButton::_is_focus_owner_in_shortcut_context() const {
if (shortcut_context == ObjectID()) {
// No context, therefore global - always "in" context.
return true;
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index 6bfffe7575..a2b6ee0845 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -80,7 +80,7 @@ protected:
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
- bool _is_focus_owner_in_shorcut_context() const;
+ bool _is_focus_owner_in_shortcut_context() const;
GDVIRTUAL0(_pressed)
GDVIRTUAL1(_toggled, bool)
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 27e8b102be..724714b93b 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -583,8 +583,8 @@ void Button::_bind_methods() {
Button::Button(const String &p_text) {
text_buf.instantiate();
text_buf->set_flags(TextServer::BREAK_MANDATORY);
-
set_mouse_filter(MOUSE_FILTER_STOP);
+
set_text(p_text);
}
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index 5e3131f8a0..527b0061ac 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -111,9 +111,12 @@ void CheckButton::_notification(int p_what) {
}
}
-CheckButton::CheckButton() {
+CheckButton::CheckButton(const String &p_text) :
+ Button(p_text) {
set_toggle_mode(true);
+
set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
+
if (is_layout_rtl()) {
_set_internal_margin(SIDE_LEFT, get_icon_size().width);
} else {
diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h
index 9a72d04db2..7d4bb8bdfc 100644
--- a/scene/gui/check_button.h
+++ b/scene/gui/check_button.h
@@ -42,7 +42,7 @@ protected:
void _notification(int p_what);
public:
- CheckButton();
+ CheckButton(const String &p_text = String());
~CheckButton();
};
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 3ea2a9795d..9f32ac223c 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -1304,7 +1304,7 @@ void ColorPickerButton::pressed() {
Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
- popup->set_as_minsize();
+ popup->reset_size();
picker->_update_presets();
Rect2i usable_rect = popup->get_usable_parent_rect();
@@ -1429,7 +1429,8 @@ void ColorPickerButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
}
-ColorPickerButton::ColorPickerButton() {
+ColorPickerButton::ColorPickerButton(const String &p_text) :
+ Button(p_text) {
set_toggle_mode(true);
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index d6067b1cf4..6f3e16009c 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -231,7 +231,7 @@ public:
ColorPicker *get_picker();
PopupPanel *get_popup();
- ColorPickerButton();
+ ColorPickerButton(const String &p_text = String());
};
VARIANT_ENUM_CAST(ColorPicker::PickerShapeType);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 46f60c92d9..d8659b1f18 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -190,10 +190,10 @@ String Control::properties_managed_by_container[] = {
"anchor_top",
"anchor_right",
"anchor_bottom",
- "rect_position",
- "rect_rotation",
- "rect_scale",
- "rect_size"
+ "position",
+ "rotation",
+ "scale",
+ "size"
};
void Control::accept_event() {
@@ -250,42 +250,41 @@ Transform2D Control::_get_internal_transform() const {
bool Control::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
- // Prefixes "custom_*" are supported for compatibility with 3.x.
- if (!name.begins_with("theme_override") && !name.begins_with("custom")) {
+ if (!name.begins_with("theme_override")) {
return false;
}
if (p_value.get_type() == Variant::NIL || (p_value.get_type() == Variant::OBJECT && (Object *)p_value == nullptr)) {
- if (name.begins_with("theme_override_icons/") || name.begins_with("custom_icons/")) {
+ if (name.begins_with("theme_override_icons/")) {
String dname = name.get_slicec('/', 1);
if (data.icon_override.has(dname)) {
data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
data.icon_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
- } else if (name.begins_with("theme_override_styles/") || name.begins_with("custom_styles/")) {
+ } else if (name.begins_with("theme_override_styles/")) {
String dname = name.get_slicec('/', 1);
if (data.style_override.has(dname)) {
data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
data.style_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
- } else if (name.begins_with("theme_override_fonts/") || name.begins_with("custom_fonts/")) {
+ } else if (name.begins_with("theme_override_fonts/")) {
String dname = name.get_slicec('/', 1);
if (data.font_override.has(dname)) {
data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
data.font_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
- } else if (name.begins_with("theme_override_font_sizes/") || name.begins_with("custom_font_sizes/")) {
+ } else if (name.begins_with("theme_override_font_sizes/")) {
String dname = name.get_slicec('/', 1);
data.font_size_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
- } else if (name.begins_with("theme_override_colors/") || name.begins_with("custom_colors/")) {
+ } else if (name.begins_with("theme_override_colors/")) {
String dname = name.get_slicec('/', 1);
data.color_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
- } else if (name.begins_with("theme_override_constants/") || name.begins_with("custom_constants/")) {
+ } else if (name.begins_with("theme_override_constants/")) {
String dname = name.get_slicec('/', 1);
data.constant_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
@@ -294,22 +293,22 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) {
}
} else {
- if (name.begins_with("theme_override_icons/") || name.begins_with("custom_icons/")) {
+ if (name.begins_with("theme_override_icons/")) {
String dname = name.get_slicec('/', 1);
add_theme_icon_override(dname, p_value);
- } else if (name.begins_with("theme_override_styles/") || name.begins_with("custom_styles/")) {
+ } else if (name.begins_with("theme_override_styles/")) {
String dname = name.get_slicec('/', 1);
add_theme_style_override(dname, p_value);
- } else if (name.begins_with("theme_override_fonts/") || name.begins_with("custom_fonts/")) {
+ } else if (name.begins_with("theme_override_fonts/")) {
String dname = name.get_slicec('/', 1);
add_theme_font_override(dname, p_value);
- } else if (name.begins_with("theme_override_font_sizes/") || name.begins_with("custom_font_sizes/")) {
+ } else if (name.begins_with("theme_override_font_sizes/")) {
String dname = name.get_slicec('/', 1);
add_theme_font_size_override(dname, p_value);
- } else if (name.begins_with("theme_override_colors/") || name.begins_with("custom_colors/")) {
+ } else if (name.begins_with("theme_override_colors/")) {
String dname = name.get_slicec('/', 1);
add_theme_color_override(dname, p_value);
- } else if (name.begins_with("theme_override_constants/") || name.begins_with("custom_constants/")) {
+ } else if (name.begins_with("theme_override_constants/")) {
String dname = name.get_slicec('/', 1);
add_theme_constant_override(dname, p_value);
} else {
@@ -491,7 +490,7 @@ void Control::_validate_property(PropertyInfo &property) const {
} else if (Object::cast_to<Container>(parent_node)) {
// If the parent is a container, display only container-related properties.
if (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_") || property.name == "anchors_preset" ||
- (property.name.begins_with("rect_") && property.name != "rect_min_size" && property.name != "rect_clip_content" && property.name != "rect_global_position")) {
+ property.name == "position" || property.name == "rotation" || property.name == "scale" || property.name == "size" || property.name == "pivot_offset") {
property.usage ^= PROPERTY_USAGE_EDITOR;
} else if (property.name == "layout_mode") {
@@ -3343,8 +3342,8 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_auto_translating"), &Control::is_auto_translating);
ADD_GROUP("Layout", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimum_size"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
@@ -3373,15 +3372,13 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_horizontal", PROPERTY_HINT_ENUM, "Left,Right,Both"), "set_h_grow_direction", "get_h_grow_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Top,Bottom,Both"), "set_v_grow_direction", "get_v_grow_direction");
- ADD_SUBGROUP("Rectangle", "rect_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size");
-
- ADD_SUBGROUP("Transform", "rect_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rect_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset");
+ ADD_SUBGROUP("Transform", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset"), "set_pivot_offset", "get_pivot_offset");
ADD_SUBGROUP("Container Sizing", "size_flags_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_horizontal", PROPERTY_HINT_FLAGS, "Fill:1,Expand:2,Shrink Center:4,Shrink End:8"), "set_h_size_flags", "get_h_size_flags");
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 79aaf5c511..678229683f 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -262,7 +262,8 @@ void FileDialog::_action_pressed() {
return;
}
- String f = dir_access->get_current_dir().plus_file(file->get_text());
+ String file_text = file->get_text();
+ String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text);
if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
emit_signal(SNAME("file_selected"), f);
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index ff4e071a95..da39a3d387 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -647,8 +647,8 @@ void LineEdit::_notification(int p_what) {
#ifdef TOOLS_ENABLED
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) {
- set_caret_blink_enabled(EDITOR_DEF("text_editor/appearance/caret/caret_blink", false));
- set_caret_blink_speed(EDITOR_DEF("text_editor/appearance/caret/caret_blink_speed", 0.65));
+ set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
+ set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed"));
if (!EditorSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed))) {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed));
@@ -1944,8 +1944,8 @@ PopupMenu *LineEdit::get_menu() const {
void LineEdit::_editor_settings_changed() {
#ifdef TOOLS_ENABLED
- set_caret_blink_enabled(EDITOR_DEF("text_editor/appearance/caret/caret_blink", false));
- set_caret_blink_speed(EDITOR_DEF("text_editor/appearance/caret/caret_blink_speed", 0.65));
+ set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
+ set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed"));
#endif
}
@@ -2437,7 +2437,7 @@ void LineEdit::_ensure_menu() {
}
}
-LineEdit::LineEdit() {
+LineEdit::LineEdit(const String &p_placeholder) {
text_rid = TS->create_shaped_text();
_create_undo_state();
@@ -2452,6 +2452,8 @@ LineEdit::LineEdit() {
caret_blink_timer->connect("timeout", callable_mp(this, &LineEdit::_toggle_draw_caret));
set_caret_blink_enabled(false);
+ set_placeholder(p_placeholder);
+
set_editable(true); // Initialise to opposite first, so we get past the early-out in set_editable.
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 1519c09d73..444c9a1c50 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -332,7 +332,7 @@ public:
void show_virtual_keyboard();
- LineEdit();
+ LineEdit(const String &p_placeholder = String());
~LineEdit();
};
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 8f40f717c2..dc4f09d22d 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -317,8 +317,10 @@ void LinkButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
}
-LinkButton::LinkButton() {
+LinkButton::LinkButton(const String &p_text) {
text_buf.instantiate();
set_focus_mode(FOCUS_NONE);
set_default_cursor_shape(CURSOR_POINTING_HAND);
+
+ set_text(p_text);
}
diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h
index a455e866b1..f996558f32 100644
--- a/scene/gui/link_button.h
+++ b/scene/gui/link_button.h
@@ -90,7 +90,7 @@ public:
void set_underline_mode(UnderlineMode p_underline_mode);
UnderlineMode get_underline_mode() const;
- LinkButton();
+ LinkButton(const String &p_text = String());
};
VARIANT_ENUM_CAST(LinkButton::UnderlineMode);
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 46d8a61ca1..7e724e4d71 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -36,7 +36,7 @@
void MenuButton::unhandled_key_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!_is_focus_owner_in_shorcut_context()) {
+ if (!_is_focus_owner_in_shortcut_context()) {
return;
}
@@ -227,7 +227,8 @@ void MenuButton::set_disable_shortcuts(bool p_disabled) {
disable_shortcuts = p_disabled;
}
-MenuButton::MenuButton() {
+MenuButton::MenuButton(const String &p_text) :
+ Button(p_text) {
set_flat(true);
set_toggle_mode(true);
set_disable_shortcuts(false);
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index 3647a69d33..9cfb780255 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -67,7 +67,7 @@ public:
void set_item_count(int p_count);
int get_item_count() const;
- MenuButton();
+ MenuButton(const String &p_text = String());
~MenuButton();
};
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 698d74843c..b3804e73d9 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -412,7 +412,8 @@ void OptionButton::_bind_methods() {
ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index")));
}
-OptionButton::OptionButton() {
+OptionButton::OptionButton(const String &p_text) :
+ Button(p_text) {
set_toggle_mode(true);
set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
if (is_layout_rtl()) {
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index adf2bb90ef..5352fe18a6 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -94,7 +94,7 @@ public:
virtual void get_translatable_strings(List<String> *p_strings) const override;
- OptionButton();
+ OptionButton(const String &p_text = String());
~OptionButton();
};
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 24b91cd16a..b9e3e7814e 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -111,10 +111,6 @@ void Popup::_close_pressed() {
call_deferred(SNAME("hide"));
}
-void Popup::set_as_minsize() {
- set_size(get_contents_minimum_size());
-}
-
void Popup::_bind_methods() {
ADD_SIGNAL(MethodInfo("popup_hide"));
}
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index a3c56c9ff1..c45f4ddc24 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -58,8 +58,6 @@ protected:
static void _bind_methods();
public:
- void set_as_minsize();
-
Popup();
~Popup();
};
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index af2edfa090..840c3d5c31 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -186,7 +186,7 @@ void PopupMenu::_activate_submenu(int p_over) {
float scroll_offset = control->get_position().y;
- submenu_popup->set_as_minsize(); // Shrink the popup size to its contents.
+ submenu_popup->reset_size(); // Shrink the popup size to its contents.
Size2 submenu_size = submenu_popup->get_size();
Point2 submenu_pos;
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index 879f25c8d8..2fb6452a97 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -40,6 +40,9 @@ TypedArray<String> Range::get_configuration_warnings() const {
return warnings;
}
+void Range::_value_changed(double p_value) {
+ GDVIRTUAL_CALL(_value_changed, p_value);
+}
void Range::_value_changed_notify() {
_value_changed(shared->val);
emit_signal(SNAME("value_changed"), shared->val);
@@ -279,6 +282,8 @@ void Range::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_greater"), "set_allow_greater", "is_greater_allowed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed");
+ GDVIRTUAL_BIND(_value_changed);
+
ADD_LINKED_PROPERTY("min_value", "value");
ADD_LINKED_PROPERTY("min_value", "max_value");
ADD_LINKED_PROPERTY("min_value", "page");
diff --git a/scene/gui/range.h b/scene/gui/range.h
index c27eeee13c..597c50ca26 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -62,12 +62,14 @@ class Range : public Control {
void _validate_values();
protected:
- virtual void _value_changed(double) {}
+ virtual void _value_changed(double p_value);
static void _bind_methods();
bool _rounded_values = false;
+ GDVIRTUAL1(_value_changed, double)
+
public:
void set_value(double p_val);
void set_min(double p_min);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index dd07831b83..bad7be7d42 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -3250,6 +3250,10 @@ void RichTextLabel::append_text(const String &p_bbcode) {
push_paragraph(HORIZONTAL_ALIGNMENT_FILL);
pos = brk_end + 1;
tag_stack.push_front(tag);
+ } else if (tag == "left") {
+ push_paragraph(HORIZONTAL_ALIGNMENT_LEFT);
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
} else if (tag == "right") {
push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT);
pos = brk_end + 1;
@@ -4712,7 +4716,7 @@ Dictionary RichTextLabel::parse_expressions_for_values(Vector<String> p_expressi
return d;
}
-RichTextLabel::RichTextLabel() {
+RichTextLabel::RichTextLabel(const String &p_text) {
main = memnew(ItemFrame);
main->index = 0;
current = main;
@@ -4734,6 +4738,8 @@ RichTextLabel::RichTextLabel() {
vscroll->set_step(1);
vscroll->hide();
+ set_text(p_text);
+
set_clip_contents(true);
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 53c2046c8f..076b68a0da 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -620,7 +620,7 @@ public:
void set_fixed_size_to_width(int p_width);
virtual Size2 get_minimum_size() const override;
- RichTextLabel();
+ RichTextLabel(const String &p_text = String());
~RichTextLabel();
};
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 5fd31c5416..e50d7e765c 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -39,7 +39,7 @@ Size2 SpinBox::get_minimum_size() const {
return ms;
}
-void SpinBox::_value_changed(double) {
+void SpinBox::_value_changed(double p_value) {
String value = TS->format_number(String::num(get_value(), Math::range_step_decimals(get_step())));
if (!prefix.is_empty()) {
value = prefix + " " + value;
@@ -48,6 +48,7 @@ void SpinBox::_value_changed(double) {
value += " " + suffix;
}
line_edit->set_text(value);
+ Range::_value_changed(p_value);
}
void SpinBox::_text_submitted(const String &p_string) {
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 0691a4b48d..a15e3fe5f5 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -47,7 +47,7 @@ class SpinBox : public Range {
void _release_mouse();
void _text_submitted(const String &p_string);
- virtual void _value_changed(double) override;
+ virtual void _value_changed(double p_value) override;
void _text_changed(const String &p_string);
String prefix;
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index ce60da762f..af314b9545 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -71,7 +71,7 @@ Size2 TabBar::get_minimum_size() const {
Ref<Texture2D> tex = tabs[i].icon;
if (tex.is_valid()) {
- ms.height = MAX(ms.height, tex->get_size().height);
+ ms.height = MAX(ms.height, tex->get_size().height + y_margin);
ms.width += tex->get_size().width + hseparation;
}
@@ -91,13 +91,13 @@ Size2 TabBar::get_minimum_size() const {
ms.width += button_highlight->get_margin(SIDE_LEFT) + rb->get_width() + hseparation;
}
- ms.height = MAX(rb->get_height() + style->get_minimum_size().height, ms.height);
+ ms.height = MAX(ms.height, rb->get_height() + y_margin);
}
if (close_visible) {
ms.width += button_highlight->get_margin(SIDE_LEFT) + close->get_width() + hseparation;
- ms.height = MAX(close->get_height() + style->get_minimum_size().height, ms.height);
+ ms.height = MAX(ms.height, close->get_height() + y_margin);
}
if (ms.width - ofs > style->get_minimum_size().width) {
@@ -552,10 +552,6 @@ void TabBar::set_current_tab(int p_current) {
emit_signal(SNAME("tab_selected"), current);
return;
}
- // Triggered by dragging a tab from another TabBar to the selected index, to ensure that tab_changed is emitted.
- if (previous == -1) {
- previous = current;
- }
emit_signal(SNAME("tab_selected"), current);
@@ -831,78 +827,52 @@ void TabBar::_update_cache() {
int limit_minus_buttons = limit - incr->get_width() - decr->get_width();
int w = 0;
- int mw = 0;
- int size_fixed = 0;
- int count_resize = 0;
+
+ max_drawn_tab = tabs.size() - 1;
for (int i = 0; i < tabs.size(); i++) {
- tabs.write[i].size_text = Math::ceil(tabs[i].text_buf->get_size().x);
tabs.write[i].text_buf->set_width(-1);
-
- tabs.write[i].ofs_cache = 0;
+ tabs.write[i].size_text = Math::ceil(tabs[i].text_buf->get_size().x);
tabs.write[i].size_cache = get_tab_width(i);
- if (!tabs[i].hidden) {
- mw += tabs[i].size_cache;
+ if (max_width > 0 && tabs[i].size_cache > max_width) {
+ int size_textless = tabs[i].size_cache - tabs[i].size_text;
+ int mw = MAX(size_textless, max_width);
- if (tabs[i].size_cache <= min_width || i == current) {
- size_fixed += tabs[i].size_cache;
- } else {
- count_resize++;
- }
+ tabs.write[i].size_text = MAX(mw - size_textless, 1);
+ tabs.write[i].text_buf->set_width(tabs[i].size_text);
+ tabs.write[i].size_cache = size_textless + tabs[i].size_text;
}
- }
-
- int m_width = min_width;
- if (count_resize > 0) {
- m_width = MAX((limit_minus_buttons - size_fixed) / count_resize, min_width);
- }
-
- for (int i = offset; i < tabs.size(); i++) {
- if (tabs[i].hidden) {
- tabs.write[i].ofs_cache = w;
- max_drawn_tab = i;
+ if (i < offset || i > max_drawn_tab) {
+ tabs.write[i].ofs_cache = 0;
continue;
}
- int lsize = tabs[i].size_cache;
- int slen = tabs[i].size_text;
+ tabs.write[i].ofs_cache = w;
- // FIXME: This is completely broken.
- if (min_width > 0 && (mw > limit || (offset > 0 && mw > limit_minus_buttons)) && i != current && lsize > m_width) {
- slen = MAX(m_width - tabs[i].size_cache + tabs[i].size_text, 1);
- lsize = m_width;
+ if (tabs[i].hidden) {
+ continue;
}
- tabs.write[i].ofs_cache = w;
- tabs.write[i].size_cache = lsize;
- tabs.write[i].size_text = slen;
- tabs.write[i].text_buf->set_width(slen);
-
- w += lsize;
- max_drawn_tab = i;
+ w += tabs[i].size_cache;
// Check if all tabs would fit inside the area.
if (clip_tabs && i > offset && (w > limit || (offset > 0 && w > limit_minus_buttons))) {
tabs.write[i].ofs_cache = 0;
- tabs.write[i].text_buf->set_width(-1);
w -= tabs[i].size_cache;
- max_drawn_tab--;
+ max_drawn_tab = i - 1;
while (w > limit_minus_buttons && max_drawn_tab > offset) {
tabs.write[max_drawn_tab].ofs_cache = 0;
if (!tabs[max_drawn_tab].hidden) {
- tabs.write[max_drawn_tab].text_buf->set_width(-1);
w -= tabs[max_drawn_tab].size_cache;
}
max_drawn_tab--;
}
-
- break;
}
}
@@ -942,21 +912,28 @@ void TabBar::_on_mouse_exited() {
void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) {
Tab t;
t.text = p_str;
- t.xl_text = atr(p_str);
t.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
- t.text_buf->add_string(t.xl_text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
t.icon = p_icon;
tabs.push_back(t);
+ _shape(tabs.size() - 1);
_update_cache();
if (scroll_to_selected) {
ensure_tab_visible(current);
}
update();
update_minimum_size();
+
+ if (tabs.size() == 1 && is_inside_tree()) {
+ emit_signal(SNAME("tab_changed"), 0);
+ }
}
void TabBar::clear_tabs() {
+ if (tabs.is_empty()) {
+ return;
+ }
+
tabs.clear();
offset = 0;
max_drawn_tab = 0;
@@ -971,14 +948,16 @@ void TabBar::clear_tabs() {
void TabBar::remove_tab(int p_idx) {
ERR_FAIL_INDEX(p_idx, tabs.size());
tabs.remove_at(p_idx);
- if (current >= p_idx) {
+
+ bool is_tab_changing = current == p_idx && !tabs.is_empty();
+
+ if (current >= p_idx && current > 0) {
current--;
}
- if (current < 0) {
+ if (tabs.is_empty()) {
offset = 0;
max_drawn_tab = 0;
- current = 0;
previous = 0;
} else {
offset = MIN(offset, tabs.size() - 1);
@@ -986,7 +965,7 @@ void TabBar::remove_tab(int p_idx) {
_update_cache();
_ensure_no_over_offset();
- if (scroll_to_selected && !tabs.is_empty()) {
+ if (scroll_to_selected) {
ensure_tab_visible(current);
}
}
@@ -994,15 +973,18 @@ void TabBar::remove_tab(int p_idx) {
update();
update_minimum_size();
notify_property_list_changed();
+
+ if (is_tab_changing && is_inside_tree()) {
+ emit_signal(SNAME("tab_changed"), current);
+ }
}
Variant TabBar::get_drag_data(const Point2 &p_point) {
if (!drag_to_rearrange_enabled) {
- return Variant();
+ return Control::get_drag_data(p_point); // Allow stuff like TabContainer to override it.
}
int tab_over = get_tab_idx_at_point(p_point);
-
if (tab_over < 0) {
return Variant();
}
@@ -1025,12 +1007,13 @@ Variant TabBar::get_drag_data(const Point2 &p_point) {
drag_data["type"] = "tab_element";
drag_data["tab_element"] = tab_over;
drag_data["from_path"] = get_path();
+
return drag_data;
}
bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
if (!drag_to_rearrange_enabled) {
- return false;
+ return Control::can_drop_data(p_point, p_data); // Allow stuff like TabContainer to override it.
}
Dictionary d = p_data;
@@ -1052,16 +1035,16 @@ bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
}
}
}
+
return false;
}
void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
if (!drag_to_rearrange_enabled) {
+ Control::drop_data(p_point, p_data); // Allow stuff like TabContainer to override it.
return;
}
- int hover_now = get_tab_idx_at_point(p_point);
-
Dictionary d = p_data;
if (!d.has("type")) {
return;
@@ -1069,6 +1052,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
if (String(d["type"]) == "tab_element") {
int tab_from_id = d["tab_element"];
+ int hover_now = get_tab_idx_at_point(p_point);
NodePath from_path = d["from_path"];
NodePath to_path = get_path();
@@ -1096,15 +1080,25 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
hover_now = get_tab_count();
}
- // Workaround to ensure that tab_changed is emitted.
- if (current == hover_now) {
- current = -1;
+ from_tabs->remove_tab(tab_from_id);
+ tabs.insert(hover_now, moving_tab);
+
+ if (tabs.size() > 1) {
+ if (current >= hover_now) {
+ current++;
+ }
+ if (previous >= hover_now) {
+ previous++;
+ }
}
- tabs.insert(hover_now, moving_tab);
- from_tabs->remove_tab(tab_from_id);
set_current_tab(hover_now);
update_minimum_size();
+
+ if (tabs.size() == 1) {
+ emit_signal(SNAME("tab_selected"), 0);
+ emit_signal(SNAME("tab_changed"), 0);
+ }
}
}
}
@@ -1157,17 +1151,33 @@ bool TabBar::get_clip_tabs() const {
return clip_tabs;
}
-void TabBar::move_tab(int from, int to) {
- if (from == to) {
+void TabBar::move_tab(int p_from, int p_to) {
+ if (p_from == p_to) {
return;
}
- ERR_FAIL_INDEX(from, tabs.size());
- ERR_FAIL_INDEX(to, tabs.size());
+ ERR_FAIL_INDEX(p_from, tabs.size());
+ ERR_FAIL_INDEX(p_to, tabs.size());
+
+ Tab tab_from = tabs[p_from];
+ tabs.remove_at(p_from);
+ tabs.insert(p_to, tab_from);
+
+ if (current == p_from) {
+ current = p_to;
+ } else if (current > p_from && current <= p_to) {
+ current--;
+ } else if (current < p_from && current >= p_to) {
+ current++;
+ }
- Tab tab_from = tabs[from];
- tabs.remove_at(from);
- tabs.insert(to, tab_from);
+ if (previous == p_from) {
+ previous = p_to;
+ } else if (previous > p_from && previous >= p_to) {
+ previous--;
+ } else if (previous < p_from && previous <= p_to) {
+ previous++;
+ }
_update_cache();
_ensure_no_over_offset();
@@ -1342,8 +1352,21 @@ TabBar::CloseButtonDisplayPolicy TabBar::get_tab_close_display_policy() const {
return cb_displaypolicy;
}
-void TabBar::set_min_width(int p_width) {
- min_width = p_width;
+void TabBar::set_max_tab_width(int p_width) {
+ ERR_FAIL_COND(p_width < 0);
+ max_width = p_width;
+
+ _update_cache();
+ _ensure_no_over_offset();
+ if (scroll_to_selected) {
+ ensure_tab_visible(current);
+ }
+ update();
+ update_minimum_size();
+}
+
+int TabBar::get_max_tab_width() const {
+ return max_width;
}
void TabBar::set_scrolling_enabled(bool p_enabled) {
@@ -1466,6 +1489,7 @@ void TabBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_tab_hidden", "tab_idx"), &TabBar::is_tab_hidden);
ClassDB::bind_method(D_METHOD("remove_tab", "tab_idx"), &TabBar::remove_tab);
ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &TabBar::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>()));
+ ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabBar::get_tab_idx_at_point);
ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabBar::set_tab_alignment);
ClassDB::bind_method(D_METHOD("get_tab_alignment"), &TabBar::get_tab_alignment);
ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &TabBar::set_clip_tabs);
@@ -1477,6 +1501,8 @@ void TabBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_tab", "from", "to"), &TabBar::move_tab);
ClassDB::bind_method(D_METHOD("set_tab_close_display_policy", "policy"), &TabBar::set_tab_close_display_policy);
ClassDB::bind_method(D_METHOD("get_tab_close_display_policy"), &TabBar::get_tab_close_display_policy);
+ ClassDB::bind_method(D_METHOD("set_max_tab_width", "width"), &TabBar::set_max_tab_width);
+ ClassDB::bind_method(D_METHOD("get_max_tab_width"), &TabBar::get_max_tab_width);
ClassDB::bind_method(D_METHOD("set_scrolling_enabled", "enabled"), &TabBar::set_scrolling_enabled);
ClassDB::bind_method(D_METHOD("get_scrolling_enabled"), &TabBar::get_scrolling_enabled);
ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &TabBar::set_drag_to_rearrange_enabled);
@@ -1501,8 +1527,10 @@ void TabBar::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_tab_width", PROPERTY_HINT_RANGE, "0,99999,1"), "set_max_tab_width", "get_max_tab_width");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_rearrange_group"), "set_tabs_rearrange_group", "get_tabs_rearrange_group");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_to_selected"), "set_scroll_to_selected", "get_scroll_to_selected");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_with_rmb"), "set_select_with_rmb", "get_select_with_rmb");
diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h
index b428538570..0f2184aca7 100644
--- a/scene/gui/tab_bar.h
+++ b/scene/gui/tab_bar.h
@@ -98,7 +98,7 @@ private:
CloseButtonDisplayPolicy cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER;
int hover = -1; // Hovered tab.
- int min_width = 0;
+ int max_width = 0;
bool scrolling_enabled = true;
bool drag_to_rearrange_enabled = false;
bool scroll_to_selected = true;
@@ -126,7 +126,6 @@ protected:
Variant get_drag_data(const Point2 &p_point) override;
bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;
void drop_data(const Point2 &p_point, const Variant &p_data) override;
- int get_tab_idx_at_point(const Point2 &p_point) const;
public:
void add_tab(const String &p_str = "", const Ref<Texture2D> &p_icon = Ref<Texture2D>());
@@ -156,13 +155,15 @@ public:
void set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon);
Ref<Texture2D> get_tab_button_icon(int p_tab) const;
+ int get_tab_idx_at_point(const Point2 &p_point) const;
+
void set_tab_alignment(AlignmentMode p_alignment);
AlignmentMode get_tab_alignment() const;
void set_clip_tabs(bool p_clip_tabs);
bool get_clip_tabs() const;
- void move_tab(int from, int to);
+ void move_tab(int p_from, int p_to);
void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy);
CloseButtonDisplayPolicy get_tab_close_display_policy() const;
@@ -197,7 +198,9 @@ public:
bool get_select_with_rmb() const;
void ensure_tab_visible(int p_idx);
- void set_min_width(int p_width);
+
+ void set_max_tab_width(int p_width);
+ int get_max_tab_width() const;
Rect2 get_tab_rect(int p_tab) const;
Size2 get_minimum_size() const override;
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 31a5e41086..ee61c862b7 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -30,44 +30,17 @@
#include "tab_container.h"
-#include "core/object/message_queue.h"
-#include "core/string/translation.h"
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
#include "scene/gui/texture_rect.h"
int TabContainer::_get_top_margin() const {
- if (!tabs_visible) {
- return 0;
+ int height = 0;
+ if (tabs_visible && get_tab_count() > 0) {
+ height = tab_bar->get_minimum_size().height;
}
- // Respect the minimum tab height.
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
-
- int tab_height = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height);
-
- // Font height or higher icon wins.
- int content_height = 0;
-
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- content_height = MAX(content_height, text_buf[i]->get_size().y);
-
- Control *c = tabs[i];
- if (!c->has_meta("_tab_icon")) {
- continue;
- }
-
- Ref<Texture2D> tex = c->get_meta("_tab_icon");
- if (!tex.is_valid()) {
- continue;
- }
- content_height = MAX(content_height, tex->get_size().height);
- }
-
- return tab_height + content_height;
+ return height;
}
void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
@@ -113,77 +86,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
return;
}
}
-
- // Do not activate tabs when tabs is empty.
- if (get_tab_count() == 0) {
- return;
- }
-
- Vector<Control *> tabs = _get_tabs();
-
- // Handle navigation buttons.
- if (buttons_visible_cache) {
- int popup_ofs = 0;
- if (popup) {
- popup_ofs = menu->get_width();
- }
-
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
- if (is_layout_rtl()) {
- if (pos.x < popup_ofs + decrement->get_width()) {
- if (last_tab_cache < tabs.size() - 1) {
- first_tab_cache += 1;
- update();
- }
- return;
- } else if (pos.x < popup_ofs + increment->get_width() + decrement->get_width()) {
- if (first_tab_cache > 0) {
- first_tab_cache -= 1;
- update();
- }
- return;
- }
- } else {
- if (pos.x > size.width - increment->get_width() - popup_ofs && pos.x) {
- if (last_tab_cache < tabs.size() - 1) {
- first_tab_cache += 1;
- update();
- }
- return;
- } else if (pos.x > size.width - increment->get_width() - decrement->get_width() - popup_ofs) {
- if (first_tab_cache > 0) {
- first_tab_cache -= 1;
- update();
- }
- return;
- }
- }
- }
-
- // Activate the clicked tab.
- if (is_layout_rtl()) {
- pos.x = size.width - pos.x;
- }
-
- if (pos.x < tabs_ofs_cache) {
- return;
- }
-
- pos.x -= tabs_ofs_cache;
- for (int i = first_tab_cache; i <= last_tab_cache; i++) {
- if (get_tab_hidden(i)) {
- continue;
- }
- int tab_width = _get_tab_width(i);
- if (pos.x < tab_width) {
- if (!get_tab_disabled(i)) {
- set_current_tab(i);
- }
- break;
- }
- pos.x -= tab_width;
- }
}
Ref<InputEventMouseMotion> mm = p_event;
@@ -194,9 +96,8 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
// Mouse must be on tabs in the tab header area.
if (pos.y > _get_top_margin()) {
- if (menu_hovered || highlight_arrow > -1) {
+ if (menu_hovered) {
menu_hovered = false;
- highlight_arrow = -1;
update();
}
return;
@@ -208,7 +109,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
if (pos.x <= menu->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
- highlight_arrow = -1;
update();
return;
}
@@ -220,7 +120,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
if (pos.x >= size.width - menu->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
- highlight_arrow = -1;
update();
return;
}
@@ -234,102 +133,26 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
return;
}
}
-
- // Do not activate tabs when tabs is empty.
- if ((get_tab_count() == 0 || !buttons_visible_cache) && menu_hovered) {
- highlight_arrow = -1;
- update();
- return;
- }
-
- int popup_ofs = 0;
- if (popup) {
- popup_ofs = menu->get_width();
- }
-
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
-
- if (is_layout_rtl()) {
- if (pos.x <= popup_ofs + decrement->get_width()) {
- if (highlight_arrow != 1) {
- highlight_arrow = 1;
- update();
- }
- } else if (pos.x <= popup_ofs + increment->get_width() + decrement->get_width()) {
- if (highlight_arrow != 0) {
- highlight_arrow = 0;
- update();
- }
- } else if (highlight_arrow > -1) {
- highlight_arrow = -1;
- update();
- }
- } else {
- if (pos.x >= size.width - increment->get_width() - popup_ofs) {
- if (highlight_arrow != 1) {
- highlight_arrow = 1;
- update();
- }
- } else if (pos.x >= size.width - increment->get_width() - decrement->get_width() - popup_ofs) {
- if (highlight_arrow != 0) {
- highlight_arrow = 0;
- update();
- }
- } else if (highlight_arrow > -1) {
- highlight_arrow = -1;
- update();
- }
- }
}
}
void TabContainer::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_RESIZED: {
- Vector<Control *> tabs = _get_tabs();
- int side_margin = get_theme_constant(SNAME("side_margin"));
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
- int header_width = get_size().width - side_margin * 2;
-
- // Find the width of the header area.
- Popup *popup = get_popup();
- if (popup) {
- header_width -= menu->get_width();
- }
- if (buttons_visible_cache) {
- header_width -= increment->get_width() + decrement->get_width();
- }
- if (popup || buttons_visible_cache) {
- header_width += side_margin;
+ case NOTIFICATION_ENTER_TREE: {
+ // If some nodes happen to be renamed outside the tree, the tab names need to be updated manually.
+ if (get_tab_count() > 0) {
+ _refresh_tab_names();
}
+ } break;
- // Find the width of all tabs after first_tab_cache.
- int all_tabs_width = 0;
- for (int i = first_tab_cache; i < tabs.size(); i++) {
- int tab_width = _get_tab_width(i);
- all_tabs_width += tab_width;
- }
-
- // Check if tabs before first_tab_cache would fit into the header area.
- for (int i = first_tab_cache - 1; i >= 0; i--) {
- int tab_width = _get_tab_width(i);
-
- if (all_tabs_width + tab_width > header_width) {
- break;
- }
-
- all_tabs_width += tab_width;
- first_tab_cache--;
- }
+ case NOTIFICATION_READY:
+ case NOTIFICATION_RESIZED: {
+ _update_margins();
} break;
case NOTIFICATION_DRAW: {
RID canvas = get_canvas_item();
Size2 size = get_size();
- bool rtl = is_layout_rtl();
// Draw only the tab area if the header is hidden.
Ref<StyleBox> panel = get_theme_stylebox(SNAME("panel"));
@@ -338,481 +161,171 @@ void TabContainer::_notification(int p_what) {
return;
}
- Vector<Control *> tabs = _get_tabs();
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> increment_hl = get_theme_icon(SNAME("increment_highlight"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
- Ref<Texture2D> decrement_hl = get_theme_icon(SNAME("decrement_highlight"));
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
- Ref<Texture2D> menu_hl = get_theme_icon(SNAME("menu_highlight"));
- Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
- Color font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
- Color font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
- int side_margin = get_theme_constant(SNAME("side_margin"));
-
- // Find out start and width of the header area.
- int header_x = side_margin;
- int header_width = size.width - side_margin * 2;
int header_height = _get_top_margin();
- Popup *popup = get_popup();
- if (popup) {
- header_width -= menu->get_width();
- }
-
- // Check if all tabs would fit into the header area.
- int all_tabs_width = 0;
- for (int i = 0; i < tabs.size(); i++) {
- if (get_tab_hidden(i)) {
- continue;
- }
- int tab_width = _get_tab_width(i);
- all_tabs_width += tab_width;
-
- if (all_tabs_width > header_width) {
- // Not all tabs are visible at the same time - reserve space for navigation buttons.
- buttons_visible_cache = true;
- header_width -= decrement->get_width() + increment->get_width();
- break;
- } else {
- buttons_visible_cache = false;
- }
- }
- // With buttons, a right side margin does not need to be respected.
- if (popup || buttons_visible_cache) {
- header_width += side_margin;
- }
-
- if (!buttons_visible_cache) {
- first_tab_cache = 0;
- }
-
- // Go through the visible tabs to find the width they occupy.
- all_tabs_width = 0;
- Vector<int> tab_widths;
- for (int i = first_tab_cache; i < tabs.size(); i++) {
- if (get_tab_hidden(i)) {
- tab_widths.push_back(0);
- continue;
- }
- int tab_width = _get_tab_width(i);
- if (all_tabs_width + tab_width > header_width && tab_widths.size() > 0) {
- break;
- }
- all_tabs_width += tab_width;
- tab_widths.push_back(tab_width);
- }
-
- // Find the offset at which to draw tabs, according to the alignment.
- switch (alignment) {
- case ALIGNMENT_LEFT:
- tabs_ofs_cache = header_x;
- break;
- case ALIGNMENT_CENTER:
- tabs_ofs_cache = header_x + (header_width / 2) - (all_tabs_width / 2);
- break;
- case ALIGNMENT_RIGHT:
- tabs_ofs_cache = header_x + header_width - all_tabs_width;
- 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;
- int index = 0;
- for (int i = 0; i < tab_widths.size(); i++) {
- index = i + first_tab_cache;
- if (get_tab_hidden(index)) {
- continue;
- }
-
- int tab_width = tab_widths[i];
- if (index == current) {
- x_current = x;
- } else if (get_tab_disabled(index)) {
- if (rtl) {
- _draw_tab(tab_disabled, font_disabled_color, index, size.width - (tabs_ofs_cache + x) - tab_width);
- } else {
- _draw_tab(tab_disabled, font_disabled_color, index, tabs_ofs_cache + x);
- }
- } else {
- if (rtl) {
- _draw_tab(tab_unselected, font_unselected_color, index, size.width - (tabs_ofs_cache + x) - tab_width);
- } else {
- _draw_tab(tab_unselected, font_unselected_color, index, tabs_ofs_cache + x);
- }
- }
- x += tab_width;
- last_tab_cache = index;
- }
+ 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 the popup menu.
+ if (get_popup()) {
+ Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
+ Ref<Texture2D> menu_hl = get_theme_icon(SNAME("menu_highlight"));
- // 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) {
- Ref<StyleBox> current_style_box = get_tab_disabled(current) ? tab_disabled : tab_selected;
- if (rtl) {
- _draw_tab(current_style_box, font_selected_color, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]);
- } else {
- _draw_tab(current_style_box, font_selected_color, current, tabs_ofs_cache + x_current);
- }
- }
+ int x = is_layout_rtl() ? 0 : get_size().width - menu->get_width();
- // Draw the popup menu.
- if (rtl) {
- x = 0;
- } else {
- x = get_size().width;
- }
- if (popup) {
- if (!rtl) {
- x -= menu->get_width();
- }
if (menu_hovered) {
menu_hl->draw(get_canvas_item(), Size2(x, (header_height - menu_hl->get_height()) / 2));
} else {
menu->draw(get_canvas_item(), Size2(x, (header_height - menu->get_height()) / 2));
}
- if (rtl) {
- x += menu->get_width();
- }
- }
-
- // Draw the navigation buttons.
- if (buttons_visible_cache) {
- if (rtl) {
- if (last_tab_cache < tabs.size() - 1) {
- draw_texture(highlight_arrow == 1 ? decrement_hl : decrement, Point2(x, (header_height - increment->get_height()) / 2));
- } else {
- draw_texture(decrement, Point2(x, (header_height - increment->get_height()) / 2), Color(1, 1, 1, 0.5));
- }
- x += increment->get_width();
-
- if (first_tab_cache > 0) {
- draw_texture(highlight_arrow == 0 ? increment_hl : increment, Point2(x, (header_height - decrement->get_height()) / 2));
- } else {
- draw_texture(increment, Point2(x, (header_height - decrement->get_height()) / 2), Color(1, 1, 1, 0.5));
- }
- x += decrement->get_width();
- } else {
- x -= increment->get_width();
- if (last_tab_cache < tabs.size() - 1) {
- draw_texture(highlight_arrow == 1 ? increment_hl : increment, Point2(x, (header_height - increment->get_height()) / 2));
- } else {
- draw_texture(increment, Point2(x, (header_height - increment->get_height()) / 2), Color(1, 1, 1, 0.5));
- }
-
- x -= decrement->get_width();
- if (first_tab_cache > 0) {
- draw_texture(highlight_arrow == 0 ? decrement_hl : decrement, Point2(x, (header_height - decrement->get_height()) / 2));
- } else {
- draw_texture(decrement, Point2(x, (header_height - decrement->get_height()) / 2), Color(1, 1, 1, 0.5));
- }
- }
}
} break;
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- text_buf.write[i]->clear();
- }
- _theme_changing = true;
+ theme_changing = true;
call_deferred(SNAME("_on_theme_changed")); // Wait until all changed theme.
} break;
}
}
-void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x) {
- Control *control = get_tab_control(p_index);
- RID canvas = get_canvas_item();
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
- int icon_text_distance = get_theme_constant(SNAME("icon_separation"));
- int tab_width = _get_tab_width(p_index);
- int header_height = _get_top_margin();
-
- // Draw the tab background.
- Rect2 tab_rect(p_x, 0, tab_width, header_height);
- p_tab_style->draw(canvas, tab_rect);
-
- // Draw the tab contents.
- String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name()));
-
- int x_content = tab_rect.position.x + p_tab_style->get_margin(SIDE_LEFT);
- int top_margin = p_tab_style->get_margin(SIDE_TOP);
- int y_center = top_margin + (tab_rect.size.y - p_tab_style->get_minimum_size().y) / 2;
-
- // Draw the tab icon.
- if (control->has_meta("_tab_icon")) {
- Ref<Texture2D> icon = control->get_meta("_tab_icon");
- if (icon.is_valid()) {
- int y = y_center - (icon->get_height() / 2);
- icon->draw(canvas, Point2i(x_content, y));
- if (!text.is_empty()) {
- x_content += icon->get_width() + icon_text_distance;
- }
- }
- }
-
- // Draw the tab text.
- Point2i text_pos(x_content, y_center - text_buf[p_index]->get_size().y / 2);
- if (outline_size > 0 && font_outline_color.a > 0) {
- text_buf[p_index]->draw_outline(canvas, text_pos, outline_size, font_outline_color);
- }
- text_buf[p_index]->draw(canvas, text_pos, p_font_color);
-}
-
-void TabContainer::_refresh_texts() {
- text_buf.clear();
- Vector<Control *> tabs = _get_tabs();
- bool rtl = is_layout_rtl();
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
- for (int i = 0; i < tabs.size(); i++) {
- Control *control = Object::cast_to<Control>(tabs[i]);
- String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name()));
-
- Ref<TextLine> name;
- name.instantiate();
- name->set_direction(rtl ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
- name->add_string(text, font, font_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- text_buf.push_back(name);
- }
-}
-
void TabContainer::_on_theme_changed() {
- if (!_theme_changing) {
+ if (!theme_changing) {
return;
}
- _refresh_texts();
-
- update_minimum_size();
+ tab_bar->add_theme_style_override(SNAME("tab_unselected"), get_theme_stylebox(SNAME("tab_unselected")));
+ tab_bar->add_theme_style_override(SNAME("tab_selected"), get_theme_stylebox(SNAME("tab_selected")));
+ tab_bar->add_theme_style_override(SNAME("tab_disabled"), get_theme_stylebox(SNAME("tab_disabled")));
+ tab_bar->add_theme_icon_override(SNAME("increment"), get_theme_icon(SNAME("increment")));
+ tab_bar->add_theme_icon_override(SNAME("increment_highlight"), get_theme_icon(SNAME("increment_highlight")));
+ tab_bar->add_theme_icon_override(SNAME("decrement"), get_theme_icon(SNAME("decrement")));
+ tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), get_theme_icon(SNAME("decrement_highlight")));
+ tab_bar->add_theme_color_override(SNAME("font_selected_color"), get_theme_color(SNAME("font_selected_color")));
+ tab_bar->add_theme_color_override(SNAME("font_unselected_color"), get_theme_color(SNAME("font_unselected_color")));
+ tab_bar->add_theme_color_override(SNAME("font_disabled_color"), get_theme_color(SNAME("font_disabled_color")));
+ tab_bar->add_theme_color_override(SNAME("font_outline_color"), get_theme_color(SNAME("font_outline_color")));
+ tab_bar->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("font")));
+ tab_bar->add_theme_constant_override(SNAME("font_size"), get_theme_constant(SNAME("font_size")));
+ tab_bar->add_theme_constant_override(SNAME("icon_separation"), get_theme_constant(SNAME("icon_separation")));
+ tab_bar->add_theme_constant_override(SNAME("outline_size"), get_theme_constant(SNAME("outline_size")));
+
+ _update_margins();
if (get_tab_count() > 0) {
_repaint();
- update();
+ } else {
+ update_minimum_size();
}
- _theme_changing = false;
+ update();
+
+ theme_changing = false;
}
void TabContainer::_repaint() {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"));
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- Control *c = tabs[i];
+ Vector<Control *> controls = _get_tab_controls();
+ int current = get_current_tab();
+
+ for (int i = 0; i < controls.size(); i++) {
+ Control *c = controls[i];
+
if (i == current) {
c->show();
c->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+
if (tabs_visible) {
c->set_offset(SIDE_TOP, _get_top_margin());
}
+
c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + sb->get_margin(SIDE_TOP));
c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + sb->get_margin(SIDE_LEFT));
c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - sb->get_margin(SIDE_RIGHT));
c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - sb->get_margin(SIDE_BOTTOM));
-
} else {
c->hide();
}
}
-}
-
-void TabContainer::_on_mouse_exited() {
- if (menu_hovered || highlight_arrow > -1) {
- menu_hovered = false;
- highlight_arrow = -1;
- update();
- }
-}
-
-int TabContainer::_get_tab_width(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0);
- Control *control = get_tab_control(p_index);
- if (!control || get_tab_hidden(p_index)) {
- return 0;
- }
-
- // Get the width of the text displayed on the tab.
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
- String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name()));
- int width = font->get_string_size(text, font_size).width;
-
- // Add space for a tab icon.
- if (control->has_meta("_tab_icon")) {
- Ref<Texture2D> icon = control->get_meta("_tab_icon");
- if (icon.is_valid()) {
- width += icon->get_width();
- if (!text.is_empty()) {
- width += get_theme_constant(SNAME("icon_separation"));
- }
- }
- }
- // Respect a minimum size.
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- if (get_tab_disabled(p_index)) {
- width += tab_disabled->get_minimum_size().width;
- } else if (p_index == current) {
- width += tab_selected->get_minimum_size().width;
- } else {
- width += tab_unselected->get_minimum_size().width;
- }
-
- return width;
+ update_minimum_size();
}
-Vector<Control *> TabContainer::_get_tabs() const {
- Vector<Control *> controls;
- for (int i = 0; i < get_child_count(); i++) {
- Control *control = Object::cast_to<Control>(get_child(i));
- if (!control || control->is_set_as_top_level()) {
- continue;
- }
-
- controls.push_back(control);
- }
- return controls;
-}
+void TabContainer::_update_margins() {
+ int menu_width = get_theme_icon(SNAME("menu"))->get_width();
+ int side_margin = get_theme_constant(SNAME("side_margin"));
-void TabContainer::_child_renamed_callback() {
- _refresh_texts();
- update();
-}
+ // Directly check for validity, to avoid errors when quitting.
+ bool has_popup = popup_obj_id.is_valid();
-void TabContainer::add_child_notify(Node *p_child) {
- Container::add_child_notify(p_child);
+ if (get_tab_count() == 0) {
+ tab_bar->set_offset(SIDE_LEFT, 0);
+ tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
- Control *c = Object::cast_to<Control>(p_child);
- if (!c || c->is_set_as_top_level()) {
return;
}
- _refresh_texts();
- call_deferred(SNAME("_repaint"));
- update();
-
- bool first = (_get_tabs().size() == 1);
- if (first) {
- current = 0;
- previous = 0;
- }
-
- p_child->connect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback));
- if (first && is_inside_tree()) {
- emit_signal(SNAME("tab_changed"), current);
- }
-}
-
-void TabContainer::move_child_notify(Node *p_child) {
- Container::move_child_notify(p_child);
-
- Control *c = Object::cast_to<Control>(p_child);
- if (!c || c->is_set_as_top_level()) {
- return;
- }
+ switch (get_tab_alignment()) {
+ case TabBar::ALIGNMENT_LEFT: {
+ tab_bar->set_offset(SIDE_LEFT, side_margin);
+ tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
+ } break;
- _update_current_tab();
- update();
-}
+ case TabBar::ALIGNMENT_CENTER: {
+ tab_bar->set_offset(SIDE_LEFT, 0);
+ tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
+ } break;
-int TabContainer::get_tab_count() const {
- return _get_tabs().size();
-}
+ case TabBar::ALIGNMENT_RIGHT: {
+ tab_bar->set_offset(SIDE_LEFT, 0);
-void TabContainer::set_current_tab(int p_current) {
- ERR_FAIL_INDEX(p_current, get_tab_count());
+ if (has_popup) {
+ tab_bar->set_offset(SIDE_RIGHT, -menu_width);
+ return;
+ }
- int pending_previous = current;
- current = p_current;
+ int first_tab_pos = tab_bar->get_tab_rect(0).position.x;
+ Rect2 last_tab_rect = tab_bar->get_tab_rect(get_tab_count() - 1);
+ int total_tabs_width = last_tab_rect.position.x - first_tab_pos + last_tab_rect.size.width;
- _repaint();
+ // Calculate if all the tabs would still fit if the margin was present.
+ if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + side_margin) > get_size().width))) {
+ tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
+ } else {
+ tab_bar->set_offset(SIDE_RIGHT, -side_margin);
+ }
+ } break;
- if (pending_previous == current) {
- emit_signal(SNAME("tab_selected"), current);
- } else {
- previous = pending_previous;
- emit_signal(SNAME("tab_selected"), current);
- emit_signal(SNAME("tab_changed"), current);
+ case TabBar::ALIGNMENT_MAX:
+ break; // Can't happen, but silences warning.
}
-
- update();
}
-int TabContainer::get_current_tab() const {
- return current;
-}
-
-int TabContainer::get_previous_tab() const {
- return previous;
-}
-
-Control *TabContainer::get_tab_control(int p_idx) const {
- Vector<Control *> tabs = _get_tabs();
- if (p_idx >= 0 && p_idx < tabs.size()) {
- return tabs[p_idx];
- } else {
- return nullptr;
+void TabContainer::_on_mouse_exited() {
+ if (menu_hovered) {
+ menu_hovered = false;
+ update();
}
}
-Control *TabContainer::get_current_tab_control() const {
- return get_tab_control(current);
-}
-
-void TabContainer::remove_child_notify(Node *p_child) {
- Container::remove_child_notify(p_child);
+Vector<Control *> TabContainer::_get_tab_controls() const {
+ Vector<Control *> controls;
+ for (int i = 0; i < get_child_count(); i++) {
+ Control *control = Object::cast_to<Control>(get_child(i));
+ if (!control || control->is_set_as_top_level() || control == tab_bar) {
+ continue;
+ }
- Control *c = Object::cast_to<Control>(p_child);
- if (!c || c->is_set_as_top_level()) {
- return;
+ controls.push_back(control);
}
- // Defer the call because tab is not yet removed (remove_child_notify is called right before p_child is actually removed).
- call_deferred(SNAME("_update_current_tab"));
-
- p_child->disconnect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback));
-
- update();
-}
-
-void TabContainer::_update_current_tab() {
- _refresh_texts();
-
- int tc = get_tab_count();
- if (current >= tc) {
- current = tc - 1;
- }
- if (current < 0) {
- current = 0;
- } else {
- set_current_tab(current);
- }
+ return controls;
}
-Variant TabContainer::get_drag_data(const Point2 &p_point) {
+Variant TabContainer::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) {
if (!drag_to_rearrange_enabled) {
return Variant();
}
int tab_over = get_tab_idx_at_point(p_point);
-
if (tab_over < 0) {
return Variant();
}
@@ -825,18 +338,20 @@ Variant TabContainer::get_drag_data(const Point2 &p_point) {
tf->set_texture(icon);
drag_preview->add_child(tf);
}
+
Label *label = memnew(Label(get_tab_title(tab_over)));
- drag_preview->add_child(label);
set_drag_preview(drag_preview);
+ drag_preview->add_child(label);
Dictionary drag_data;
drag_data["type"] = "tabc_element";
drag_data["tabc_element"] = tab_over;
drag_data["from_path"] = get_path();
+
return drag_data;
}
-bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
+bool TabContainer::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const {
if (!drag_to_rearrange_enabled) {
return false;
}
@@ -852,7 +367,7 @@ bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) c
if (from_path == to_path) {
return true;
} else if (get_tabs_rearrange_group() != -1) {
- // drag and drop between other TabContainers
+ // Drag and drop between other TabContainers.
Node *from_node = get_node(from_path);
TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node);
if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
@@ -860,10 +375,11 @@ bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) c
}
}
}
+
return false;
}
-void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) {
+void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) {
if (!drag_to_rearrange_enabled) {
return;
}
@@ -883,85 +399,195 @@ void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) {
if (hover_now < 0) {
hover_now = get_tab_count() - 1;
}
- move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index());
- set_current_tab(hover_now);
+
+ move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index(false));
+ if (!is_tab_disabled(hover_now)) {
+ set_current_tab(hover_now);
+ }
+
} else if (get_tabs_rearrange_group() != -1) {
- // drag and drop between TabContainers
+ // Drag and drop between TabContainers.
Node *from_node = get_node(from_path);
TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node);
if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
Control *moving_tabc = from_tabc->get_tab_control(tab_from_id);
from_tabc->remove_child(moving_tabc);
- add_child(moving_tabc, false, INTERNAL_MODE_FRONT);
+ add_child(moving_tabc, true);
+
if (hover_now < 0) {
hover_now = get_tab_count() - 1;
}
- move_child(moving_tabc, get_tab_control(hover_now)->get_index());
- set_current_tab(hover_now);
- emit_signal(SNAME("tab_changed"), hover_now);
+
+ move_child(moving_tabc, get_tab_control(hover_now)->get_index(false));
+ if (!is_tab_disabled(hover_now)) {
+ set_current_tab(hover_now);
+ }
}
}
}
- update();
}
-int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const {
- if (get_tab_count() == 0) {
- return -1;
+void TabContainer::_on_tab_changed(int p_tab) {
+ call_deferred(SNAME("_repaint"));
+
+ emit_signal(SNAME("tab_changed"), p_tab);
+}
+
+void TabContainer::_on_tab_selected(int p_tab) {
+ if (p_tab != get_previous_tab()) {
+ call_deferred(SNAME("_repaint"));
+ }
+
+ emit_signal(SNAME("tab_selected"), p_tab);
+}
+
+void TabContainer::_refresh_tab_names() {
+ Vector<Control *> controls = _get_tab_controls();
+ for (int i = 0; i < controls.size(); i++) {
+ if (!controls[i]->has_meta("_tab_name") && String(controls[i]->get_name()) != get_tab_title(i)) {
+ tab_bar->set_tab_title(i, controls[i]->get_name());
+ }
}
+}
- // must be on tabs in the tab header area.
- if (p_point.y > _get_top_margin()) {
- return -1;
+void TabContainer::add_child_notify(Node *p_child) {
+ if (p_child == tab_bar) {
+ return;
+ }
+
+ Container::add_child_notify(p_child);
+
+ Control *c = Object::cast_to<Control>(p_child);
+ if (!c || c->is_set_as_top_level()) {
+ return;
}
+ c->hide();
- Size2 size = get_size();
- int button_ofs = 0;
- int px = p_point.x;
+ tab_bar->add_tab(p_child->get_name());
- if (is_layout_rtl()) {
- px = size.width - px;
+ _update_margins();
+
+ p_child->connect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names));
+
+ // TabBar won't emit the "tab_changed" signal when not inside the tree.
+ if (!is_inside_tree()) {
+ call_deferred("_repaint");
}
+}
- if (px < tabs_ofs_cache) {
- return -1;
+void TabContainer::move_child_notify(Node *p_child) {
+ if (p_child == tab_bar) {
+ return;
}
- Popup *popup = get_popup();
- if (popup) {
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
- button_ofs += menu->get_width();
+ Container::move_child_notify(p_child);
+
+ Control *c = Object::cast_to<Control>(p_child);
+ if (c && !c->is_set_as_top_level()) {
+ int old_idx = -1;
+ String tab_name = c->has_meta("_tab_name") ? String(c->get_meta("_tab_name")) : String(c->get_name());
+
+ // Find the previous tab index of the control.
+ for (int i = 0; i < get_tab_count(); i++) {
+ if (get_tab_title(i) == tab_name) {
+ old_idx = i;
+ break;
+ }
+ }
+
+ tab_bar->move_tab(old_idx, get_tab_idx_from_control(c));
}
- if (buttons_visible_cache) {
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
- button_ofs += increment->get_width() + decrement->get_width();
+}
+
+void TabContainer::remove_child_notify(Node *p_child) {
+ if (p_child == tab_bar) {
+ return;
}
- if (px > size.width - button_ofs) {
- return -1;
+
+ Container::remove_child_notify(p_child);
+
+ Control *c = Object::cast_to<Control>(p_child);
+ if (!c || c->is_set_as_top_level()) {
+ return;
}
- // get the tab at the point
- Vector<Control *> tabs = _get_tabs();
- px -= tabs_ofs_cache;
- for (int i = first_tab_cache; i <= last_tab_cache; i++) {
- int tab_width = _get_tab_width(i);
- if (px < tab_width) {
+ tab_bar->remove_tab(get_tab_idx_from_control(c));
+
+ _update_margins();
+
+ if (p_child->has_meta("_tab_name")) {
+ p_child->remove_meta("_tab_name");
+ }
+ p_child->disconnect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names));
+
+ // TabBar won't emit the "tab_changed" signal when not inside the tree.
+ if (!is_inside_tree()) {
+ call_deferred("_repaint");
+ }
+}
+
+int TabContainer::get_tab_count() const {
+ return tab_bar->get_tab_count();
+}
+
+void TabContainer::set_current_tab(int p_current) {
+ tab_bar->set_current_tab(p_current);
+}
+
+int TabContainer::get_current_tab() const {
+ return tab_bar->get_current_tab();
+}
+
+int TabContainer::get_previous_tab() const {
+ return tab_bar->get_previous_tab();
+}
+
+Control *TabContainer::get_tab_control(int p_idx) const {
+ Vector<Control *> controls = _get_tab_controls();
+ if (p_idx >= 0 && p_idx < controls.size()) {
+ return controls[p_idx];
+ } else {
+ return nullptr;
+ }
+}
+
+Control *TabContainer::get_current_tab_control() const {
+ return get_tab_control(tab_bar->get_current_tab());
+}
+
+int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const {
+ return tab_bar->get_tab_idx_at_point(p_point);
+}
+
+int TabContainer::get_tab_idx_from_control(Control *p_child) const {
+ ERR_FAIL_NULL_V(p_child, -1);
+ ERR_FAIL_COND_V(p_child->get_parent() != this, -1);
+
+ Vector<Control *> controls = _get_tab_controls();
+ for (int i = 0; i < controls.size(); i++) {
+ if (controls[i] == p_child) {
return i;
}
- px -= tab_width;
}
+
return -1;
}
-void TabContainer::set_tab_alignment(AlignmentMode p_alignment) {
- ERR_FAIL_INDEX(p_alignment, 3);
- alignment = p_alignment;
- update();
+void TabContainer::set_tab_alignment(TabBar::AlignmentMode p_alignment) {
+ tab_bar->set_tab_alignment(p_alignment);
+ _update_margins();
}
-TabContainer::AlignmentMode TabContainer::get_tab_alignment() const {
- return alignment;
+TabBar::AlignmentMode TabContainer::get_tab_alignment() const {
+ return tab_bar->get_tab_alignment();
+}
+
+void TabContainer::set_clip_tabs(bool p_clip_tabs) {
+ tab_bar->set_clip_tabs(p_clip_tabs);
+}
+
+bool TabContainer::get_clip_tabs() const {
+ return tab_bar->get_clip_tabs();
}
void TabContainer::set_tabs_visible(bool p_visible) {
@@ -970,11 +596,12 @@ void TabContainer::set_tabs_visible(bool p_visible) {
}
tabs_visible = p_visible;
+ tab_bar->set_visible(tabs_visible);
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- Control *c = tabs[i];
- if (p_visible) {
+ Vector<Control *> controls = _get_tab_controls();
+ for (int i = 0; i < controls.size(); i++) {
+ Control *c = controls[i];
+ if (tabs_visible) {
c->set_offset(SIDE_TOP, _get_top_margin());
} else {
c->set_offset(SIDE_TOP, 0);
@@ -996,7 +623,8 @@ void TabContainer::set_all_tabs_in_front(bool p_in_front) {
all_tabs_in_front = p_in_front;
- update();
+ remove_child(tab_bar);
+ add_child(tab_bar, false, all_tabs_in_front ? INTERNAL_MODE_FRONT : INTERNAL_MODE_BACK);
}
bool TabContainer::is_all_tabs_in_front() const {
@@ -1006,95 +634,78 @@ bool TabContainer::is_all_tabs_in_front() const {
void TabContainer::set_tab_title(int p_tab, const String &p_title) {
Control *child = get_tab_control(p_tab);
ERR_FAIL_COND(!child);
- child->set_meta("_tab_name", p_title);
- _refresh_texts();
- update();
-}
-String TabContainer::get_tab_title(int p_tab) const {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND_V(!child, "");
- if (child->has_meta("_tab_name")) {
- return child->get_meta("_tab_name");
+ tab_bar->set_tab_title(p_tab, p_title);
+
+ if (p_title == child->get_name()) {
+ if (child->has_meta("_tab_name")) {
+ child->remove_meta("_tab_name");
+ }
} else {
- return child->get_name();
+ child->set_meta("_tab_name", p_title);
+ }
+
+ _update_margins();
+ if (!get_clip_tabs()) {
+ update_minimum_size();
}
}
+String TabContainer::get_tab_title(int p_tab) const {
+ return tab_bar->get_tab_title(p_tab);
+}
+
void TabContainer::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND(!child);
- child->set_meta("_tab_icon", p_icon);
- update();
+ tab_bar->set_tab_icon(p_tab, p_icon);
+
+ _update_margins();
+ _repaint();
}
Ref<Texture2D> TabContainer::get_tab_icon(int p_tab) const {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND_V(!child, Ref<Texture2D>());
- if (child->has_meta("_tab_icon")) {
- return child->get_meta("_tab_icon");
- } else {
- return Ref<Texture2D>();
- }
+ return tab_bar->get_tab_icon(p_tab);
}
void TabContainer::set_tab_disabled(int p_tab, bool p_disabled) {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND(!child);
- child->set_meta("_tab_disabled", p_disabled);
- update();
-}
+ tab_bar->set_tab_disabled(p_tab, p_disabled);
-bool TabContainer::get_tab_disabled(int p_tab) const {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND_V(!child, false);
- if (child->has_meta("_tab_disabled")) {
- return child->get_meta("_tab_disabled");
- } else {
- return false;
+ _update_margins();
+ if (!get_clip_tabs()) {
+ update_minimum_size();
}
}
+bool TabContainer::is_tab_disabled(int p_tab) const {
+ return tab_bar->is_tab_disabled(p_tab);
+}
+
void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) {
Control *child = get_tab_control(p_tab);
ERR_FAIL_COND(!child);
- child->set_meta("_tab_hidden", p_hidden);
- update();
- for (int i = 0; i < get_tab_count(); i++) {
- int try_tab = (p_tab + 1 + i) % get_tab_count();
- if (get_tab_disabled(try_tab) || get_tab_hidden(try_tab)) {
- continue;
- }
- set_current_tab(try_tab);
- return;
- }
-
- //assumed no other tab can be switched to, just hide
+ tab_bar->set_tab_hidden(p_tab, p_hidden);
child->hide();
-}
-bool TabContainer::get_tab_hidden(int p_tab) const {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND_V(!child, false);
- if (child->has_meta("_tab_hidden")) {
- return child->get_meta("_tab_hidden");
- } else {
- return false;
+ _update_margins();
+ if (!get_clip_tabs()) {
+ update_minimum_size();
}
}
+bool TabContainer::is_tab_hidden(int p_tab) const {
+ return tab_bar->is_tab_hidden(p_tab);
+}
+
void TabContainer::get_translatable_strings(List<String> *p_strings) const {
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- Control *c = tabs[i];
+ Vector<Control *> controls = _get_tab_controls();
+ for (int i = 0; i < controls.size(); i++) {
+ Control *c = controls[i];
if (!c->has_meta("_tab_name")) {
continue;
}
String name = c->get_meta("_tab_name");
-
if (!name.is_empty()) {
p_strings->push_back(name);
}
@@ -1104,9 +715,26 @@ void TabContainer::get_translatable_strings(List<String> *p_strings) const {
Size2 TabContainer::get_minimum_size() const {
Size2 ms;
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- Control *c = tabs[i];
+ if (tabs_visible) {
+ ms = tab_bar->get_minimum_size();
+
+ if (!get_clip_tabs()) {
+ if (get_popup()) {
+ ms.x += get_theme_icon(SNAME("menu"))->get_width();
+ }
+
+ int side_margin = get_theme_constant(SNAME("side_margin"));
+ if (side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER &&
+ (get_tab_alignment() != TabBar::ALIGNMENT_RIGHT || !get_popup())) {
+ ms.x += side_margin;
+ }
+ }
+ }
+
+ Vector<Control *> controls = _get_tab_controls();
+ int max_control_height = 0;
+ for (int i = 0; i < controls.size(); i++) {
+ Control *c = controls[i];
if (!c->is_visible_in_tree() && !use_hidden_tabs_for_min_size) {
continue;
@@ -1114,29 +742,30 @@ Size2 TabContainer::get_minimum_size() const {
Size2 cms = c->get_combined_minimum_size();
ms.x = MAX(ms.x, cms.x);
- ms.y = MAX(ms.y, cms.y);
+ max_control_height = MAX(max_control_height, cms.y);
}
+ ms.y += max_control_height;
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
-
- if (tabs_visible) {
- ms.y += MAX(MAX(tab_unselected->get_minimum_size().y, tab_selected->get_minimum_size().y), tab_disabled->get_minimum_size().y);
- ms.y += _get_top_margin();
- }
-
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"));
- ms += sb->get_minimum_size();
+ Size2 panel_ms = get_theme_stylebox(SNAME("panel"))->get_minimum_size();
+ ms.x = MAX(ms.x, panel_ms.x);
+ ms.y += panel_ms.y;
return ms;
}
void TabContainer::set_popup(Node *p_popup) {
- ERR_FAIL_NULL(p_popup);
+ bool had_popup = get_popup();
+
Popup *popup = Object::cast_to<Popup>(p_popup);
popup_obj_id = popup ? popup->get_instance_id() : ObjectID();
- update();
+
+ if (had_popup != bool(popup)) {
+ update();
+ _update_margins();
+ if (!get_clip_tabs()) {
+ update_minimum_size();
+ }
+ }
}
Popup *TabContainer::get_popup() const {
@@ -1151,6 +780,7 @@ Popup *TabContainer::get_popup() const {
popup_obj_id = ObjectID();
}
}
+
return nullptr;
}
@@ -1163,15 +793,16 @@ bool TabContainer::get_drag_to_rearrange_enabled() const {
}
void TabContainer::set_tabs_rearrange_group(int p_group_id) {
- tabs_rearrange_group = p_group_id;
+ tab_bar->set_tabs_rearrange_group(p_group_id);
}
int TabContainer::get_tabs_rearrange_group() const {
- return tabs_rearrange_group;
+ return tab_bar->get_tabs_rearrange_group();
}
void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) {
use_hidden_tabs_for_min_size = p_use_hidden_tabs;
+ update_minimum_size();
}
bool TabContainer::get_use_hidden_tabs_for_min_size() const {
@@ -1195,6 +826,8 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tab_control", "tab_idx"), &TabContainer::get_tab_control);
ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabContainer::set_tab_alignment);
ClassDB::bind_method(D_METHOD("get_tab_alignment"), &TabContainer::get_tab_alignment);
+ ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &TabContainer::set_clip_tabs);
+ ClassDB::bind_method(D_METHOD("get_clip_tabs"), &TabContainer::get_clip_tabs);
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);
@@ -1204,23 +837,25 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabContainer::set_tab_icon);
ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabContainer::get_tab_icon);
ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabContainer::set_tab_disabled);
- ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &TabContainer::get_tab_disabled);
+ ClassDB::bind_method(D_METHOD("is_tab_disabled", "tab_idx"), &TabContainer::is_tab_disabled);
ClassDB::bind_method(D_METHOD("set_tab_hidden", "tab_idx", "hidden"), &TabContainer::set_tab_hidden);
- ClassDB::bind_method(D_METHOD("get_tab_hidden", "tab_idx"), &TabContainer::get_tab_hidden);
+ ClassDB::bind_method(D_METHOD("is_tab_hidden", "tab_idx"), &TabContainer::is_tab_hidden);
ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabContainer::get_tab_idx_at_point);
+ ClassDB::bind_method(D_METHOD("get_tab_idx_from_control", "control"), &TabContainer::get_tab_idx_from_control);
ClassDB::bind_method(D_METHOD("set_popup", "popup"), &TabContainer::set_popup);
ClassDB::bind_method(D_METHOD("get_popup"), &TabContainer::get_popup);
ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &TabContainer::set_drag_to_rearrange_enabled);
ClassDB::bind_method(D_METHOD("get_drag_to_rearrange_enabled"), &TabContainer::get_drag_to_rearrange_enabled);
ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabContainer::set_tabs_rearrange_group);
ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabContainer::get_tabs_rearrange_group);
-
ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size);
ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size);
ClassDB::bind_method(D_METHOD("_repaint"), &TabContainer::_repaint);
ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);
- ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &TabContainer::_get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TabContainer::_can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TabContainer::_drop_data_fw);
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab")));
@@ -1228,16 +863,21 @@ void TabContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment");
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, "clip_tabs"), "set_clip_tabs", "get_clip_tabs");
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::INT, "tabs_rearrange_group"), "set_tabs_rearrange_group", "get_tabs_rearrange_group");
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");
-
- BIND_ENUM_CONSTANT(ALIGNMENT_LEFT);
- BIND_ENUM_CONSTANT(ALIGNMENT_CENTER);
- BIND_ENUM_CONSTANT(ALIGNMENT_RIGHT);
}
TabContainer::TabContainer() {
+ tab_bar = memnew(TabBar);
+ tab_bar->set_drag_forwarding(this);
+ add_child(tab_bar, false, INTERNAL_MODE_FRONT);
+ tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
+ tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed));
+ tab_bar->connect("tab_selected", callable_mp(this, &TabContainer::_on_tab_selected));
+
connect("mouse_exited", callable_mp(this, &TabContainer::_on_mouse_exited));
}
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index ee1b3fea51..c54934b37b 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -33,65 +33,51 @@
#include "scene/gui/container.h"
#include "scene/gui/popup.h"
-#include "scene/resources/text_line.h"
+#include "scene/gui/tab_bar.h"
class TabContainer : public Container {
GDCLASS(TabContainer, Container);
-public:
- enum AlignmentMode {
- ALIGNMENT_LEFT,
- ALIGNMENT_CENTER,
- ALIGNMENT_RIGHT,
- };
-
-private:
- int first_tab_cache = 0;
- int tabs_ofs_cache = 0;
- int last_tab_cache = 0;
- int current = 0;
- int previous = 0;
+ TabBar *tab_bar;
bool tabs_visible = true;
bool all_tabs_in_front = false;
- bool buttons_visible_cache = false;
bool menu_hovered = false;
- int highlight_arrow = -1;
- AlignmentMode alignment = ALIGNMENT_CENTER;
- int _get_top_margin() const;
mutable ObjectID popup_obj_id;
bool drag_to_rearrange_enabled = false;
bool use_hidden_tabs_for_min_size = false;
- int tabs_rearrange_group = -1;
+ bool theme_changing = false;
- Vector<Ref<TextLine>> text_buf;
- Vector<Control *> _get_tabs() const;
- int _get_tab_width(int p_index) const;
- bool _theme_changing = false;
+ int _get_top_margin() const;
+ Vector<Control *> _get_tab_controls() const;
void _on_theme_changed();
void _repaint();
+ void _refresh_tab_names();
+ void _update_margins();
void _on_mouse_exited();
- void _update_current_tab();
- void _draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x);
- void _refresh_texts();
+ void _on_tab_changed(int p_tab);
+ void _on_tab_selected(int p_tab);
+
+ Variant _get_drag_data_fw(const Point2 &p_point, Control *p_from_control);
+ bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const;
+ void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control);
protected:
- void _child_renamed_callback();
virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
+ static void _bind_methods();
- Variant get_drag_data(const Point2 &p_point) override;
- bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;
- void drop_data(const Point2 &p_point, const Variant &p_data) override;
+public:
int get_tab_idx_at_point(const Point2 &p_point) const;
+ int get_tab_idx_from_control(Control *p_child) const;
- static void _bind_methods();
+ void set_tab_alignment(TabBar::AlignmentMode p_alignment);
+ TabBar::AlignmentMode get_tab_alignment() const;
-public:
- void set_tab_alignment(AlignmentMode p_alignment);
- AlignmentMode get_tab_alignment() const;
+ void set_clip_tabs(bool p_clip_tabs);
+ bool get_clip_tabs() const;
void set_tabs_visible(bool p_visible);
bool are_tabs_visible() const;
@@ -106,10 +92,10 @@ public:
Ref<Texture2D> get_tab_icon(int p_tab) const;
void set_tab_disabled(int p_tab, bool p_disabled);
- bool get_tab_disabled(int p_tab) const;
+ bool is_tab_disabled(int p_tab) const;
void set_tab_hidden(int p_tab, bool p_hidden);
- bool get_tab_hidden(int p_tab) const;
+ bool is_tab_hidden(int p_tab) const;
int get_tab_count() const;
void set_current_tab(int p_current);
@@ -139,6 +125,4 @@ public:
TabContainer();
};
-VARIANT_ENUM_CAST(TabContainer::AlignmentMode);
-
#endif // TAB_CONTAINER_H
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 854a9e463c..05fda7128c 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -5664,8 +5664,10 @@ void TextEdit::_generate_context_menu() {
if (editable) {
menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_paste") : Key::NONE);
}
- menu->add_separator();
- if (is_selecting_enabled()) {
+ if (selecting_enabled || editable) {
+ menu->add_separator();
+ }
+ if (selecting_enabled) {
menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : Key::NONE);
}
if (editable) {
@@ -6579,7 +6581,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
emit_signal(SNAME("lines_edited_from"), p_to_line, p_from_line);
}
-TextEdit::TextEdit() {
+TextEdit::TextEdit(const String &p_placeholder) {
placeholder_data_buf.instantiate();
clear();
@@ -6621,5 +6623,7 @@ TextEdit::TextEdit() {
undo_stack_max_size = GLOBAL_GET("gui/common/text_edit_undo_stack_max_size");
+ set_placeholder(p_placeholder);
+
set_editable(true);
}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 83a63ae40a..6deaf76e5e 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -940,7 +940,7 @@ public:
void set_draw_spaces(bool p_enabled);
bool is_drawing_spaces() const;
- TextEdit();
+ TextEdit(const String &p_placeholder = String());
};
VARIANT_ENUM_CAST(TextEdit::CaretType);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 5afc37061b..ff8d2b88b1 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1186,7 +1186,7 @@ void recursive_call_aux(TreeItem *p_item, const StringName &p_method, const Vari
if (!p_item) {
return;
}
- p_item->call(p_method, p_args, p_argcount, r_error);
+ p_item->callp(p_method, p_args, p_argcount, r_error);
TreeItem *c = p_item->get_first_child();
while (c) {
recursive_call_aux(c, p_method, p_args, p_argcount, r_error);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 211667ce38..208bbe4d72 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -211,7 +211,7 @@ void Node::_propagate_enter_tree() {
if (data.parent) {
Variant c = this;
const Variant *cptr = &c;
- data.parent->emit_signal(SNAME("child_entered_tree"), &cptr, 1);
+ data.parent->emit_signalp(SNAME("child_entered_tree"), &cptr, 1);
}
data.blocked++;
@@ -287,7 +287,7 @@ void Node::_propagate_exit_tree() {
if (data.parent) {
Variant c = this;
const Variant *cptr = &c;
- data.parent->emit_signal(SNAME("child_exited_tree"), &cptr, 1);
+ data.parent->emit_signalp(SNAME("child_exited_tree"), &cptr, 1);
}
// exit groups
@@ -582,34 +582,6 @@ uint16_t Node::rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc
/***** RPC FUNCTIONS ********/
-void Node::rpc(const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- rpcp(0, p_method, argptr, argc);
-}
-
-void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- rpcp(p_peer_id, p_method, argptr, argc);
-}
-
Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 1) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -2389,42 +2361,6 @@ void Node::_replace_connections_target(Node *p_new_target) {
}
}
-Vector<Variant> Node::make_binds(VARIANT_ARG_DECLARE) {
- Vector<Variant> ret;
-
- if (p_arg1.get_type() == Variant::NIL) {
- return ret;
- } else {
- ret.push_back(p_arg1);
- }
-
- if (p_arg2.get_type() == Variant::NIL) {
- return ret;
- } else {
- ret.push_back(p_arg2);
- }
-
- if (p_arg3.get_type() == Variant::NIL) {
- return ret;
- } else {
- ret.push_back(p_arg3);
- }
-
- if (p_arg4.get_type() == Variant::NIL) {
- return ret;
- } else {
- ret.push_back(p_arg4);
- }
-
- if (p_arg5.get_type() == Variant::NIL) {
- return ret;
- } else {
- ret.push_back(p_arg5);
- }
-
- return ret;
-}
-
bool Node::has_node_and_resource(const NodePath &p_path) const {
if (!has_node(p_path)) {
return false;
diff --git a/scene/main/node.h b/scene/main/node.h
index 8e49f871a7..f5fbcf6587 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -420,7 +420,11 @@ public:
void set_scene_instance_load_placeholder(bool p_enable);
bool get_scene_instance_load_placeholder() const;
- static Vector<Variant> make_binds(VARIANT_ARG_LIST);
+ template <typename... VarArgs>
+ Vector<Variant> make_binds(VarArgs... p_args) {
+ Vector<Variant> binds = { p_args... };
+ return binds;
+ }
void replace_by(Node *p_node, bool p_keep_data = false);
@@ -472,8 +476,26 @@ public:
uint16_t rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc_mode, bool p_call_local = false, Multiplayer::TransferMode p_transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE, int p_channel = 0); // config a local method for RPC
Vector<Multiplayer::RPCConfig> get_node_rpc_methods() const;
- void rpc(const StringName &p_method, VARIANT_ARG_LIST); // RPC, honors RPCMode, TransferMode, channel
- void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); // RPC to specific peer(s), honors RPCMode, TransferMode, channel
+ template <typename... VarArgs>
+ void rpc(const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ rpcp(0, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ template <typename... VarArgs>
+ void rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
void rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount);
Ref<MultiplayerAPI> get_multiplayer() const;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 69e7472cf2..3ddce28b69 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -175,13 +175,13 @@ void SceneTree::_flush_ugc() {
while (unique_group_calls.size()) {
Map<UGCall, Vector<Variant>>::Element *E = unique_group_calls.front();
- Variant v[VARIANT_ARG_MAX];
+ const Variant **argptrs = (const Variant **)alloca(E->get().size() * sizeof(Variant *));
+
for (int i = 0; i < E->get().size(); i++) {
- v[i] = E->get()[i];
+ argptrs[i] = &E->get()[i];
}
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- call_group_flags(GROUP_CALL_REALTIME, E->key().group, E->key().call, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ call_group_flagsp(GROUP_CALL_REALTIME, E->key().group, E->key().call, argptrs, E->get().size());
unique_group_calls.erase(E);
}
@@ -210,7 +210,7 @@ void SceneTree::_update_group_order(Group &g, bool p_use_priority) {
g.changed = false;
}
-void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) {
+void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, const Variant **p_args, int p_argcount) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E) {
return;
@@ -231,14 +231,9 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou
return;
}
- VARIANT_ARGPTRS;
-
Vector<Variant> args;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- args.push_back(*argptr[i]);
+ for (int i = 0; i < p_argcount; i++) {
+ args.push_back(*p_args[i]);
}
unique_group_calls[ug] = args;
@@ -260,9 +255,10 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou
}
if (p_call_flags & GROUP_CALL_REALTIME) {
- nodes[i]->call(p_function, VARIANT_ARG_PASS);
+ Callable::CallError ce;
+ nodes[i]->callp(p_function, p_args, p_argcount, ce);
} else {
- MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS);
+ MessageQueue::get_singleton()->push_callp(nodes[i], p_function, p_args, p_argcount);
}
}
@@ -273,9 +269,10 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou
}
if (p_call_flags & GROUP_CALL_REALTIME) {
- nodes[i]->call(p_function, VARIANT_ARG_PASS);
+ Callable::CallError ce;
+ nodes[i]->callp(p_function, p_args, p_argcount, ce);
} else {
- MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS);
+ MessageQueue::get_singleton()->push_callp(nodes[i], p_function, p_args, p_argcount);
}
}
}
@@ -388,10 +385,6 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
}
}
-void SceneTree::call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) {
- call_group_flags(0, p_group, p_function, VARIANT_ARG_PASS);
-}
-
void SceneTree::notify_group(const StringName &p_group, int p_notification) {
notify_group_flags(0, p_group, p_notification);
}
@@ -486,7 +479,7 @@ bool SceneTree::process(double p_time) {
}
E->get()->set_time_left(time_left);
- if (time_left < 0) {
+ if (time_left <= 0) {
E->get()->emit_signal(SNAME("timeout"));
timers.erase(E);
}
@@ -930,14 +923,8 @@ Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Cal
int flags = *p_args[0];
StringName group = *p_args[1];
StringName method = *p_args[2];
- Variant v[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(p_argcount - 3, 5); i++) {
- v[i] = *p_args[i + 3];
- }
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- call_group_flags(flags, group, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ call_group_flagsp(flags, group, method, p_args + 3, p_argcount - 3);
return Variant();
}
@@ -950,14 +937,8 @@ Variant SceneTree::_call_group(const Variant **p_args, int p_argcount, Callable:
StringName group = *p_args[0];
StringName method = *p_args[1];
- Variant v[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(p_argcount - 2, 5); i++) {
- v[i] = *p_args[i + 2];
- }
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- call_group_flags(0, group, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+ call_group_flagsp(0, group, method, p_args + 2, p_argcount - 2);
return Variant();
}
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 5f7c1729e8..6197e52fc1 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -229,14 +229,33 @@ public:
_FORCE_INLINE_ Window *get_root() const { return root; }
- void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST);
+ void call_group_flagsp(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, const Variant **p_args, int p_argcount);
void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification);
void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value);
- void call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST);
void notify_group(const StringName &p_group, int p_notification);
void set_group(const StringName &p_group, const String &p_name, const Variant &p_value);
+ template <typename... VarArgs>
+ void call_group(const StringName &p_group, const StringName &p_function, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ call_group_flagsp(0, p_group, p_function, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ template <typename... VarArgs>
+ void call_group_flags(uint32_t p_flags, const StringName &p_group, const StringName &p_function, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ call_group_flagsp(p_flags, p_group, p_function, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
void flush_transform_notifications();
virtual void initialize() override;
diff --git a/scene/multiplayer/scene_rpc_interface.cpp b/scene/multiplayer/scene_rpc_interface.cpp
index 2239a5d81c..84700a82f3 100644
--- a/scene/multiplayer/scene_rpc_interface.cpp
+++ b/scene/multiplayer/scene_rpc_interface.cpp
@@ -278,7 +278,7 @@ void SceneRPCInterface::_process_rpc(Node *p_node, const uint16_t p_rpc_method_i
Callable::CallError ce;
- p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce);
+ p_node->callp(config.name, (const Variant **)argp.ptr(), argc, ce);
if (ce.error != Callable::CallError::CALL_OK) {
String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce);
error = "RPC - " + error;
@@ -480,7 +480,7 @@ void SceneRPCInterface::rpcp(Object *p_obj, int p_peer_id, const StringName &p_m
Callable::CallError ce;
multiplayer->set_remote_sender_override(peer->get_unique_id());
- node->call(p_method, p_arg, p_argcount, ce);
+ node->callp(p_method, p_arg, p_argcount, ce);
multiplayer->set_remote_sender_override(0);
if (ce.error != Callable::CallError::CALL_OK) {
@@ -496,7 +496,7 @@ void SceneRPCInterface::rpcp(Object *p_obj, int p_peer_id, const StringName &p_m
ce.error = Callable::CallError::CALL_OK;
multiplayer->set_remote_sender_override(peer->get_unique_id());
- node->get_script_instance()->call(p_method, p_arg, p_argcount, ce);
+ node->get_script_instance()->callp(p_method, p_arg, p_argcount, ce);
multiplayer->set_remote_sender_override(0);
if (ce.error != Callable::CallError::CALL_OK) {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 152a1616f8..fb5d57ab9e 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -260,9 +260,9 @@
static Ref<ResourceFormatSaverText> resource_saver_text;
static Ref<ResourceFormatLoaderText> resource_loader_text;
-static Ref<ResourceFormatLoaderStreamTexture2D> resource_loader_stream_texture;
-static Ref<ResourceFormatLoaderStreamTextureLayered> resource_loader_texture_layered;
-static Ref<ResourceFormatLoaderStreamTexture3D> resource_loader_texture_3d;
+static Ref<ResourceFormatLoaderCompressedTexture2D> resource_loader_stream_texture;
+static Ref<ResourceFormatLoaderCompressedTextureLayered> resource_loader_texture_layered;
+static Ref<ResourceFormatLoaderCompressedTexture3D> resource_loader_texture_3d;
static Ref<ResourceFormatSaverShader> resource_saver_shader;
static Ref<ResourceFormatLoaderShader> resource_loader_shader;
@@ -300,9 +300,9 @@ void register_scene_types() {
GDREGISTER_CLASS(Object);
GDREGISTER_CLASS(Node);
- GDREGISTER_VIRTUAL_CLASS(InstancePlaceholder);
+ GDREGISTER_ABSTRACT_CLASS(InstancePlaceholder);
- GDREGISTER_VIRTUAL_CLASS(Viewport);
+ GDREGISTER_ABSTRACT_CLASS(Viewport);
GDREGISTER_CLASS(SubViewport);
GDREGISTER_CLASS(ViewportTexture);
GDREGISTER_CLASS(HTTPRequest);
@@ -324,11 +324,11 @@ void register_scene_types() {
GDREGISTER_CLASS(Control);
GDREGISTER_CLASS(Button);
GDREGISTER_CLASS(Label);
- GDREGISTER_VIRTUAL_CLASS(ScrollBar);
+ GDREGISTER_ABSTRACT_CLASS(ScrollBar);
GDREGISTER_CLASS(HScrollBar);
GDREGISTER_CLASS(VScrollBar);
GDREGISTER_CLASS(ProgressBar);
- GDREGISTER_VIRTUAL_CLASS(Slider);
+ GDREGISTER_ABSTRACT_CLASS(Slider);
GDREGISTER_CLASS(HSlider);
GDREGISTER_CLASS(VSlider);
GDREGISTER_CLASS(Popup);
@@ -349,19 +349,19 @@ void register_scene_types() {
GDREGISTER_CLASS(AspectRatioContainer);
GDREGISTER_CLASS(TabContainer);
GDREGISTER_CLASS(TabBar);
- GDREGISTER_VIRTUAL_CLASS(Separator);
+ GDREGISTER_ABSTRACT_CLASS(Separator);
GDREGISTER_CLASS(HSeparator);
GDREGISTER_CLASS(VSeparator);
GDREGISTER_CLASS(TextureButton);
GDREGISTER_CLASS(Container);
- GDREGISTER_VIRTUAL_CLASS(BoxContainer);
+ GDREGISTER_ABSTRACT_CLASS(BoxContainer);
GDREGISTER_CLASS(HBoxContainer);
GDREGISTER_CLASS(VBoxContainer);
GDREGISTER_CLASS(GridContainer);
GDREGISTER_CLASS(CenterContainer);
GDREGISTER_CLASS(ScrollContainer);
GDREGISTER_CLASS(PanelContainer);
- GDREGISTER_VIRTUAL_CLASS(FlowContainer);
+ GDREGISTER_ABSTRACT_CLASS(FlowContainer);
GDREGISTER_CLASS(HFlowContainer);
GDREGISTER_CLASS(VFlowContainer);
@@ -384,7 +384,7 @@ void register_scene_types() {
GDREGISTER_CLASS(SyntaxHighlighter);
GDREGISTER_CLASS(CodeHighlighter);
- GDREGISTER_VIRTUAL_CLASS(TreeItem);
+ GDREGISTER_ABSTRACT_CLASS(TreeItem);
GDREGISTER_CLASS(OptionButton);
GDREGISTER_CLASS(SpinBox);
GDREGISTER_CLASS(ColorPicker);
@@ -398,7 +398,7 @@ void register_scene_types() {
GDREGISTER_CLASS(MarginContainer);
GDREGISTER_CLASS(SubViewportContainer);
- GDREGISTER_VIRTUAL_CLASS(SplitContainer);
+ GDREGISTER_ABSTRACT_CLASS(SplitContainer);
GDREGISTER_CLASS(HSplitContainer);
GDREGISTER_CLASS(VSplitContainer);
@@ -418,7 +418,7 @@ void register_scene_types() {
GDREGISTER_CLASS(AnimationPlayer);
GDREGISTER_CLASS(Tween);
- GDREGISTER_VIRTUAL_CLASS(Tweener);
+ GDREGISTER_ABSTRACT_CLASS(Tweener);
GDREGISTER_CLASS(PropertyTweener);
GDREGISTER_CLASS(IntervalTweener);
GDREGISTER_CLASS(CallbackTweener);
@@ -453,9 +453,9 @@ void register_scene_types() {
#ifndef _3D_DISABLED
GDREGISTER_CLASS(Node3D);
- GDREGISTER_VIRTUAL_CLASS(Node3DGizmo);
+ GDREGISTER_ABSTRACT_CLASS(Node3DGizmo);
GDREGISTER_CLASS(Skin);
- GDREGISTER_VIRTUAL_CLASS(SkinReference);
+ GDREGISTER_ABSTRACT_CLASS(SkinReference);
GDREGISTER_CLASS(Skeleton3D);
GDREGISTER_CLASS(ImporterMesh);
GDREGISTER_CLASS(ImporterMeshInstance3D);
@@ -464,22 +464,22 @@ void register_scene_types() {
GDREGISTER_CLASS(Camera3D);
GDREGISTER_CLASS(AudioListener3D);
GDREGISTER_CLASS(XRCamera3D);
- GDREGISTER_VIRTUAL_CLASS(XRNode3D);
+ GDREGISTER_ABSTRACT_CLASS(XRNode3D);
GDREGISTER_CLASS(XRController3D);
GDREGISTER_CLASS(XRAnchor3D);
GDREGISTER_CLASS(XROrigin3D);
GDREGISTER_CLASS(MeshInstance3D);
GDREGISTER_CLASS(OccluderInstance3D);
- GDREGISTER_VIRTUAL_CLASS(Occluder3D);
+ GDREGISTER_ABSTRACT_CLASS(Occluder3D);
GDREGISTER_CLASS(ArrayOccluder3D);
GDREGISTER_CLASS(QuadOccluder3D);
GDREGISTER_CLASS(BoxOccluder3D);
GDREGISTER_CLASS(SphereOccluder3D);
GDREGISTER_CLASS(PolygonOccluder3D);
- GDREGISTER_VIRTUAL_CLASS(SpriteBase3D);
+ GDREGISTER_ABSTRACT_CLASS(SpriteBase3D);
GDREGISTER_CLASS(Sprite3D);
GDREGISTER_CLASS(AnimatedSprite3D);
- GDREGISTER_VIRTUAL_CLASS(Light3D);
+ GDREGISTER_ABSTRACT_CLASS(Light3D);
GDREGISTER_CLASS(DirectionalLight3D);
GDREGISTER_CLASS(OmniLight3D);
GDREGISTER_CLASS(SpotLight3D);
@@ -490,14 +490,14 @@ void register_scene_types() {
GDREGISTER_CLASS(LightmapGI);
GDREGISTER_CLASS(LightmapGIData);
GDREGISTER_CLASS(LightmapProbe);
- GDREGISTER_VIRTUAL_CLASS(Lightmapper);
+ GDREGISTER_ABSTRACT_CLASS(Lightmapper);
GDREGISTER_CLASS(GPUParticles3D);
- GDREGISTER_VIRTUAL_CLASS(GPUParticlesCollision3D);
+ GDREGISTER_ABSTRACT_CLASS(GPUParticlesCollision3D);
GDREGISTER_CLASS(GPUParticlesCollisionBox3D);
GDREGISTER_CLASS(GPUParticlesCollisionSphere3D);
GDREGISTER_CLASS(GPUParticlesCollisionSDF3D);
GDREGISTER_CLASS(GPUParticlesCollisionHeightField3D);
- GDREGISTER_VIRTUAL_CLASS(GPUParticlesAttractor3D);
+ GDREGISTER_ABSTRACT_CLASS(GPUParticlesAttractor3D);
GDREGISTER_CLASS(GPUParticlesAttractorBox3D);
GDREGISTER_CLASS(GPUParticlesAttractorSphere3D);
GDREGISTER_CLASS(GPUParticlesAttractorVectorField3D);
@@ -509,8 +509,8 @@ void register_scene_types() {
OS::get_singleton()->yield(); // may take time to init
- GDREGISTER_VIRTUAL_CLASS(CollisionObject3D);
- GDREGISTER_VIRTUAL_CLASS(PhysicsBody3D);
+ GDREGISTER_ABSTRACT_CLASS(CollisionObject3D);
+ GDREGISTER_ABSTRACT_CLASS(PhysicsBody3D);
GDREGISTER_CLASS(StaticBody3D);
GDREGISTER_CLASS(AnimatableBody3D);
GDREGISTER_CLASS(RigidDynamicBody3D);
@@ -542,7 +542,7 @@ void register_scene_types() {
GDREGISTER_CLASS(FogMaterial);
GDREGISTER_CLASS(RemoteTransform3D);
- GDREGISTER_VIRTUAL_CLASS(Joint3D);
+ GDREGISTER_ABSTRACT_CLASS(Joint3D);
GDREGISTER_CLASS(PinJoint3D);
GDREGISTER_CLASS(HingeJoint3D);
GDREGISTER_CLASS(SliderJoint3D);
@@ -560,14 +560,14 @@ void register_scene_types() {
GDREGISTER_CLASS(Shader);
GDREGISTER_CLASS(VisualShader);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNode);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNode);
GDREGISTER_CLASS(VisualShaderNodeCustom);
GDREGISTER_CLASS(VisualShaderNodeInput);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeOutput);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeResizableBase);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeGroupBase);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeConstant);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeVectorBase);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeOutput);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeResizableBase);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeGroupBase);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeConstant);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeVectorBase);
GDREGISTER_CLASS(VisualShaderNodeComment);
GDREGISTER_CLASS(VisualShaderNodeFloatConstant);
GDREGISTER_CLASS(VisualShaderNodeIntConstant);
@@ -607,11 +607,11 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeTexture);
GDREGISTER_CLASS(VisualShaderNodeCurveTexture);
GDREGISTER_CLASS(VisualShaderNodeCurveXYZTexture);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeSample3D);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeSample3D);
GDREGISTER_CLASS(VisualShaderNodeTexture2DArray);
GDREGISTER_CLASS(VisualShaderNodeTexture3D);
GDREGISTER_CLASS(VisualShaderNodeCubemap);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeUniform);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeUniform);
GDREGISTER_CLASS(VisualShaderNodeUniformRef);
GDREGISTER_CLASS(VisualShaderNodeFloatUniform);
GDREGISTER_CLASS(VisualShaderNodeIntUniform);
@@ -634,6 +634,9 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeCompare);
GDREGISTER_CLASS(VisualShaderNodeMultiplyAdd);
GDREGISTER_CLASS(VisualShaderNodeBillboard);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeVarying);
+ GDREGISTER_CLASS(VisualShaderNodeVaryingSetter);
+ GDREGISTER_CLASS(VisualShaderNodeVaryingGetter);
GDREGISTER_CLASS(VisualShaderNodeSDFToScreenUV);
GDREGISTER_CLASS(VisualShaderNodeScreenUVToSDF);
@@ -642,7 +645,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeSDFRaymarch);
GDREGISTER_CLASS(VisualShaderNodeParticleOutput);
- GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeParticleEmitter);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeParticleEmitter);
GDREGISTER_CLASS(VisualShaderNodeParticleSphereEmitter);
GDREGISTER_CLASS(VisualShaderNodeParticleBoxEmitter);
GDREGISTER_CLASS(VisualShaderNodeParticleRingEmitter);
@@ -654,7 +657,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeParticleEmit);
GDREGISTER_CLASS(ShaderMaterial);
- GDREGISTER_VIRTUAL_CLASS(CanvasItem);
+ GDREGISTER_ABSTRACT_CLASS(CanvasItem);
GDREGISTER_CLASS(CanvasTexture);
GDREGISTER_CLASS(CanvasItemMaterial);
SceneTree::add_idle_callback(CanvasItemMaterial::flush_changes);
@@ -673,8 +676,8 @@ void register_scene_types() {
GDREGISTER_CLASS(Line2D);
GDREGISTER_CLASS(MeshInstance2D);
GDREGISTER_CLASS(MultiMeshInstance2D);
- GDREGISTER_VIRTUAL_CLASS(CollisionObject2D);
- GDREGISTER_VIRTUAL_CLASS(PhysicsBody2D);
+ GDREGISTER_ABSTRACT_CLASS(CollisionObject2D);
+ GDREGISTER_ABSTRACT_CLASS(PhysicsBody2D);
GDREGISTER_CLASS(StaticBody2D);
GDREGISTER_CLASS(AnimatableBody2D);
GDREGISTER_CLASS(RigidDynamicBody2D);
@@ -690,7 +693,7 @@ void register_scene_types() {
GDREGISTER_CLASS(Polygon2D);
GDREGISTER_CLASS(Skeleton2D);
GDREGISTER_CLASS(Bone2D);
- GDREGISTER_VIRTUAL_CLASS(Light2D);
+ GDREGISTER_ABSTRACT_CLASS(Light2D);
GDREGISTER_CLASS(PointLight2D);
GDREGISTER_CLASS(DirectionalLight2D);
GDREGISTER_CLASS(LightOccluder2D);
@@ -701,12 +704,12 @@ void register_scene_types() {
GDREGISTER_CLASS(Camera2D);
GDREGISTER_CLASS(AudioListener2D);
- GDREGISTER_VIRTUAL_CLASS(Joint2D);
+ GDREGISTER_ABSTRACT_CLASS(Joint2D);
GDREGISTER_CLASS(PinJoint2D);
GDREGISTER_CLASS(GrooveJoint2D);
GDREGISTER_CLASS(DampedSpringJoint2D);
GDREGISTER_CLASS(TileSet);
- GDREGISTER_VIRTUAL_CLASS(TileSetSource);
+ GDREGISTER_ABSTRACT_CLASS(TileSetSource);
GDREGISTER_CLASS(TileSetAtlasSource);
GDREGISTER_CLASS(TileSetScenesCollectionSource);
GDREGISTER_CLASS(TileMapPattern);
@@ -733,7 +736,7 @@ void register_scene_types() {
/* REGISTER RESOURCES */
- GDREGISTER_VIRTUAL_CLASS(Shader);
+ GDREGISTER_ABSTRACT_CLASS(Shader);
GDREGISTER_CLASS(ParticlesMaterial);
SceneTree::add_idle_callback(ParticlesMaterial::flush_changes);
ParticlesMaterial::init_shaders();
@@ -762,7 +765,7 @@ void register_scene_types() {
GDREGISTER_CLASS(RibbonTrailMesh);
GDREGISTER_CLASS(PointMesh);
GDREGISTER_VIRTUAL_CLASS(Material);
- GDREGISTER_VIRTUAL_CLASS(BaseMaterial3D);
+ GDREGISTER_ABSTRACT_CLASS(BaseMaterial3D);
GDREGISTER_CLASS(StandardMaterial3D);
GDREGISTER_CLASS(ORMMaterial3D);
SceneTree::add_idle_callback(BaseMaterial3D::flush_changes);
@@ -772,7 +775,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); // may take time to init
- GDREGISTER_VIRTUAL_CLASS(Shape3D);
+ GDREGISTER_ABSTRACT_CLASS(Shape3D);
GDREGISTER_CLASS(SeparationRayShape3D);
GDREGISTER_CLASS(SphereShape3D);
GDREGISTER_CLASS(BoxShape3D);
@@ -805,7 +808,7 @@ void register_scene_types() {
GDREGISTER_VIRTUAL_CLASS(Texture);
GDREGISTER_VIRTUAL_CLASS(Texture2D);
GDREGISTER_CLASS(Sky);
- GDREGISTER_CLASS(StreamTexture2D);
+ GDREGISTER_CLASS(CompressedTexture2D);
GDREGISTER_CLASS(ImageTexture);
GDREGISTER_CLASS(AtlasTexture);
GDREGISTER_CLASS(MeshTexture);
@@ -817,17 +820,17 @@ void register_scene_types() {
GDREGISTER_CLASS(AnimatedTexture);
GDREGISTER_CLASS(CameraTexture);
GDREGISTER_VIRTUAL_CLASS(TextureLayered);
- GDREGISTER_VIRTUAL_CLASS(ImageTextureLayered);
+ GDREGISTER_ABSTRACT_CLASS(ImageTextureLayered);
GDREGISTER_VIRTUAL_CLASS(Texture3D);
GDREGISTER_CLASS(ImageTexture3D);
- GDREGISTER_CLASS(StreamTexture3D);
+ GDREGISTER_CLASS(CompressedTexture3D);
GDREGISTER_CLASS(Cubemap);
GDREGISTER_CLASS(CubemapArray);
GDREGISTER_CLASS(Texture2DArray);
- GDREGISTER_VIRTUAL_CLASS(StreamTextureLayered);
- GDREGISTER_CLASS(StreamCubemap);
- GDREGISTER_CLASS(StreamCubemapArray);
- GDREGISTER_CLASS(StreamTexture2DArray);
+ GDREGISTER_ABSTRACT_CLASS(CompressedTextureLayered);
+ GDREGISTER_CLASS(CompressedCubemap);
+ GDREGISTER_CLASS(CompressedCubemapArray);
+ GDREGISTER_CLASS(CompressedTexture2DArray);
GDREGISTER_CLASS(Animation);
GDREGISTER_CLASS(FontData);
@@ -857,12 +860,12 @@ void register_scene_types() {
#ifndef _3D_DISABLED
GDREGISTER_CLASS(AudioStreamPlayer3D);
#endif
- GDREGISTER_VIRTUAL_CLASS(VideoStream);
+ GDREGISTER_ABSTRACT_CLASS(VideoStream);
GDREGISTER_CLASS(AudioStreamSample);
OS::get_singleton()->yield(); // may take time to init
- GDREGISTER_VIRTUAL_CLASS(Shape2D);
+ GDREGISTER_ABSTRACT_CLASS(Shape2D);
GDREGISTER_CLASS(WorldBoundaryShape2D);
GDREGISTER_CLASS(SegmentShape2D);
GDREGISTER_CLASS(SeparationRayShape2D);
@@ -883,11 +886,11 @@ void register_scene_types() {
OS::get_singleton()->yield(); // may take time to init
- GDREGISTER_VIRTUAL_CLASS(SceneState);
+ GDREGISTER_ABSTRACT_CLASS(SceneState);
GDREGISTER_CLASS(PackedScene);
GDREGISTER_CLASS(SceneTree);
- GDREGISTER_VIRTUAL_CLASS(SceneTreeTimer); // sorry, you can't create it
+ GDREGISTER_ABSTRACT_CLASS(SceneTreeTimer); // sorry, you can't create it
#ifndef DISABLE_DEPRECATED
// Dropped in 4.0, near approximation.
@@ -925,8 +928,6 @@ void register_scene_types() {
ClassDB::add_compatibility_class("ARVRServer", "XRServer");
ClassDB::add_compatibility_class("BoneAttachment", "BoneAttachment3D");
ClassDB::add_compatibility_class("BoxShape", "BoxShape3D");
- ClassDB::add_compatibility_class("BulletPhysicsDirectBodyState", "BulletPhysicsDirectBodyState3D");
- ClassDB::add_compatibility_class("BulletPhysicsServer", "BulletPhysicsServer3D");
ClassDB::add_compatibility_class("Camera", "Camera3D");
ClassDB::add_compatibility_class("CapsuleShape", "CapsuleShape3D");
ClassDB::add_compatibility_class("ClippedCamera", "ClippedCamera3D");
@@ -1013,7 +1014,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("StreamTexture", "StreamTexture2D");
+ ClassDB::add_compatibility_class("StreamTexture", "CompressedTexture2D");
ClassDB::add_compatibility_class("TextureProgress", "TextureProgressBar");
ClassDB::add_compatibility_class("VehicleBody", "VehicleBody3D");
ClassDB::add_compatibility_class("VehicleWheel", "VehicleWheel3D");
@@ -1043,6 +1044,14 @@ void register_scene_types() {
ClassDB::add_compatibility_class("VisualShaderNodeScalarDerivativeFunc", "VisualShaderNodeDerivativeFunc");
ClassDB::add_compatibility_class("VisualShaderNodeVectorDerivativeFunc", "VisualShaderNodeDerivativeFunc");
ClassDB::add_compatibility_class("World", "World3D");
+
+ // Renamed during 4.0 alpha, added to ease transition between alphas.
+ ClassDB::add_compatibility_class("StreamCubemap", "CompressedCubemap");
+ ClassDB::add_compatibility_class("StreamCubemapArray", "CompressedCubemapArray");
+ ClassDB::add_compatibility_class("StreamTexture2D", "CompressedTexture2D");
+ ClassDB::add_compatibility_class("StreamTexture2DArray", "CompressedTexture2DArray");
+ ClassDB::add_compatibility_class("StreamTexture3D", "CompressedTexture3D");
+ ClassDB::add_compatibility_class("StreamTextureLayered", "CompressedTextureLayered");
#endif /* DISABLE_DEPRECATED */
OS::get_singleton()->yield(); // may take time to init
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 312a557602..f6e0df0265 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -4347,7 +4347,7 @@ struct AnimationCompressionDataState {
if (temp_packets.size() == 0) {
return; //nohing to do
}
-#define DEBUG_PACKET_PUSH
+//#define DEBUG_PACKET_PUSH
#ifdef DEBUG_PACKET_PUSH
#ifndef _MSC_VER
#warning Debugging packet push, disable this code in production to gain a bit more import performance.
@@ -4378,7 +4378,7 @@ struct AnimationCompressionDataState {
header_bytes += 2;
}
- while (header_bytes % 4 != 0) {
+ while (header_bytes < 8 && header_bytes % 4 != 0) { // First cond needed to silence wrong GCC warning.
header[header_bytes++] = 0;
}
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 6fb0c0468d..a0e6cc28ce 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -88,6 +88,37 @@ void Material::inspect_native_shader_code() {
}
}
+RID Material::get_shader_rid() const {
+ RID ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_shader_rid, ret)) {
+ return ret;
+ }
+ return RID();
+}
+Shader::Mode Material::get_shader_mode() const {
+ Shader::Mode ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_shader_mode, ret)) {
+ return ret;
+ }
+
+ return Shader::MODE_MAX;
+}
+
+bool Material::_can_do_next_pass() const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_can_do_next_pass, ret)) {
+ return ret;
+ }
+ return false;
+}
+bool Material::_can_use_render_priority() const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_can_use_render_priority, ret)) {
+ return ret;
+ }
+ return false;
+}
+
void Material::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_next_pass", "next_pass"), &Material::set_next_pass);
ClassDB::bind_method(D_METHOD("get_next_pass"), &Material::get_next_pass);
@@ -103,6 +134,11 @@ void Material::_bind_methods() {
BIND_CONSTANT(RENDER_PRIORITY_MAX);
BIND_CONSTANT(RENDER_PRIORITY_MIN);
+
+ GDVIRTUAL_BIND(_get_shader_rid)
+ GDVIRTUAL_BIND(_get_shader_mode)
+ GDVIRTUAL_BIND(_can_do_next_pass)
+ GDVIRTUAL_BIND(_can_use_render_priority)
}
Material::Material() {
diff --git a/scene/resources/material.h b/scene/resources/material.h
index a79f072f9a..07227c037c 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -51,11 +51,15 @@ class Material : public Resource {
protected:
_FORCE_INLINE_ RID _get_material() const { return material; }
static void _bind_methods();
- virtual bool _can_do_next_pass() const { return false; }
- virtual bool _can_use_render_priority() const { return false; }
+ virtual bool _can_do_next_pass() const;
+ virtual bool _can_use_render_priority() const;
void _validate_property(PropertyInfo &property) const override;
+ GDVIRTUAL0RC(RID, _get_shader_rid)
+ GDVIRTUAL0RC(Shader::Mode, _get_shader_mode)
+ GDVIRTUAL0RC(bool, _can_do_next_pass)
+ GDVIRTUAL0RC(bool, _can_use_render_priority)
public:
enum {
RENDER_PRIORITY_MAX = RS::MATERIAL_RENDER_PRIORITY_MAX,
@@ -68,9 +72,8 @@ public:
int get_render_priority() const;
virtual RID get_rid() const override;
- virtual RID get_shader_rid() const = 0;
-
- virtual Shader::Mode get_shader_mode() const = 0;
+ virtual RID get_shader_rid() const;
+ virtual Shader::Mode get_shader_mode() const;
Material();
virtual ~Material();
};
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 6b44b05e02..3c67a20f50 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -40,6 +40,122 @@
Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
+int Mesh::get_surface_count() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_surface_count, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+int Mesh::surface_get_array_len(int p_idx) const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_get_array_len, p_idx, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+int Mesh::surface_get_array_index_len(int p_idx) const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_get_array_index_len, p_idx, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+Array Mesh::surface_get_arrays(int p_surface) const {
+ Array ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_get_arrays, p_surface, ret)) {
+ return ret;
+ }
+ return Array();
+}
+
+Array Mesh::surface_get_blend_shape_arrays(int p_surface) const {
+ Array ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_get_blend_shape_arrays, p_surface, ret)) {
+ return ret;
+ }
+
+ return Array();
+}
+
+Dictionary Mesh::surface_get_lods(int p_surface) const {
+ Dictionary ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_get_lods, p_surface, ret)) {
+ return ret;
+ }
+
+ return Dictionary();
+}
+
+uint32_t Mesh::surface_get_format(int p_idx) const {
+ uint32_t ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_get_format, p_idx, ret)) {
+ return ret;
+ }
+
+ return 0;
+}
+
+Mesh::PrimitiveType Mesh::surface_get_primitive_type(int p_idx) const {
+ uint32_t ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_get_primitive_type, p_idx, ret)) {
+ return (Mesh::PrimitiveType)ret;
+ }
+
+ return PRIMITIVE_MAX;
+}
+
+void Mesh::surface_set_material(int p_idx, const Ref<Material> &p_material) {
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_set_material, p_idx, p_material)) {
+ return;
+ }
+}
+
+Ref<Material> Mesh::surface_get_material(int p_idx) const {
+ Ref<Material> ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_surface_get_material, p_idx, ret)) {
+ return ret;
+ }
+
+ return Ref<Material>();
+}
+
+int Mesh::get_blend_shape_count() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_blend_shape_count, ret)) {
+ return ret;
+ }
+
+ return 0;
+}
+
+StringName Mesh::get_blend_shape_name(int p_index) const {
+ StringName ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_blend_shape_name, p_index, ret)) {
+ return ret;
+ }
+
+ return StringName();
+}
+
+void Mesh::set_blend_shape_name(int p_index, const StringName &p_name) {
+ if (GDVIRTUAL_REQUIRED_CALL(_set_blend_shape_name, p_index, p_name)) {
+ return;
+ }
+}
+
+AABB Mesh::get_aabb() const {
+ AABB ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_aabb, ret)) {
+ return ret;
+ }
+
+ return AABB();
+}
+
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
if (triangle_mesh.is_valid()) {
return triangle_mesh;
@@ -502,6 +618,21 @@ void Mesh::_bind_methods() {
BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
+
+ GDVIRTUAL_BIND(_get_surface_count)
+ GDVIRTUAL_BIND(_surface_get_array_len, "index")
+ GDVIRTUAL_BIND(_surface_get_array_index_len, "index")
+ GDVIRTUAL_BIND(_surface_get_arrays, "index")
+ GDVIRTUAL_BIND(_surface_get_blend_shape_arrays, "index")
+ GDVIRTUAL_BIND(_surface_get_lods, "index")
+ GDVIRTUAL_BIND(_surface_get_format, "index")
+ GDVIRTUAL_BIND(_surface_get_primitive_type, "index")
+ GDVIRTUAL_BIND(_surface_set_material, "index", "material")
+ GDVIRTUAL_BIND(_surface_get_material, "index")
+ GDVIRTUAL_BIND(_get_blend_shape_count)
+ GDVIRTUAL_BIND(_get_blend_shape_name, "index")
+ GDVIRTUAL_BIND(_set_blend_shape_name, "index", "name")
+ GDVIRTUAL_BIND(_get_aabb)
}
void Mesh::clear_cache() const {
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 08d834bdb9..652c045a24 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -45,9 +45,34 @@ class Mesh : public Resource {
mutable Vector<Vector3> debug_lines;
Size2i lightmap_size_hint;
+public:
+ enum PrimitiveType {
+ PRIMITIVE_POINTS = RenderingServer::PRIMITIVE_POINTS,
+ PRIMITIVE_LINES = RenderingServer::PRIMITIVE_LINES,
+ PRIMITIVE_LINE_STRIP = RenderingServer::PRIMITIVE_LINE_STRIP,
+ PRIMITIVE_TRIANGLES = RenderingServer::PRIMITIVE_TRIANGLES,
+ PRIMITIVE_TRIANGLE_STRIP = RenderingServer::PRIMITIVE_TRIANGLE_STRIP,
+ PRIMITIVE_MAX = RenderingServer::PRIMITIVE_MAX,
+ };
+
protected:
static void _bind_methods();
+ GDVIRTUAL0RC(int, _get_surface_count)
+ GDVIRTUAL1RC(int, _surface_get_array_len, int)
+ GDVIRTUAL1RC(int, _surface_get_array_index_len, int)
+ GDVIRTUAL1RC(Array, _surface_get_arrays, int)
+ GDVIRTUAL1RC(Array, _surface_get_blend_shape_arrays, int)
+ GDVIRTUAL1RC(Dictionary, _surface_get_lods, int)
+ GDVIRTUAL1RC(uint32_t, _surface_get_format, int)
+ GDVIRTUAL1RC(uint32_t, _surface_get_primitive_type, int)
+ GDVIRTUAL2(_surface_set_material, int, Ref<Material>)
+ GDVIRTUAL1RC(Ref<Material>, _surface_get_material, int)
+ GDVIRTUAL0RC(int, _get_blend_shape_count)
+ GDVIRTUAL1RC(StringName, _get_blend_shape_name, int)
+ GDVIRTUAL2(_set_blend_shape_name, int, StringName)
+ GDVIRTUAL0RC(AABB, _get_aabb)
+
public:
enum {
NO_INDEX_ARRAY = RenderingServer::NO_INDEX_ARRAY,
@@ -120,28 +145,20 @@ public:
};
- enum PrimitiveType {
- PRIMITIVE_POINTS = RenderingServer::PRIMITIVE_POINTS,
- PRIMITIVE_LINES = RenderingServer::PRIMITIVE_LINES,
- PRIMITIVE_LINE_STRIP = RenderingServer::PRIMITIVE_LINE_STRIP,
- PRIMITIVE_TRIANGLES = RenderingServer::PRIMITIVE_TRIANGLES,
- PRIMITIVE_TRIANGLE_STRIP = RenderingServer::PRIMITIVE_TRIANGLE_STRIP,
- PRIMITIVE_MAX = RenderingServer::PRIMITIVE_MAX,
- };
-
- 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;
- virtual Array surface_get_arrays(int p_surface) const = 0;
- virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0;
- virtual Dictionary surface_get_lods(int p_surface) const = 0;
- virtual uint32_t surface_get_format(int p_idx) const = 0;
- virtual PrimitiveType surface_get_primitive_type(int p_idx) const = 0;
- virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) = 0;
- virtual Ref<Material> surface_get_material(int p_idx) const = 0;
- virtual int get_blend_shape_count() const = 0;
- virtual StringName get_blend_shape_name(int p_index) const = 0;
- virtual void set_blend_shape_name(int p_index, const StringName &p_name) = 0;
+ virtual int get_surface_count() const;
+ virtual int surface_get_array_len(int p_idx) const;
+ virtual int surface_get_array_index_len(int p_idx) const;
+ virtual Array surface_get_arrays(int p_surface) const;
+ virtual Array surface_get_blend_shape_arrays(int p_surface) const;
+ virtual Dictionary surface_get_lods(int p_surface) const;
+ virtual uint32_t surface_get_format(int p_idx) const;
+ virtual PrimitiveType surface_get_primitive_type(int p_idx) const;
+ virtual void surface_set_material(int p_idx, const Ref<Material> &p_material);
+ virtual Ref<Material> surface_get_material(int p_idx) const;
+ virtual int get_blend_shape_count() const;
+ virtual StringName get_blend_shape_name(int p_index) const;
+ virtual void set_blend_shape_name(int p_index, const StringName &p_name);
+ virtual AABB get_aabb() const;
Vector<Face3> get_faces() const;
Ref<TriangleMesh> generate_triangle_mesh() const;
@@ -153,8 +170,6 @@ public:
Ref<Mesh> create_outline(float p_margin) const;
- virtual AABB get_aabb() const = 0;
-
void set_lightmap_size_hint(const Size2i &p_size);
Size2i get_lightmap_size_hint() const;
void clear_cache() const;
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 9d388d465d..2f1ac7a83a 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -1653,7 +1653,7 @@ void PackedScene::recreate_state() {
#endif
}
-Ref<SceneState> PackedScene::get_state() {
+Ref<SceneState> PackedScene::get_state() const {
return state;
}
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 81b38840d9..96222937d0 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -228,7 +228,7 @@ public:
virtual void set_last_modified_time(uint64_t p_time) override { state->set_last_modified_time(p_time); }
#endif
- Ref<SceneState> get_state();
+ Ref<SceneState> get_state() const;
PackedScene();
};
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 38acd0af0a..781e219f1f 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -36,11 +36,17 @@
*/
void PrimitiveMesh::_update() const {
Array arr;
- arr.resize(RS::ARRAY_MAX);
- _create_mesh_array(arr);
+ if (GDVIRTUAL_CALL(_create_mesh_array, arr)) {
+ ERR_FAIL_COND_MSG(arr.size() != RS::ARRAY_MAX, "_create_mesh_array must return an array of Mesh.ARRAY_MAX elements.");
+ } else {
+ arr.resize(RS::ARRAY_MAX);
+ _create_mesh_array(arr);
+ }
Vector<Vector3> points = arr[RS::ARRAY_VERTEX];
+ ERR_FAIL_COND_MSG(points.size() == 0, "_create_mesh_array must return at least a vertex array.");
+
aabb = AABB();
int pc = points.size();
@@ -210,6 +216,8 @@ void PrimitiveMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
+
+ GDVIRTUAL_BIND(_create_mesh_array);
}
void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 3fc5fd4a16..eef5eb3f7d 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -64,8 +64,9 @@ protected:
static void _bind_methods();
- virtual void _create_mesh_array(Array &p_arr) const = 0;
+ virtual void _create_mesh_array(Array &p_arr) const {}
void _request_update();
+ GDVIRTUAL0RC(Array, _create_mesh_array)
public:
virtual int get_surface_count() const override;
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 5afd424e03..fe52761482 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -34,10 +34,28 @@
#include <limits.h>
+float StyleBox::get_style_margin(Side p_side) const {
+ float ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_style_margin, p_side, ret)) {
+ return ret;
+ }
+ return 0;
+}
bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret)) {
+ return ret;
+ }
+
return true;
}
+void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const {
+ if (GDVIRTUAL_REQUIRED_CALL(_draw, p_canvas_item, p_rect)) {
+ return;
+ }
+}
+
void StyleBox::set_default_margin(Side p_side, float p_value) {
ERR_FAIL_INDEX((int)p_side, 4);
@@ -74,10 +92,19 @@ Point2 StyleBox::get_offset() const {
}
Size2 StyleBox::get_center_size() const {
+ Size2 ret;
+ if (GDVIRTUAL_CALL(_get_center_size, ret)) {
+ return ret;
+ }
+
return Size2();
}
Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const {
+ Rect2 ret;
+ if (GDVIRTUAL_CALL(_get_draw_rect, p_rect, ret)) {
+ return ret;
+ }
return p_rect;
}
@@ -100,6 +127,12 @@ void StyleBox::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_BOTTOM);
+
+ GDVIRTUAL_BIND(_get_style_margin, "side")
+ GDVIRTUAL_BIND(_test_mask, "point", "rect")
+ GDVIRTUAL_BIND(_get_center_size)
+ GDVIRTUAL_BIND(_get_draw_rect, "rect")
+ GDVIRTUAL_BIND(_draw, "to_canvas_item", "rect")
}
StyleBox::StyleBox() {
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 4c41f42293..68ad41b69c 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -44,9 +44,15 @@ class StyleBox : public Resource {
float margin[4];
protected:
- virtual float get_style_margin(Side p_side) const = 0;
+ virtual float get_style_margin(Side p_side) const;
static void _bind_methods();
+ GDVIRTUAL1RC(float, _get_style_margin, Side)
+ GDVIRTUAL2RC(bool, _test_mask, Point2, Rect2)
+ GDVIRTUAL0RC(Size2, _get_center_size)
+ GDVIRTUAL1RC(Rect2, _get_draw_rect, Rect2)
+ GDVIRTUAL2C(_draw, RID, Rect2)
+
public:
virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const;
@@ -56,7 +62,7 @@ public:
virtual Size2 get_center_size() const;
virtual Rect2 get_draw_rect(const Rect2 &p_rect) const;
- virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const = 0;
+ virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const;
CanvasItem *get_current_item_drawn() const;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 0ee0e4b33e..d541284381 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -38,23 +38,61 @@
#include "scene/resources/bit_map.h"
#include "servers/camera/camera_feed.h"
+int Texture2D::get_width() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_width, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+int Texture2D::get_height() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_height, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
Size2 Texture2D::get_size() const {
return Size2(get_width(), get_height());
}
bool Texture2D::is_pixel_opaque(int p_x, int p_y) const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_is_pixel_opaque, p_x, p_y, ret)) {
+ return ret;
+ }
+
+ return true;
+}
+bool Texture2D::has_alpha() const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_has_alpha, ret)) {
+ return ret;
+ }
+
return true;
}
void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
+ if (GDVIRTUAL_CALL(_draw, p_canvas_item, p_pos, p_modulate, p_transpose)) {
+ return;
+ }
RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose);
}
void Texture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
+ if (GDVIRTUAL_CALL(_draw_rect, p_canvas_item, p_rect, p_tile, p_modulate, p_transpose)) {
+ return;
+ }
RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose);
}
void Texture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
+ if (GDVIRTUAL_CALL(_draw_rect_region, p_canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv)) {
+ return;
+ }
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, p_clip_uv);
}
@@ -75,6 +113,15 @@ void Texture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_image"), &Texture2D::get_image);
ADD_GROUP("", "");
+
+ GDVIRTUAL_BIND(_get_width);
+ GDVIRTUAL_BIND(_get_height);
+ GDVIRTUAL_BIND(_is_pixel_opaque, "x", "y");
+ GDVIRTUAL_BIND(_has_alpha);
+
+ GDVIRTUAL_BIND(_draw, "to_canvas_item", "pos", "modulate", "transpose")
+ GDVIRTUAL_BIND(_draw_rect, "to_canvas_item", "rect", "tile", "modulate", "transpose")
+ GDVIRTUAL_BIND(_draw_rect_region, "tp_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
}
Texture2D::Texture2D() {
@@ -293,7 +340,7 @@ ImageTexture::~ImageTexture() {
//////////////////////////////////////////
-Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit) {
+Ref<Image> CompressedTexture2D::load_image_from_file(FileAccess *f, int p_size_limit) {
uint32_t data_format = f->get_32();
uint32_t w = f->get_16();
uint32_t h = f->get_16();
@@ -426,7 +473,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit
return Ref<Image>();
}
-void StreamTexture2D::set_path(const String &p_path, bool p_take_over) {
+void CompressedTexture2D::set_path(const String &p_path, bool p_take_over) {
if (texture.is_valid()) {
RenderingServer::get_singleton()->texture_set_path(texture, p_path);
}
@@ -434,36 +481,36 @@ void StreamTexture2D::set_path(const String &p_path, bool p_take_over) {
Resource::set_path(p_path, p_take_over);
}
-void StreamTexture2D::_requested_3d(void *p_ud) {
- StreamTexture2D *st = (StreamTexture2D *)p_ud;
- Ref<StreamTexture2D> stex(st);
+void CompressedTexture2D::_requested_3d(void *p_ud) {
+ CompressedTexture2D *st = (CompressedTexture2D *)p_ud;
+ Ref<CompressedTexture2D> stex(st);
ERR_FAIL_COND(!request_3d_callback);
request_3d_callback(stex);
}
-void StreamTexture2D::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) {
- StreamTexture2D *st = (StreamTexture2D *)p_ud;
- Ref<StreamTexture2D> stex(st);
+void CompressedTexture2D::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) {
+ CompressedTexture2D *st = (CompressedTexture2D *)p_ud;
+ Ref<CompressedTexture2D> stex(st);
ERR_FAIL_COND(!request_roughness_callback);
request_roughness_callback(stex, p_normal_path, p_roughness_channel);
}
-void StreamTexture2D::_requested_normal(void *p_ud) {
- StreamTexture2D *st = (StreamTexture2D *)p_ud;
- Ref<StreamTexture2D> stex(st);
+void CompressedTexture2D::_requested_normal(void *p_ud) {
+ CompressedTexture2D *st = (CompressedTexture2D *)p_ud;
+ Ref<CompressedTexture2D> stex(st);
ERR_FAIL_COND(!request_normal_callback);
request_normal_callback(stex);
}
-StreamTexture2D::TextureFormatRequestCallback StreamTexture2D::request_3d_callback = nullptr;
-StreamTexture2D::TextureFormatRoughnessRequestCallback StreamTexture2D::request_roughness_callback = nullptr;
-StreamTexture2D::TextureFormatRequestCallback StreamTexture2D::request_normal_callback = nullptr;
+CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_3d_callback = nullptr;
+CompressedTexture2D::TextureFormatRoughnessRequestCallback CompressedTexture2D::request_roughness_callback = nullptr;
+CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_normal_callback = nullptr;
-Image::Format StreamTexture2D::get_format() const {
+Image::Format CompressedTexture2D::get_format() const {
return format;
}
-Error StreamTexture2D::_load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) {
+Error CompressedTexture2D::_load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) {
alpha_cache.unref();
ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER);
@@ -523,7 +570,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &r_width, int &r_hei
return OK;
}
-Error StreamTexture2D::load(const String &p_path) {
+Error CompressedTexture2D::load(const String &p_path) {
int lw, lh;
Ref<Image> image;
image.instantiate();
@@ -590,51 +637,51 @@ Error StreamTexture2D::load(const String &p_path) {
return OK;
}
-String StreamTexture2D::get_load_path() const {
+String CompressedTexture2D::get_load_path() const {
return path_to_file;
}
-int StreamTexture2D::get_width() const {
+int CompressedTexture2D::get_width() const {
return w;
}
-int StreamTexture2D::get_height() const {
+int CompressedTexture2D::get_height() const {
return h;
}
-RID StreamTexture2D::get_rid() const {
+RID CompressedTexture2D::get_rid() const {
if (!texture.is_valid()) {
texture = RS::get_singleton()->texture_2d_placeholder_create();
}
return texture;
}
-void StreamTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
+void CompressedTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
if ((w | h) == 0) {
return;
}
RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose);
}
-void StreamTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
+void CompressedTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
if ((w | h) == 0) {
return;
}
RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);
}
-void StreamTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
+void CompressedTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
if ((w | h) == 0) {
return;
}
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);
}
-bool StreamTexture2D::has_alpha() const {
+bool CompressedTexture2D::has_alpha() const {
return false;
}
-Ref<Image> StreamTexture2D::get_image() const {
+Ref<Image> CompressedTexture2D::get_image() const {
if (texture.is_valid()) {
return RS::get_singleton()->texture_2d_get(texture);
} else {
@@ -642,7 +689,7 @@ Ref<Image> StreamTexture2D::get_image() const {
}
}
-bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const {
+bool CompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
if (!alpha_cache.is_valid()) {
Ref<Image> img = get_image();
if (img.is_valid()) {
@@ -676,7 +723,7 @@ bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const {
return true;
}
-void StreamTexture2D::reload_from_file() {
+void CompressedTexture2D::reload_from_file() {
String path = get_path();
if (!path.is_resource_file()) {
return;
@@ -691,26 +738,26 @@ void StreamTexture2D::reload_from_file() {
load(path);
}
-void StreamTexture2D::_validate_property(PropertyInfo &property) const {
+void CompressedTexture2D::_validate_property(PropertyInfo &property) const {
}
-void StreamTexture2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture2D::load);
- ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture2D::get_load_path);
+void CompressedTexture2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture2D::load);
+ ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture2D::get_load_path);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
}
-StreamTexture2D::StreamTexture2D() {}
+CompressedTexture2D::CompressedTexture2D() {}
-StreamTexture2D::~StreamTexture2D() {
+CompressedTexture2D::~CompressedTexture2D() {
if (texture.is_valid()) {
RS::get_singleton()->free(texture);
}
}
-RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- Ref<StreamTexture2D> st;
+RES ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<CompressedTexture2D> st;
st.instantiate();
Error err = st->load(p_path);
if (r_error) {
@@ -723,24 +770,24 @@ RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String
return st;
}
-void ResourceFormatLoaderStreamTexture2D::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("stex");
+void ResourceFormatLoaderCompressedTexture2D::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("ctex");
}
-bool ResourceFormatLoaderStreamTexture2D::handles_type(const String &p_type) const {
- return p_type == "StreamTexture2D";
+bool ResourceFormatLoaderCompressedTexture2D::handles_type(const String &p_type) const {
+ return p_type == "CompressedTexture2D";
}
-String ResourceFormatLoaderStreamTexture2D::get_resource_type(const String &p_path) const {
- if (p_path.get_extension().to_lower() == "stex") {
- return "StreamTexture2D";
+String ResourceFormatLoaderCompressedTexture2D::get_resource_type(const String &p_path) const {
+ if (p_path.get_extension().to_lower() == "ctex") {
+ return "CompressedTexture2D";
}
return "";
}
////////////////////////////////////
-TypedArray<Image> Texture3D::_get_data() const {
+TypedArray<Image> Texture3D::_get_datai() const {
Vector<Ref<Image>> data = get_data();
TypedArray<Image> ret;
@@ -751,13 +798,73 @@ TypedArray<Image> Texture3D::_get_data() const {
return ret;
}
+Image::Format Texture3D::get_format() const {
+ Image::Format ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_format, ret)) {
+ return ret;
+ }
+ return Image::FORMAT_MAX;
+}
+
+int Texture3D::get_width() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_width, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+int Texture3D::get_height() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_height, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+int Texture3D::get_depth() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_depth, ret)) {
+ return ret;
+ }
+
+ return 0;
+}
+
+bool Texture3D::has_mipmaps() const {
+ bool ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_has_mipmaps, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+Vector<Ref<Image>> Texture3D::get_data() const {
+ TypedArray<Image> ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_data, ret)) {
+ Vector<Ref<Image>> data;
+ data.resize(ret.size());
+ for (int i = 0; i < data.size(); i++) {
+ data.write[i] = ret[i];
+ }
+ return data;
+ }
+ return Vector<Ref<Image>>();
+}
void Texture3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_format"), &Texture3D::get_format);
ClassDB::bind_method(D_METHOD("get_width"), &Texture3D::get_width);
ClassDB::bind_method(D_METHOD("get_height"), &Texture3D::get_height);
ClassDB::bind_method(D_METHOD("get_depth"), &Texture3D::get_depth);
ClassDB::bind_method(D_METHOD("has_mipmaps"), &Texture3D::has_mipmaps);
- ClassDB::bind_method(D_METHOD("get_data"), &Texture3D::_get_data);
+ ClassDB::bind_method(D_METHOD("get_data"), &Texture3D::_get_datai);
+
+ GDVIRTUAL_BIND(_get_format);
+ GDVIRTUAL_BIND(_get_width);
+ GDVIRTUAL_BIND(_get_height);
+ GDVIRTUAL_BIND(_get_depth);
+ GDVIRTUAL_BIND(_has_mipmaps);
+ GDVIRTUAL_BIND(_get_data);
}
//////////////////////////////////////////
@@ -846,7 +953,7 @@ ImageTexture3D::~ImageTexture3D() {
////////////////////////////////////////////
-void StreamTexture3D::set_path(const String &p_path, bool p_take_over) {
+void CompressedTexture3D::set_path(const String &p_path, bool p_take_over) {
if (texture.is_valid()) {
RenderingServer::get_singleton()->texture_set_path(texture, p_path);
}
@@ -854,11 +961,11 @@ void StreamTexture3D::set_path(const String &p_path, bool p_take_over) {
Resource::set_path(p_path, p_take_over);
}
-Image::Format StreamTexture3D::get_format() const {
+Image::Format CompressedTexture3D::get_format() const {
return format;
}
-Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) {
+Error CompressedTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));
@@ -887,7 +994,7 @@ Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_da
r_data.clear();
for (int i = 0; i < (r_depth + mipmaps); i++) {
- Ref<Image> image = StreamTexture2D::load_image_from_file(f, 0);
+ Ref<Image> image = CompressedTexture2D::load_image_from_file(f, 0);
ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);
if (i == 0) {
r_format = image->get_format();
@@ -900,7 +1007,7 @@ Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_da
return OK;
}
-Error StreamTexture3D::load(const String &p_path) {
+Error CompressedTexture3D::load(const String &p_path) {
Vector<Ref<Image>> data;
int tw, th, td;
@@ -937,34 +1044,34 @@ Error StreamTexture3D::load(const String &p_path) {
return OK;
}
-String StreamTexture3D::get_load_path() const {
+String CompressedTexture3D::get_load_path() const {
return path_to_file;
}
-int StreamTexture3D::get_width() const {
+int CompressedTexture3D::get_width() const {
return w;
}
-int StreamTexture3D::get_height() const {
+int CompressedTexture3D::get_height() const {
return h;
}
-int StreamTexture3D::get_depth() const {
+int CompressedTexture3D::get_depth() const {
return d;
}
-bool StreamTexture3D::has_mipmaps() const {
+bool CompressedTexture3D::has_mipmaps() const {
return mipmaps;
}
-RID StreamTexture3D::get_rid() const {
+RID CompressedTexture3D::get_rid() const {
if (!texture.is_valid()) {
texture = RS::get_singleton()->texture_3d_placeholder_create();
}
return texture;
}
-Vector<Ref<Image>> StreamTexture3D::get_data() const {
+Vector<Ref<Image>> CompressedTexture3D::get_data() const {
if (texture.is_valid()) {
return RS::get_singleton()->texture_3d_get(texture);
} else {
@@ -972,7 +1079,7 @@ Vector<Ref<Image>> StreamTexture3D::get_data() const {
}
}
-void StreamTexture3D::reload_from_file() {
+void CompressedTexture3D::reload_from_file() {
String path = get_path();
if (!path.is_resource_file()) {
return;
@@ -987,19 +1094,19 @@ void StreamTexture3D::reload_from_file() {
load(path);
}
-void StreamTexture3D::_validate_property(PropertyInfo &property) const {
+void CompressedTexture3D::_validate_property(PropertyInfo &property) const {
}
-void StreamTexture3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture3D::load);
- ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture3D::get_load_path);
+void CompressedTexture3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture3D::load);
+ ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture3D::get_load_path);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
}
-StreamTexture3D::StreamTexture3D() {}
+CompressedTexture3D::CompressedTexture3D() {}
-StreamTexture3D::~StreamTexture3D() {
+CompressedTexture3D::~CompressedTexture3D() {
if (texture.is_valid()) {
RS::get_singleton()->free(texture);
}
@@ -1007,8 +1114,8 @@ StreamTexture3D::~StreamTexture3D() {
/////////////////////////////
-RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- Ref<StreamTexture3D> st;
+RES ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<CompressedTexture3D> st;
st.instantiate();
Error err = st->load(p_path);
if (r_error) {
@@ -1021,17 +1128,17 @@ RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String
return st;
}
-void ResourceFormatLoaderStreamTexture3D::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceFormatLoaderCompressedTexture3D::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("stex3d");
}
-bool ResourceFormatLoaderStreamTexture3D::handles_type(const String &p_type) const {
- return p_type == "StreamTexture3D";
+bool ResourceFormatLoaderCompressedTexture3D::handles_type(const String &p_type) const {
+ return p_type == "CompressedTexture3D";
}
-String ResourceFormatLoaderStreamTexture3D::get_resource_type(const String &p_path) const {
+String ResourceFormatLoaderCompressedTexture3D::get_resource_type(const String &p_path) const {
if (p_path.get_extension().to_lower() == "stex3d") {
- return "StreamTexture3D";
+ return "CompressedTexture3D";
}
return "";
}
@@ -2446,6 +2553,63 @@ AnimatedTexture::~AnimatedTexture() {
///////////////////////////////
+Image::Format TextureLayered::get_format() const {
+ Image::Format ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_format, ret)) {
+ return ret;
+ }
+ return Image::FORMAT_MAX;
+}
+
+TextureLayered::LayeredType TextureLayered::get_layered_type() const {
+ uint32_t ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_layered_type, ret)) {
+ return (LayeredType)ret;
+ }
+ return LAYERED_TYPE_2D_ARRAY;
+}
+
+int TextureLayered::get_width() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_width, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+int TextureLayered::get_height() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_height, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+int TextureLayered::get_layers() const {
+ int ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_layers, ret)) {
+ return ret;
+ }
+
+ return 0;
+}
+
+bool TextureLayered::has_mipmaps() const {
+ bool ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_has_mipmaps, ret)) {
+ return ret;
+ }
+ return false;
+}
+
+Ref<Image> TextureLayered::get_layer_data(int p_layer) const {
+ Ref<Image> ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_layer_data, p_layer, ret)) {
+ return ret;
+ }
+ return Ref<Image>();
+}
+
void TextureLayered::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format);
ClassDB::bind_method(D_METHOD("get_layered_type"), &TextureLayered::get_layered_type);
@@ -2458,6 +2622,14 @@ void TextureLayered::_bind_methods() {
BIND_ENUM_CONSTANT(LAYERED_TYPE_2D_ARRAY);
BIND_ENUM_CONSTANT(LAYERED_TYPE_CUBEMAP);
BIND_ENUM_CONSTANT(LAYERED_TYPE_CUBEMAP_ARRAY);
+
+ GDVIRTUAL_BIND(_get_format);
+ GDVIRTUAL_BIND(_get_layered_type);
+ GDVIRTUAL_BIND(_get_width);
+ GDVIRTUAL_BIND(_get_height);
+ GDVIRTUAL_BIND(_get_layers);
+ GDVIRTUAL_BIND(_has_mipmaps);
+ GDVIRTUAL_BIND(_get_layer_data, "layer_index");
}
///////////////////////////////
@@ -2599,7 +2771,7 @@ ImageTextureLayered::~ImageTextureLayered() {
///////////////////////////////////////////
-void StreamTextureLayered::set_path(const String &p_path, bool p_take_over) {
+void CompressedTextureLayered::set_path(const String &p_path, bool p_take_over) {
if (texture.is_valid()) {
RenderingServer::get_singleton()->texture_set_path(texture, p_path);
}
@@ -2607,11 +2779,11 @@ void StreamTextureLayered::set_path(const String &p_path, bool p_take_over) {
Resource::set_path(p_path, p_take_over);
}
-Image::Format StreamTextureLayered::get_format() const {
+Image::Format CompressedTextureLayered::get_format() const {
return format;
}
-Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) {
+Error CompressedTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) {
ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER);
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
@@ -2647,7 +2819,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>>
images.resize(layer_count);
for (uint32_t i = 0; i < layer_count; i++) {
- Ref<Image> image = StreamTexture2D::load_image_from_file(f, p_size_limit);
+ Ref<Image> image = CompressedTexture2D::load_image_from_file(f, p_size_limit);
ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);
images.write[i] = image;
}
@@ -2655,7 +2827,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>>
return OK;
}
-Error StreamTextureLayered::load(const String &p_path) {
+Error CompressedTextureLayered::load(const String &p_path) {
Vector<Ref<Image>> images;
int mipmap_limit;
@@ -2690,38 +2862,38 @@ Error StreamTextureLayered::load(const String &p_path) {
return OK;
}
-String StreamTextureLayered::get_load_path() const {
+String CompressedTextureLayered::get_load_path() const {
return path_to_file;
}
-int StreamTextureLayered::get_width() const {
+int CompressedTextureLayered::get_width() const {
return w;
}
-int StreamTextureLayered::get_height() const {
+int CompressedTextureLayered::get_height() const {
return h;
}
-int StreamTextureLayered::get_layers() const {
+int CompressedTextureLayered::get_layers() const {
return layers;
}
-bool StreamTextureLayered::has_mipmaps() const {
+bool CompressedTextureLayered::has_mipmaps() const {
return mipmaps;
}
-TextureLayered::LayeredType StreamTextureLayered::get_layered_type() const {
+TextureLayered::LayeredType CompressedTextureLayered::get_layered_type() const {
return layered_type;
}
-RID StreamTextureLayered::get_rid() const {
+RID CompressedTextureLayered::get_rid() const {
if (!texture.is_valid()) {
texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));
}
return texture;
}
-Ref<Image> StreamTextureLayered::get_layer_data(int p_layer) const {
+Ref<Image> CompressedTextureLayered::get_layer_data(int p_layer) const {
if (texture.is_valid()) {
return RS::get_singleton()->texture_2d_layer_get(texture, p_layer);
} else {
@@ -2729,7 +2901,7 @@ Ref<Image> StreamTextureLayered::get_layer_data(int p_layer) const {
}
}
-void StreamTextureLayered::reload_from_file() {
+void CompressedTextureLayered::reload_from_file() {
String path = get_path();
if (!path.is_resource_file()) {
return;
@@ -2744,21 +2916,21 @@ void StreamTextureLayered::reload_from_file() {
load(path);
}
-void StreamTextureLayered::_validate_property(PropertyInfo &property) const {
+void CompressedTextureLayered::_validate_property(PropertyInfo &property) const {
}
-void StreamTextureLayered::_bind_methods() {
- ClassDB::bind_method(D_METHOD("load", "path"), &StreamTextureLayered::load);
- ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTextureLayered::get_load_path);
+void CompressedTextureLayered::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTextureLayered::load);
+ ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTextureLayered::get_load_path);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");
}
-StreamTextureLayered::StreamTextureLayered(LayeredType p_type) {
+CompressedTextureLayered::CompressedTextureLayered(LayeredType p_type) {
layered_type = p_type;
}
-StreamTextureLayered::~StreamTextureLayered() {
+CompressedTextureLayered::~CompressedTextureLayered() {
if (texture.is_valid()) {
RS::get_singleton()->free(texture);
}
@@ -2766,18 +2938,18 @@ StreamTextureLayered::~StreamTextureLayered() {
/////////////////////////////////////////////////
-RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- Ref<StreamTextureLayered> st;
+RES ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<CompressedTextureLayered> st;
if (p_path.get_extension().to_lower() == "stexarray") {
- Ref<StreamTexture2DArray> s;
+ Ref<CompressedTexture2DArray> s;
s.instantiate();
st = s;
} else if (p_path.get_extension().to_lower() == "scube") {
- Ref<StreamCubemap> s;
+ Ref<CompressedCubemap> s;
s.instantiate();
st = s;
} else if (p_path.get_extension().to_lower() == "scubearray") {
- Ref<StreamCubemapArray> s;
+ Ref<CompressedCubemapArray> s;
s.instantiate();
st = s;
} else {
@@ -2797,25 +2969,25 @@ RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const S
return st;
}
-void ResourceFormatLoaderStreamTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {
+void ResourceFormatLoaderCompressedTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("stexarray");
p_extensions->push_back("scube");
p_extensions->push_back("scubearray");
}
-bool ResourceFormatLoaderStreamTextureLayered::handles_type(const String &p_type) const {
- return p_type == "StreamTexture2DArray" || p_type == "StreamCubemap" || p_type == "StreamCubemapArray";
+bool ResourceFormatLoaderCompressedTextureLayered::handles_type(const String &p_type) const {
+ return p_type == "CompressedTexture2DArray" || p_type == "CompressedCubemap" || p_type == "CompressedCubemapArray";
}
-String ResourceFormatLoaderStreamTextureLayered::get_resource_type(const String &p_path) const {
+String ResourceFormatLoaderCompressedTextureLayered::get_resource_type(const String &p_path) const {
if (p_path.get_extension().to_lower() == "stexarray") {
- return "StreamTexture2DArray";
+ return "CompressedTexture2DArray";
}
if (p_path.get_extension().to_lower() == "scube") {
- return "StreamCubemap";
+ return "CompressedCubemap";
}
if (p_path.get_extension().to_lower() == "scubearray") {
- return "StreamCubemapArray";
+ return "CompressedCubemapArray";
}
return "";
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 8075497c42..1e07b83547 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -57,14 +57,23 @@ class Texture2D : public Texture {
protected:
static void _bind_methods();
+ GDVIRTUAL0RC(int, _get_width)
+ GDVIRTUAL0RC(int, _get_height)
+ GDVIRTUAL2RC(bool, _is_pixel_opaque, int, int)
+ GDVIRTUAL0RC(bool, _has_alpha)
+
+ GDVIRTUAL4C(_draw, RID, Point2, Color, bool)
+ GDVIRTUAL5C(_draw_rect, RID, Rect2, bool, Color, bool)
+ GDVIRTUAL6C(_draw_rect_region, RID, Rect2, Rect2, Color, bool, bool)
+
public:
- virtual int get_width() const = 0;
- virtual int get_height() const = 0;
+ virtual int get_width() const;
+ virtual int get_height() const;
virtual Size2 get_size() const;
virtual bool is_pixel_opaque(int p_x, int p_y) const;
- virtual bool has_alpha() const = 0;
+ virtual bool has_alpha() const;
virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const;
virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const;
@@ -128,8 +137,8 @@ public:
~ImageTexture();
};
-class StreamTexture2D : public Texture2D {
- GDCLASS(StreamTexture2D, Texture2D);
+class CompressedTexture2D : public Texture2D {
+ GDCLASS(CompressedTexture2D, Texture2D);
public:
enum DataFormat {
@@ -174,8 +183,8 @@ protected:
public:
static Ref<Image> load_image_from_file(FileAccess *p_file, int p_size_limit);
- typedef void (*TextureFormatRequestCallback)(const Ref<StreamTexture2D> &);
- typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<StreamTexture2D> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel);
+ typedef void (*TextureFormatRequestCallback)(const Ref<CompressedTexture2D> &);
+ typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<CompressedTexture2D> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel);
static TextureFormatRequestCallback request_3d_callback;
static TextureFormatRoughnessRequestCallback request_roughness_callback;
@@ -200,11 +209,11 @@ public:
virtual Ref<Image> get_image() const override;
- StreamTexture2D();
- ~StreamTexture2D();
+ CompressedTexture2D();
+ ~CompressedTexture2D();
};
-class ResourceFormatLoaderStreamTexture2D : public ResourceFormatLoader {
+class ResourceFormatLoaderCompressedTexture2D : 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, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
@@ -300,6 +309,13 @@ class TextureLayered : public Texture {
protected:
static void _bind_methods();
+ GDVIRTUAL0RC(Image::Format, _get_format)
+ GDVIRTUAL0RC(uint32_t, _get_layered_type)
+ GDVIRTUAL0RC(int, _get_width)
+ GDVIRTUAL0RC(int, _get_height)
+ GDVIRTUAL0RC(int, _get_layers)
+ GDVIRTUAL0RC(bool, _has_mipmaps)
+ GDVIRTUAL1RC(Ref<Image>, _get_layer_data, int)
public:
enum LayeredType {
LAYERED_TYPE_2D_ARRAY,
@@ -307,13 +323,15 @@ public:
LAYERED_TYPE_CUBEMAP_ARRAY
};
- virtual Image::Format get_format() const = 0;
- virtual LayeredType get_layered_type() const = 0;
- virtual int get_width() const = 0;
- virtual int get_height() const = 0;
- virtual int get_layers() const = 0;
- virtual bool has_mipmaps() const = 0;
- virtual Ref<Image> get_layer_data(int p_layer) const = 0;
+ virtual Image::Format get_format() const;
+ virtual LayeredType get_layered_type() const;
+ virtual int get_width() const;
+ virtual int get_height() const;
+ virtual int get_layers() const;
+ virtual bool has_mipmaps() const;
+ virtual Ref<Image> get_layer_data(int p_layer) const;
+
+ TextureLayered() {}
};
VARIANT_ENUM_CAST(TextureLayered::LayeredType)
@@ -380,8 +398,8 @@ public:
ImageTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
};
-class StreamTextureLayered : public TextureLayered {
- GDCLASS(StreamTextureLayered, TextureLayered);
+class CompressedTextureLayered : public TextureLayered {
+ GDCLASS(CompressedTextureLayered, TextureLayered);
public:
enum DataFormat {
@@ -433,34 +451,34 @@ public:
virtual Ref<Image> get_layer_data(int p_layer) const override;
- StreamTextureLayered(LayeredType p_layered_type);
- ~StreamTextureLayered();
+ CompressedTextureLayered(LayeredType p_layered_type);
+ ~CompressedTextureLayered();
};
-class StreamTexture2DArray : public StreamTextureLayered {
- GDCLASS(StreamTexture2DArray, StreamTextureLayered)
+class CompressedTexture2DArray : public CompressedTextureLayered {
+ GDCLASS(CompressedTexture2DArray, CompressedTextureLayered)
public:
- StreamTexture2DArray() :
- StreamTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
+ CompressedTexture2DArray() :
+ CompressedTextureLayered(LAYERED_TYPE_2D_ARRAY) {}
};
-class StreamCubemap : public StreamTextureLayered {
- GDCLASS(StreamCubemap, StreamTextureLayered);
+class CompressedCubemap : public CompressedTextureLayered {
+ GDCLASS(CompressedCubemap, CompressedTextureLayered);
public:
- StreamCubemap() :
- StreamTextureLayered(LAYERED_TYPE_CUBEMAP) {}
+ CompressedCubemap() :
+ CompressedTextureLayered(LAYERED_TYPE_CUBEMAP) {}
};
-class StreamCubemapArray : public StreamTextureLayered {
- GDCLASS(StreamCubemapArray, StreamTextureLayered);
+class CompressedCubemapArray : public CompressedTextureLayered {
+ GDCLASS(CompressedCubemapArray, CompressedTextureLayered);
public:
- StreamCubemapArray() :
- StreamTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
+ CompressedCubemapArray() :
+ CompressedTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {}
};
-class ResourceFormatLoaderStreamTextureLayered : public ResourceFormatLoader {
+class ResourceFormatLoaderCompressedTextureLayered : 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, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
@@ -474,15 +492,21 @@ class Texture3D : public Texture {
protected:
static void _bind_methods();
- TypedArray<Image> _get_data() const;
-
-public:
- virtual Image::Format get_format() const = 0;
- virtual int get_width() const = 0;
- virtual int get_height() const = 0;
- virtual int get_depth() const = 0;
- virtual bool has_mipmaps() const = 0;
- virtual Vector<Ref<Image>> get_data() const = 0;
+ TypedArray<Image> _get_datai() const;
+
+ GDVIRTUAL0RC(Image::Format, _get_format)
+ GDVIRTUAL0RC(int, _get_width)
+ GDVIRTUAL0RC(int, _get_height)
+ GDVIRTUAL0RC(int, _get_depth)
+ GDVIRTUAL0RC(bool, _has_mipmaps)
+ GDVIRTUAL0RC(TypedArray<Image>, _get_data)
+public:
+ virtual Image::Format get_format() const;
+ virtual int get_width() const;
+ virtual int get_height() const;
+ virtual int get_depth() const;
+ virtual bool has_mipmaps() const;
+ virtual Vector<Ref<Image>> get_data() const;
};
class ImageTexture3D : public Texture3D {
@@ -520,8 +544,8 @@ public:
~ImageTexture3D();
};
-class StreamTexture3D : public Texture3D {
- GDCLASS(StreamTexture3D, Texture3D);
+class CompressedTexture3D : public Texture3D {
+ GDCLASS(CompressedTexture3D, Texture3D);
public:
enum DataFormat {
@@ -571,11 +595,11 @@ public:
virtual Vector<Ref<Image>> get_data() const override;
- StreamTexture3D();
- ~StreamTexture3D();
+ CompressedTexture3D();
+ ~CompressedTexture3D();
};
-class ResourceFormatLoaderStreamTexture3D : public ResourceFormatLoader {
+class ResourceFormatLoaderCompressedTexture3D : 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, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 47ca643029..d3e61dbc84 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -455,32 +455,69 @@ String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader::
for (int i = 0; i < get_output_port_count(); i++) {
output_vars.push_back(p_output_vars[i]);
}
- String code = " {\n";
+
String _code;
GDVIRTUAL_CALL(_get_code, input_vars, output_vars, p_mode, p_type, _code);
- bool nend = _code.ends_with("\n");
- _code = _code.insert(0, " ");
- _code = _code.replace("\n", "\n ");
- code += _code;
- if (!nend) {
- code += "\n }";
- } else {
- code.remove_at(code.size() - 1);
- code += "}";
+ if (_is_valid_code(_code)) {
+ String code = " {\n";
+ bool nend = _code.ends_with("\n");
+ _code = _code.insert(0, " ");
+ _code = _code.replace("\n", "\n ");
+ code += _code;
+ if (!nend) {
+ code += "\n }";
+ } else {
+ code.remove_at(code.size() - 1);
+ code += "}";
+ }
+ code += "\n";
+ return code;
}
- code += "\n";
- return code;
+ return String();
}
String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
- String ret;
- if (GDVIRTUAL_CALL(_get_global_code, p_mode, ret)) {
- String code = "// " + get_caption() + "\n";
- code += ret;
- code += "\n";
- return code;
+ String _code;
+ if (GDVIRTUAL_CALL(_get_global_code, p_mode, _code)) {
+ if (_is_valid_code(_code)) {
+ String code = "// " + get_caption() + "\n";
+ code += _code;
+ code += "\n";
+ return code;
+ }
}
- return "";
+ return String();
+}
+
+String VisualShaderNodeCustom::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String _code;
+ if (GDVIRTUAL_CALL(_get_func_code, p_mode, p_type, _code)) {
+ if (_is_valid_code(_code)) {
+ bool nend = _code.ends_with("\n");
+ String code = "// " + get_caption() + "\n";
+ code += " {\n";
+ _code = _code.insert(0, " ");
+ _code = _code.replace("\n", "\n ");
+ code += _code;
+ if (!nend) {
+ code += "\n }";
+ } else {
+ code.remove_at(code.size() - 1);
+ code += "}";
+ }
+ code += "\n";
+ return code;
+ }
+ }
+ return String();
+}
+
+bool VisualShaderNodeCustom::is_available(Shader::Mode p_mode, VisualShader::Type p_type) const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret)) {
+ return ret;
+ }
+ return true;
}
void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) {
@@ -511,6 +548,13 @@ void VisualShaderNodeCustom::_set_input_port_default_value(int p_port, const Var
VisualShaderNode::set_input_port_default_value(p_port, p_value);
}
+bool VisualShaderNodeCustom::_is_valid_code(const String &p_code) const {
+ if (p_code.is_empty() || p_code == "null") {
+ return false;
+ }
+ return true;
+}
+
bool VisualShaderNodeCustom::_is_initialized() {
return is_initialized;
}
@@ -531,8 +575,10 @@ void VisualShaderNodeCustom::_bind_methods() {
GDVIRTUAL_BIND(_get_output_port_type, "port");
GDVIRTUAL_BIND(_get_output_port_name, "port");
GDVIRTUAL_BIND(_get_code, "input_vars", "output_vars", "mode", "type");
+ GDVIRTUAL_BIND(_get_func_code, "mode", "type");
GDVIRTUAL_BIND(_get_global_code, "mode");
GDVIRTUAL_BIND(_is_highend);
+ GDVIRTUAL_BIND(_is_available, "mode", "type");
ClassDB::bind_method(D_METHOD("_set_initialized", "enabled"), &VisualShaderNodeCustom::_set_initialized);
ClassDB::bind_method(D_METHOD("_is_initialized"), &VisualShaderNodeCustom::_is_initialized);
@@ -555,6 +601,72 @@ VisualShader::Type VisualShader::get_shader_type() const {
return current_type;
}
+void VisualShader::add_varying(const String &p_name, VaryingMode p_mode, VaryingType p_type) {
+ ERR_FAIL_COND(!p_name.is_valid_identifier());
+ ERR_FAIL_INDEX((int)p_mode, (int)VARYING_MODE_MAX);
+ ERR_FAIL_INDEX((int)p_type, (int)VARYING_TYPE_MAX);
+ ERR_FAIL_COND(varyings.has(p_name));
+ Varying var = Varying(p_name, p_mode, p_type);
+ varyings[p_name] = var;
+ varyings_list.push_back(var);
+ _queue_update();
+}
+
+void VisualShader::remove_varying(const String &p_name) {
+ ERR_FAIL_COND(!varyings.has(p_name));
+ varyings.erase(p_name);
+ for (List<Varying>::Element *E = varyings_list.front(); E; E = E->next()) {
+ if (E->get().name == p_name) {
+ varyings_list.erase(E);
+ break;
+ }
+ }
+ _queue_update();
+}
+
+bool VisualShader::has_varying(const String &p_name) const {
+ return varyings.has(p_name);
+}
+
+int VisualShader::get_varyings_count() const {
+ return varyings_list.size();
+}
+
+const VisualShader::Varying *VisualShader::get_varying_by_index(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, varyings_list.size(), nullptr);
+ return &varyings_list[p_idx];
+}
+
+void VisualShader::set_varying_mode(const String &p_name, VaryingMode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, (int)VARYING_MODE_MAX);
+ ERR_FAIL_COND(!varyings.has(p_name));
+ if (varyings[p_name].mode == p_mode) {
+ return;
+ }
+ varyings[p_name].mode = p_mode;
+ _queue_update();
+}
+
+VisualShader::VaryingMode VisualShader::get_varying_mode(const String &p_name) {
+ ERR_FAIL_COND_V(!varyings.has(p_name), VARYING_MODE_MAX);
+ return varyings[p_name].mode;
+}
+
+void VisualShader::set_varying_type(const String &p_name, VaryingType p_type) {
+ ERR_FAIL_INDEX((int)p_type, (int)VARYING_TYPE_MAX);
+ ERR_FAIL_COND(!varyings.has(p_name));
+ if (varyings[p_name].type == p_type) {
+ return;
+ }
+ varyings[p_name].type = p_type;
+ _queue_update();
+}
+
+VisualShader::VaryingType VisualShader::get_varying_type(const String &p_name) {
+ ERR_FAIL_COND_V(!varyings.has(p_name), VARYING_TYPE_MAX);
+ return varyings[p_name].type;
+}
+
void VisualShader::set_engine_version(const Dictionary &p_engine_version) {
ERR_FAIL_COND(!p_engine_version.has("major"));
ERR_FAIL_COND(!p_engine_version.has("minor"));
@@ -1072,7 +1184,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
code += "\nvoid fragment() {\n";
Set<int> processed;
- Error err = _write_node(p_type, global_code, global_code_per_node, global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
+ Error err = _write_node(p_type, &global_code, &global_code_per_node, &global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
ERR_FAIL_COND_V(err != OK, String());
switch (node->get_output_port_type(p_port)) {
@@ -1253,6 +1365,16 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
_queue_update();
return true;
+ } else if (name.begins_with("varyings/")) {
+ String var_name = name.get_slicec('/', 1);
+ Varying value = Varying();
+ value.name = var_name;
+ if (value.from_string(p_value) && !varyings.has(var_name)) {
+ varyings[var_name] = value;
+ varyings_list.push_back(value);
+ }
+ _queue_update();
+ return true;
} else if (name.begins_with("nodes/")) {
String typestr = name.get_slicec('/', 1);
Type type = TYPE_VERTEX;
@@ -1317,6 +1439,14 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = 0;
}
return true;
+ } else if (name.begins_with("varyings/")) {
+ String var_name = name.get_slicec('/', 1);
+ if (varyings.has(var_name)) {
+ r_ret = varyings[var_name].to_string();
+ } else {
+ r_ret = String();
+ }
+ return true;
} else if (name.begins_with("nodes/")) {
String typestr = name.get_slicec('/', 1);
Type type = TYPE_VERTEX;
@@ -1411,6 +1541,10 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "flags/" + E->get()));
}
+ for (const KeyValue<String, Varying> &E : varyings) {
+ p_list->push_back(PropertyInfo(Variant::STRING, "varyings/" + E.key));
+ }
+
for (int i = 0; i < TYPE_MAX; i++) {
for (const KeyValue<int, Node> &E : graph[i].nodes) {
String prop_name = "nodes/";
@@ -1435,7 +1569,7 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const {
+Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBuilder *global_code_per_node, Map<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const {
const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;
if (vsnode->is_disabled()) {
@@ -1477,7 +1611,9 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
if (!skip_global) {
Ref<VisualShaderNodeUniform> uniform = vsnode;
if (!uniform.is_valid() || !uniform->is_global_code_generated()) {
- global_code += vsnode->generate_global(get_mode(), type, node);
+ if (global_code) {
+ *global_code += vsnode->generate_global(get_mode(), type, node);
+ }
}
String class_name = vsnode->get_class_name();
@@ -1485,9 +1621,13 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
class_name = vsnode->get_script_instance()->get_script()->get_path();
}
if (!r_classes.has(class_name)) {
- global_code_per_node += vsnode->generate_global_per_node(get_mode(), node);
+ if (global_code_per_node) {
+ *global_code_per_node += vsnode->generate_global_per_node(get_mode(), node);
+ }
for (int i = 0; i < TYPE_MAX; i++) {
- global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
+ if (global_code_per_func) {
+ (*global_code_per_func)[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
+ }
}
r_classes.insert(class_name);
}
@@ -1940,6 +2080,7 @@ void VisualShader::_update_shader() const {
Set<String> used_uniform_names;
List<VisualShaderNodeUniform *> uniforms;
Map<int, List<int>> emitters;
+ Map<int, List<int>> varying_setters;
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
@@ -1964,18 +2105,19 @@ void VisualShader::_update_shader() const {
if (uniform.is_valid()) {
uniforms.push_back(uniform.ptr());
}
+ Ref<VisualShaderNodeVaryingSetter> varying_setter = Object::cast_to<VisualShaderNodeVaryingSetter>(E->get().node.ptr());
+ if (varying_setter.is_valid() && varying_setter->is_input_port_connected(0)) {
+ if (!varying_setters.has(i)) {
+ varying_setters.insert(i, List<int>());
+ }
+ varying_setters[i].push_back(E->key());
+ }
Ref<VisualShaderNodeParticleEmit> emit_particle = Object::cast_to<VisualShaderNodeParticleEmit>(E->get().node.ptr());
if (emit_particle.is_valid()) {
if (!emitters.has(i)) {
emitters.insert(i, List<int>());
}
-
- for (const KeyValue<int, Node> &M : graph[i].nodes) {
- if (M.value.node == emit_particle.ptr()) {
- emitters[i].push_back(M.key);
- break;
- }
- }
+ emitters[i].push_back(E->key());
}
}
}
@@ -1990,6 +2132,36 @@ void VisualShader::_update_shader() const {
}
}
+ if (!varyings.is_empty()) {
+ global_code += "\n// Varyings\n";
+
+ for (const KeyValue<String, Varying> &E : varyings) {
+ global_code += "varying ";
+ switch (E.value.type) {
+ case VaryingType::VARYING_TYPE_FLOAT:
+ global_code += "float ";
+ break;
+ case VaryingType::VARYING_TYPE_VECTOR_2D:
+ global_code += "vec2 ";
+ break;
+ case VaryingType::VARYING_TYPE_VECTOR_3D:
+ global_code += "vec3 ";
+ break;
+ case VaryingType::VARYING_TYPE_COLOR:
+ global_code += "vec4 ";
+ break;
+ case VaryingType::VARYING_TYPE_TRANSFORM:
+ global_code += "mat4 ";
+ break;
+ default:
+ break;
+ }
+ global_code += E.key + ";\n";
+ }
+
+ global_code += "\n";
+ }
+
Map<int, String> code_map;
Set<int> empty_funcs;
@@ -2003,12 +2175,54 @@ void VisualShader::_update_shader() const {
VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
StringBuilder func_code;
+ Set<int> processed;
bool is_empty_func = false;
if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY && shader_mode != Shader::MODE_FOG) {
is_empty_func = true;
}
+ String varying_code;
+ if (shader_mode == Shader::MODE_SPATIAL || shader_mode == Shader::MODE_CANVAS_ITEM) {
+ for (const KeyValue<String, Varying> &E : varyings) {
+ if ((E.value.mode == VARYING_MODE_VERTEX_TO_FRAG_LIGHT && i == TYPE_VERTEX) || (E.value.mode == VARYING_MODE_FRAG_TO_LIGHT && i == TYPE_FRAGMENT)) {
+ bool found = false;
+ for (int key : varying_setters[i]) {
+ Ref<VisualShaderNodeVaryingSetter> setter = Object::cast_to<VisualShaderNodeVaryingSetter>(const_cast<VisualShaderNode *>(graph[i].nodes[key].node.ptr()));
+ if (setter.is_valid() && E.value.name == setter->get_varying_name()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ String code2;
+ switch (E.value.type) {
+ case VaryingType::VARYING_TYPE_FLOAT:
+ code2 += "0.0";
+ break;
+ case VaryingType::VARYING_TYPE_VECTOR_2D:
+ code2 += "vec2(0.0)";
+ break;
+ case VaryingType::VARYING_TYPE_VECTOR_3D:
+ code2 += "vec3(0.0)";
+ break;
+ case VaryingType::VARYING_TYPE_COLOR:
+ code2 += "vec4(0.0)";
+ break;
+ case VaryingType::VARYING_TYPE_TRANSFORM:
+ code2 += "mat4(1.0)";
+ break;
+ default:
+ break;
+ }
+ varying_code += vformat(" %s = %s;\n", E.key, code2);
+ }
+ is_empty_func = false;
+ }
+ }
+ }
+
for (const List<Connection>::Element *E = graph[i].connections.front(); E; E = E->next()) {
ConnectionKey from_key;
from_key.node = E->get().from_node;
@@ -2037,13 +2251,19 @@ void VisualShader::_update_shader() const {
}
insertion_pos.insert(i, code.get_string_length() + func_code.get_string_length());
- Set<int> processed;
- Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
+ Error err = _write_node(Type(i), &global_code, &global_code_per_node, &global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
ERR_FAIL_COND(err != OK);
+ if (varying_setters.has(i)) {
+ for (int &E : varying_setters[i]) {
+ err = _write_node(Type(i), nullptr, nullptr, nullptr, func_code, default_tex_params, input_connections, output_connections, E, processed, false, classes);
+ ERR_FAIL_COND(err != OK);
+ }
+ }
+
if (emitters.has(i)) {
for (int &E : emitters[i]) {
- err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, E, processed, false, classes);
+ err = _write_node(Type(i), &global_code, &global_code_per_node, &global_code_per_func, func_code, default_tex_params, input_connections, output_connections, E, processed, false, classes);
ERR_FAIL_COND(err != OK);
}
}
@@ -2051,6 +2271,7 @@ void VisualShader::_update_shader() const {
if (shader_mode == Shader::MODE_PARTICLES) {
code_map.insert(i, func_code);
} else {
+ func_code += varying_code;
func_code += "}\n";
code += func_code;
}
@@ -2276,6 +2497,10 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset);
+ ClassDB::bind_method(D_METHOD("add_varying", "name", "mode", "type"), &VisualShader::add_varying);
+ ClassDB::bind_method(D_METHOD("remove_varying", "name"), &VisualShader::remove_varying);
+ ClassDB::bind_method(D_METHOD("has_varying", "name"), &VisualShader::has_varying);
+
ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
@@ -2295,6 +2520,17 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(TYPE_FOG);
BIND_ENUM_CONSTANT(TYPE_MAX);
+ BIND_ENUM_CONSTANT(VARYING_MODE_VERTEX_TO_FRAG_LIGHT);
+ BIND_ENUM_CONSTANT(VARYING_MODE_FRAG_TO_LIGHT);
+ BIND_ENUM_CONSTANT(VARYING_MODE_MAX);
+
+ BIND_ENUM_CONSTANT(VARYING_TYPE_FLOAT);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_2D);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_3D);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_COLOR);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_TRANSFORM);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_MAX);
+
BIND_CONSTANT(NODE_ID_INVALID);
BIND_CONSTANT(NODE_ID_OUTPUT);
}
@@ -2327,6 +2563,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
// Node3D, Vertex
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "vertex_id", "VERTEX_ID" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" },
@@ -2348,6 +2585,9 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
// Node3D, Fragment
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" },
@@ -2374,6 +2614,9 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_roughness_texture", "NORMAL_ROUGHNESS_TEXTURE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "depth_texture", "DEPTH_TEXTURE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
// Node3D, Light
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" },
@@ -2384,6 +2627,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light", "LIGHT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_color", "LIGHT_COLOR" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "attenuation", "ATTENUATION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "shadow_attenuation", "SHADOW_ATTENUATION" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "diffuse", "DIFFUSE_LIGHT" },
@@ -2415,6 +2659,8 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "instance_custom", "INSTANCE_CUSTOM.rgb" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "instance_custom_alpha", "INSTANCE_CUSTOM.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "instance_id", "INSTANCE_ID" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "vertex_id", "VERTEX_ID" },
// Canvas Item, Fragment
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" },
@@ -3144,6 +3390,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_view_matrix", "MODELVIEW_MATRIX" },
////////////////////////////////////////////////////////////////////////
// Node3D, Fragment.
@@ -3155,6 +3402,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular", "SPECULAR" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "emission", "EMISSION" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal_map", "NORMAL_MAP" },
@@ -3170,7 +3418,10 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor_threshold", "ALPHA_SCISSOR_THRESHOLD" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_hash_scale", "ALPHA_HASH_SCALE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_aa_edge", "ALPHA_ANTIALIASING_EDGE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "alpha_uv", "ALPHA_TEXTURE_COORDINATE" },
+
////////////////////////////////////////////////////////////////////////
// Node3D, Light.
////////////////////////////////////////////////////////////////////////
@@ -3294,7 +3545,7 @@ bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
}
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
String name = get_input_port_name(p_index);
- return bool(name == "Normal" || name == "Rim" || name == "Alpha Scissor Threshold");
+ return bool(name == "Ao" || name == "Normal" || name == "Rim" || name == "Clearcoat" || name == "Anisotropy" || name == "Subsurf Scatter" || name == "Alpha Scissor Threshold");
}
return false;
}
@@ -4199,3 +4450,299 @@ String VisualShaderNodeGlobalExpression::generate_global(Shader::Mode p_mode, Vi
VisualShaderNodeGlobalExpression::VisualShaderNodeGlobalExpression() {
set_editable(false);
}
+
+////////////// Varying
+
+List<VisualShaderNodeVarying::Varying> varyings;
+
+void VisualShaderNodeVarying::add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) { // static
+ varyings.push_back({ p_name, p_mode, p_type });
+}
+
+void VisualShaderNodeVarying::clear_varyings() { // static
+ varyings.clear();
+}
+
+bool VisualShaderNodeVarying::has_varying(const String &p_name) { // static
+ for (const VisualShaderNodeVarying::Varying &E : varyings) {
+ if (E.name == p_name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int VisualShaderNodeVarying::get_varyings_count() const {
+ return varyings.size();
+}
+
+String VisualShaderNodeVarying::get_varying_name_by_index(int p_idx) const {
+ if (p_idx >= 0 && p_idx < varyings.size()) {
+ return varyings[p_idx].name;
+ }
+ return "";
+}
+
+VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_name(const String &p_name) const {
+ for (int i = 0; i < varyings.size(); i++) {
+ if (varyings[i].name == p_name) {
+ return varyings[i].type;
+ }
+ }
+ return VisualShader::VARYING_TYPE_FLOAT;
+}
+
+VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_index(int p_idx) const {
+ if (p_idx >= 0 && p_idx < varyings.size()) {
+ return varyings[p_idx].type;
+ }
+ return VisualShader::VARYING_TYPE_FLOAT;
+}
+
+VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_name(const String &p_name) const {
+ for (int i = 0; i < varyings.size(); i++) {
+ if (varyings[i].name == p_name) {
+ return varyings[i].mode;
+ }
+ }
+ return VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT;
+}
+
+VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_index(int p_idx) const {
+ if (p_idx >= 0 && p_idx < varyings.size()) {
+ return varyings[p_idx].mode;
+ }
+ return VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT;
+}
+
+VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type_by_index(int p_idx) const {
+ if (p_idx >= 0 && p_idx < varyings.size()) {
+ return get_port_type(varyings[p_idx].type, 0);
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+//////////////
+
+void VisualShaderNodeVarying::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_varying_name", "name"), &VisualShaderNodeVarying::set_varying_name);
+ ClassDB::bind_method(D_METHOD("get_varying_name"), &VisualShaderNodeVarying::get_varying_name);
+
+ ClassDB::bind_method(D_METHOD("set_varying_type", "type"), &VisualShaderNodeVarying::set_varying_type);
+ ClassDB::bind_method(D_METHOD("get_varying_type"), &VisualShaderNodeVarying::get_varying_type);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "varying_name"), "set_varying_name", "get_varying_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Vector,Transform"), "set_varying_type", "get_varying_type");
+}
+
+String VisualShaderNodeVarying::get_type_str() const {
+ switch (varying_type) {
+ case VisualShader::VARYING_TYPE_FLOAT:
+ return "float";
+ case VisualShader::VARYING_TYPE_VECTOR_2D:
+ return "vec2";
+ case VisualShader::VARYING_TYPE_VECTOR_3D:
+ return "vec3";
+ case VisualShader::VARYING_TYPE_COLOR:
+ return "vec4";
+ case VisualShader::VARYING_TYPE_TRANSFORM:
+ return "mat4";
+ default:
+ break;
+ }
+ return "";
+}
+
+VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type(VisualShader::VaryingType p_type, int p_port) const {
+ switch (p_type) {
+ case VisualShader::VARYING_TYPE_VECTOR_2D:
+ return PORT_TYPE_VECTOR_2D;
+ case VisualShader::VARYING_TYPE_VECTOR_3D:
+ return PORT_TYPE_VECTOR_3D;
+ case VisualShader::VARYING_TYPE_COLOR:
+ if (p_port == 1) {
+ break; // scalar
+ }
+ return PORT_TYPE_VECTOR_3D;
+ case VisualShader::VARYING_TYPE_TRANSFORM:
+ return PORT_TYPE_TRANSFORM;
+ default:
+ break;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+void VisualShaderNodeVarying::set_varying_name(String p_varying_name) {
+ if (varying_name == p_varying_name) {
+ return;
+ }
+ varying_name = p_varying_name;
+ emit_changed();
+}
+
+String VisualShaderNodeVarying::get_varying_name() const {
+ return varying_name;
+}
+
+void VisualShaderNodeVarying::set_varying_type(VisualShader::VaryingType p_varying_type) {
+ ERR_FAIL_INDEX(p_varying_type, VisualShader::VARYING_TYPE_MAX);
+ if (varying_type == p_varying_type) {
+ return;
+ }
+ varying_type = p_varying_type;
+ emit_changed();
+}
+
+VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type() const {
+ return varying_type;
+}
+
+VisualShaderNodeVarying::VisualShaderNodeVarying() {
+}
+
+////////////// Varying Setter
+
+String VisualShaderNodeVaryingSetter::get_caption() const {
+ return vformat("VaryingSetter");
+}
+
+int VisualShaderNodeVaryingSetter::get_input_port_count() const {
+ if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
+ return 2;
+ }
+ return 1;
+}
+
+VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_input_port_type(int p_port) const {
+ return get_port_type(varying_type, p_port);
+}
+
+String VisualShaderNodeVaryingSetter::get_input_port_name(int p_port) const {
+ if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
+ if (p_port == 0) {
+ return "color";
+ } else {
+ return "alpha";
+ }
+ }
+ return "";
+}
+
+int VisualShaderNodeVaryingSetter::get_output_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeVaryingSetter::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeVaryingSetter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return vformat("varying %s %s;\n", get_type_str(), varying_name);
+}
+
+String VisualShaderNodeVaryingSetter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ if (varying_name == "[None]") {
+ return code;
+ }
+ if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
+ code += vformat(" %s = vec4(%s, %s);\n", varying_name, p_input_vars[0], p_input_vars[1]);
+ } else {
+ code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]);
+ }
+ return code;
+}
+
+VisualShaderNodeVaryingSetter::VisualShaderNodeVaryingSetter() {
+}
+
+////////////// Varying Getter
+
+String VisualShaderNodeVaryingGetter::get_caption() const {
+ return vformat("VaryingGetter");
+}
+
+int VisualShaderNodeVaryingGetter::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeVaryingGetter::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeVaryingGetter::get_output_port_count() const {
+ if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
+ return 2;
+ }
+ return 1;
+}
+
+VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_output_port_type(int p_port) const {
+ return get_port_type(varying_type, p_port);
+}
+
+String VisualShaderNodeVaryingGetter::get_output_port_name(int p_port) const {
+ if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
+ if (p_port == 0) {
+ return "color";
+ } else {
+ return "alpha";
+ }
+ }
+ return "";
+}
+
+bool VisualShaderNodeVaryingGetter::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String from = varying_name;
+ String from2;
+
+ if (varying_name == "[None]") {
+ switch (varying_type) {
+ case VisualShader::VARYING_TYPE_FLOAT:
+ from = "0.0";
+ break;
+ case VisualShader::VARYING_TYPE_VECTOR_2D:
+ from = "vec2(0.0)";
+ break;
+ case VisualShader::VARYING_TYPE_VECTOR_3D:
+ from = "vec3(0.0)";
+ break;
+ case VisualShader::VARYING_TYPE_COLOR:
+ from = "vec3(0.0)";
+ from2 = "0.0";
+ break;
+ case VisualShader::VARYING_TYPE_TRANSFORM:
+ from = "mat4(1.0)";
+ break;
+ default:
+ break;
+ }
+ } else if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
+ from = varying_name + ".rgb";
+ from2 = varying_name + ".a";
+ }
+
+ if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
+ String code;
+ code += vformat(" %s = %s;\n", p_output_vars[0], from);
+ code += vformat(" %s = %s;\n", p_output_vars[1], from2);
+ return code;
+ }
+ return vformat(" %s = %s;\n", p_output_vars[0], from);
+}
+
+VisualShaderNodeVaryingGetter::VisualShaderNodeVaryingGetter() {
+ varying_name = "[None]";
+}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index d3b5365893..2d4b2852e9 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -73,6 +73,49 @@ public:
List<Ref<Texture2D>> params;
};
+ enum VaryingMode {
+ VARYING_MODE_VERTEX_TO_FRAG_LIGHT,
+ VARYING_MODE_FRAG_TO_LIGHT,
+ VARYING_MODE_MAX,
+ };
+
+ enum VaryingType {
+ VARYING_TYPE_FLOAT,
+ VARYING_TYPE_VECTOR_2D,
+ VARYING_TYPE_VECTOR_3D,
+ VARYING_TYPE_COLOR,
+ VARYING_TYPE_TRANSFORM,
+ VARYING_TYPE_MAX,
+ };
+
+ struct Varying {
+ String name;
+ VaryingMode mode;
+ VaryingType type;
+
+ Varying() {
+ }
+
+ Varying(String p_name, VaryingMode p_mode, VaryingType p_type) :
+ name(p_name), mode(p_mode), type(p_type) {}
+
+ bool from_string(const String &p_str) {
+ Vector<String> arr = p_str.split(",");
+ if (arr.size() != 2) {
+ return false;
+ }
+
+ mode = (VaryingMode)arr[0].to_int();
+ type = (VaryingType)arr[1].to_int();
+
+ return true;
+ }
+
+ String to_string() const {
+ return vformat("%s,%s", itos((int)mode), itos((int)type));
+ }
+ };
+
private:
Type current_type;
@@ -94,14 +137,12 @@ private:
Vector2 graph_offset;
- struct RenderModeEnums {
- Shader::Mode mode = Shader::Mode::MODE_MAX;
- const char *string;
- };
-
HashMap<String, int> modes;
Set<StringName> flags;
+ Map<String, Varying> varyings;
+ List<Varying> varyings_list;
+
mutable SafeFlag dirty;
void _queue_update();
@@ -116,7 +157,7 @@ private:
}
};
- Error _write_node(Type p_type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const;
+ Error _write_node(Type p_type, StringBuilder *global_code, StringBuilder *global_code_per_node, Map<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const;
void _input_type_changed(Type p_type, int p_id);
bool has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const;
@@ -151,6 +192,18 @@ public:
void add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id);
void set_node_position(Type p_type, int p_id, const Vector2 &p_position);
+ void add_varying(const String &p_name, VaryingMode p_mode, VaryingType p_type);
+ void remove_varying(const String &p_name);
+ bool has_varying(const String &p_name) const;
+ int get_varyings_count() const;
+ const Varying *get_varying_by_index(int p_idx) const;
+
+ void set_varying_mode(const String &p_name, VaryingMode p_mode);
+ VaryingMode get_varying_mode(const String &p_name);
+
+ void set_varying_type(const String &p_name, VaryingType p_type);
+ VaryingType get_varying_type(const String &p_name);
+
Vector2 get_node_position(Type p_type, int p_id) const;
Ref<VisualShaderNode> get_node(Type p_type, int p_id) const;
@@ -190,6 +243,8 @@ public:
};
VARIANT_ENUM_CAST(VisualShader::Type)
+VARIANT_ENUM_CAST(VisualShader::VaryingMode)
+VARIANT_ENUM_CAST(VisualShader::VaryingType)
///
///
///
@@ -328,14 +383,20 @@ protected:
GDVIRTUAL1RC(int, _get_output_port_type, int)
GDVIRTUAL1RC(String, _get_output_port_name, int)
GDVIRTUAL4RC(String, _get_code, TypedArray<String>, TypedArray<String>, Shader::Mode, VisualShader::Type)
+ GDVIRTUAL2RC(String, _get_func_code, Shader::Mode, VisualShader::Type)
GDVIRTUAL1RC(String, _get_global_code, Shader::Mode)
GDVIRTUAL0RC(bool, _is_highend)
+ GDVIRTUAL2RC(bool, _is_available, Shader::Mode, VisualShader::Type)
+
+ bool _is_valid_code(const String &p_code) const;
protected:
void _set_input_port_default_value(int p_port, const Variant &p_value);
+ bool is_available(Shader::Mode p_mode, VisualShader::Type p_type) const;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override;
+ virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
static void _bind_methods();
@@ -697,6 +758,103 @@ public:
VisualShaderNodeGlobalExpression();
};
+class VisualShaderNodeVarying : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVarying, VisualShaderNode);
+
+public:
+ struct Varying {
+ String name;
+ VisualShader::VaryingMode mode;
+ VisualShader::VaryingType type;
+ bool assigned = false;
+ };
+
+protected:
+ VisualShader::VaryingType varying_type = VisualShader::VARYING_TYPE_FLOAT;
+ String varying_name = "[None]";
+
+public: // internal
+ static void add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type);
+ static void clear_varyings();
+ static bool has_varying(const String &p_name);
+
+ int get_varyings_count() const;
+ String get_varying_name_by_index(int p_idx) const;
+ VisualShader::VaryingMode get_varying_mode_by_name(const String &p_name) const;
+ VisualShader::VaryingMode get_varying_mode_by_index(int p_idx) const;
+ VisualShader::VaryingType get_varying_type_by_name(const String &p_name) const;
+ VisualShader::VaryingType get_varying_type_by_index(int p_idx) const;
+ PortType get_port_type_by_index(int p_idx) const;
+
+protected:
+ static void _bind_methods();
+
+protected:
+ String get_type_str() const;
+ PortType get_port_type(VisualShader::VaryingType p_type, int p_port) const;
+
+public:
+ virtual String get_caption() const override = 0;
+
+ virtual int get_input_port_count() const override = 0;
+ virtual PortType get_input_port_type(int p_port) const override = 0;
+ virtual String get_input_port_name(int p_port) const override = 0;
+
+ virtual int get_output_port_count() const override = 0;
+ virtual PortType get_output_port_type(int p_port) const override = 0;
+ virtual String get_output_port_name(int p_port) const override = 0;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override = 0;
+
+ void set_varying_name(String p_varying_name);
+ String get_varying_name() const;
+
+ void set_varying_type(VisualShader::VaryingType p_varying_type);
+ VisualShader::VaryingType get_varying_type() const;
+
+ VisualShaderNodeVarying();
+};
+
+class VisualShaderNodeVaryingSetter : public VisualShaderNodeVarying {
+ GDCLASS(VisualShaderNodeVaryingSetter, VisualShaderNodeVarying);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeVaryingSetter();
+};
+
+class VisualShaderNodeVaryingGetter : public VisualShaderNodeVarying {
+ GDCLASS(VisualShaderNodeVaryingGetter, VisualShaderNodeVarying);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+ virtual bool has_output_port_preview(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeVaryingGetter();
+};
+
extern String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name);
#endif // VISUAL_SHADER_H
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index a6aa6d8c49..7b4d7e66d4 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -5696,7 +5696,7 @@ String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port)
String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
String code;
- code += "// TRIPLANAR FUNCTION GLOBAL CODE\n";
+ code += "// " + get_caption() + "\n";
code += " vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {\n";
code += " vec4 samp = vec4(0.0);\n";
code += " samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;\n";
@@ -5719,11 +5719,13 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader:
String code;
if (p_type == VisualShader::TYPE_VERTEX) {
- code += " // TRIPLANAR FUNCTION VERTEX CODE\n";
+ code += "// " + get_caption() + "\n";
+ code += " {\n";
code += " triplanar_power_normal = pow(abs(NORMAL), vec3(triplanar_sharpness));\n";
code += " triplanar_power_normal /= dot(triplanar_power_normal, vec3(1.0));\n";
code += " triplanar_pos = VERTEX * triplanar_scale + triplanar_offset;\n";
code += " triplanar_pos *= vec3(1.0, -1.0, 1.0);\n";
+ code += " }\n";
}
return code;