diff options
Diffstat (limited to 'scene')
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; |