diff options
Diffstat (limited to 'scene/3d')
44 files changed, 285 insertions, 384 deletions
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 95ffbe48c1..2e1b77dfe5 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -259,7 +259,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> if (all_override.is_valid()) { mf.overrides.push_back(all_override); } else { - mf.overrides.push_back(mi->get_surface_material(i)); + mf.overrides.push_back(mi->get_surface_override_material(i)); } } diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 39880db29c..261ff5db55 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -75,6 +75,11 @@ void CollisionObject3D::_notification(int p_what) { } } break; + case NOTIFICATION_PREDELETE: { + if (debug_shape_count > 0) { + _clear_debug_shapes(); + } + } break; } } @@ -116,11 +121,13 @@ void CollisionObject3D::_update_debug_shapes() { for (Set<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) { if (shapes.has(shapedata_idx->get())) { ShapeData &shapedata = shapes[shapedata_idx->get()]; + ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw(); for (int i = 0; i < shapedata.shapes.size(); i++) { - ShapeData::ShapeBase &s = shapedata.shapes.write[i]; + ShapeData::ShapeBase &s = shapes[i]; if (s.debug_shape) { s.debug_shape->queue_delete(); s.debug_shape = nullptr; + --debug_shape_count; } if (s.shape.is_null() || shapedata.disabled) { continue; @@ -133,12 +140,30 @@ void CollisionObject3D::_update_debug_shapes() { add_child(mi); mi->force_update_transform(); s.debug_shape = mi; + ++debug_shape_count; } } } debug_shapes_to_update.clear(); } +void CollisionObject3D::_clear_debug_shapes() { + for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + ShapeData &shapedata = E->get(); + ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw(); + for (int i = 0; i < shapedata.shapes.size(); i++) { + ShapeData::ShapeBase &s = shapes[i]; + if (s.debug_shape) { + s.debug_shape->queue_delete(); + s.debug_shape = nullptr; + --debug_shape_count; + } + } + } + + debug_shape_count = 0; +} + void CollisionObject3D::_update_shape_data(uint32_t p_owner) { if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) { if (debug_shapes_to_update.is_empty()) { @@ -395,17 +420,14 @@ bool CollisionObject3D::get_capture_input_on_drag() const { return capture_input_on_drag; } -String CollisionObject3D::get_configuration_warning() const { - String warning = Node3D::get_configuration_warning(); +TypedArray<String> CollisionObject3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (shapes.is_empty()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."); + warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape.")); } - return warning; + return warnings; } CollisionObject3D::CollisionObject3D() { diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index fe20176984..e2f6cc7500 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -62,6 +62,7 @@ class CollisionObject3D : public Node3D { bool ray_pickable = true; Set<uint32_t> debug_shapes_to_update; + int debug_shape_count = 0; void _update_pickable(); @@ -78,6 +79,7 @@ protected: virtual void _mouse_exit(); void _update_debug_shapes(); + void _clear_debug_shapes(); public: uint32_t create_shape_owner(Object *p_owner); @@ -110,7 +112,7 @@ public: _FORCE_INLINE_ RID get_rid() const { return rid; } - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; CollisionObject3D(); ~CollisionObject3D(); diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index e3e2eb4669..ac715b22b2 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -121,7 +121,7 @@ void CollisionPolygon3D::set_polygon(const Vector<Point2> &p_polygon) { if (parent) { _build_polygon(); } - update_configuration_warning(); + update_configuration_warnings(); update_gizmo(); } @@ -167,24 +167,18 @@ void CollisionPolygon3D::set_margin(real_t p_margin) { } } -String CollisionPolygon3D::get_configuration_warning() const { - String warning = Node3D::get_configuration_warning(); +TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."); + warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape.")); } if (polygon.is_empty()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("An empty CollisionPolygon3D has no effect on collision."); + warnings.push_back(TTR("An empty CollisionPolygon3D has no effect on collision.")); } - return warning; + return warnings; } bool CollisionPolygon3D::_is_editable_3d_polygon() const { diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h index 750751b509..73b8a8e0e3 100644 --- a/scene/3d/collision_polygon_3d.h +++ b/scene/3d/collision_polygon_3d.h @@ -74,7 +74,7 @@ public: real_t get_margin() const; void set_margin(real_t p_margin); - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; CollisionPolygon3D(); }; diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 242d82ab4c..bec87914c0 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -120,34 +120,25 @@ void CollisionShape3D::resource_changed(RES res) { update_gizmo(); } -String CollisionShape3D::get_configuration_warning() const { - String warning = Node3D::get_configuration_warning(); +TypedArray<String> CollisionShape3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."); + warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape.")); } if (!shape.is_valid()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."); + warnings.push_back(TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.")); } if (shape.is_valid() && Object::cast_to<RigidBody3D>(get_parent()) && Object::cast_to<ConcavePolygonShape3D>(*shape) && Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."); + warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.")); } - return warning; + return warnings; } void CollisionShape3D::_bind_methods() { @@ -188,7 +179,7 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) { if (is_inside_tree()) { _shape_changed(); } - update_configuration_warning(); + update_configuration_warnings(); } Ref<Shape3D> CollisionShape3D::get_shape() const { diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h index 5512417f75..56a4ae3039 100644 --- a/scene/3d/collision_shape_3d.h +++ b/scene/3d/collision_shape_3d.h @@ -64,7 +64,7 @@ public: void set_disabled(bool p_disabled); bool is_disabled() const; - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; CollisionShape3D(); ~CollisionShape3D(); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index d22d7ff3ab..780773bb57 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -189,8 +189,8 @@ bool CPUParticles3D::get_fractional_delta() const { return fractional_delta; } -String CPUParticles3D::get_configuration_warning() const { - String warnings = GeometryInstance3D::get_configuration_warning(); +TypedArray<String> CPUParticles3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); bool mesh_found = false; bool anim_material_found = false; @@ -209,18 +209,12 @@ String CPUParticles3D::get_configuration_warning() const { anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES); if (!mesh_found) { - if (warnings != String()) { - warnings += "\n"; - } - warnings += "- " + TTR("Nothing is visible because no mesh has been assigned."); + warnings.push_back(TTR("Nothing is visible because no mesh has been assigned.")); } if (!anim_material_found && (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 || get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) { - if (warnings != String()) { - warnings += "\n"; - } - warnings += "- " + TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."); + warnings.push_back(TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".")); } return warnings; diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 10ac32622d..c073c93c47 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -280,7 +280,7 @@ public: void set_gravity(const Vector3 &p_gravity); Vector3 get_gravity() const; - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; void restart(); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 43f820e5d4..4d7fc29f15 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -343,7 +343,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { pm.local_xform = xf; pm.mesh = mesh; for (int i = 0; i < mesh->get_surface_count(); i++) { - pm.instance_materials.push_back(mi->get_surface_material(i)); + pm.instance_materials.push_back(mi->get_surface_override_material(i)); } pm.override_material = mi->get_material_override(); plot_meshes.push_back(pm); @@ -503,19 +503,15 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const { return Vector<Face3>(); } -String GIProbe::get_configuration_warning() const { - String warning = VisualInstance3D::get_configuration_warning(); +TypedArray<String> GIProbe::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (RenderingServer::get_singleton()->is_low_end()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."); + warnings.push_back(TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.")); } else if (probe_data.is_null()) { - warning += TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI."); + warnings.push_back(TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI.")); } - - return warning; + return warnings; } void GIProbe::_bind_methods() { diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 534b425557..dac7dd3e17 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -165,7 +165,7 @@ public: virtual AABB get_aabb() const override; virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; GIProbe(); ~GIProbe(); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index e2cfc2ed87..a075dcf990 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -115,7 +115,7 @@ void GPUParticles3D::set_process_material(const Ref<Material> &p_material) { } RS::get_singleton()->particles_set_process_material(particles, material_rid); - update_configuration_warning(); + update_configuration_warnings(); } void GPUParticles3D::set_speed_scale(float p_scale) { @@ -208,7 +208,7 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) { RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid); - update_configuration_warning(); + update_configuration_warnings(); } Ref<Mesh> GPUParticles3D::get_draw_pass_mesh(int p_pass) const { @@ -235,13 +235,13 @@ bool GPUParticles3D::get_fractional_delta() const { return fractional_delta; } -String GPUParticles3D::get_configuration_warning() const { +TypedArray<String> GPUParticles3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); + if (RenderingServer::get_singleton()->is_low_end()) { - return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."); + warnings.push_back(TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose.")); } - String warnings = GeometryInstance3D::get_configuration_warning(); - bool meshes_found = false; bool anim_material_found = false; @@ -264,26 +264,17 @@ String GPUParticles3D::get_configuration_warning() const { anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES); if (!meshes_found) { - if (warnings != String()) { - warnings += "\n"; - } - warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes."); + warnings.push_back(TTR("Nothing is visible because meshes have not been assigned to draw passes.")); } if (process_material.is_null()) { - if (warnings != String()) { - warnings += "\n"; - } - warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted."); + warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted.")); } else { const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr()); if (!anim_material_found && process && (process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { - if (warnings != String()) { - warnings += "\n"; - } - warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."); + warnings.push_back(TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".")); } } diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index 0c1a1a510c..b9e2b5ccef 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -125,7 +125,7 @@ public: void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh); Ref<Mesh> get_draw_pass_mesh(int p_pass) const; - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; void set_sub_emitter(const NodePath &p_path); NodePath get_sub_emitter() const; diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index f109640aef..d45749d36b 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -48,7 +48,7 @@ void Light3D::set_param(Param p_param, float p_value) { update_gizmo(); if (p_param == PARAM_SPOT_ANGLE) { - update_configuration_warning(); + update_configuration_warnings(); } } } @@ -63,7 +63,7 @@ void Light3D::set_shadow(bool p_enable) { RS::get_singleton()->light_set_shadow(light, p_enable); if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) { - update_configuration_warning(); + update_configuration_warnings(); } notify_property_list_changed(); @@ -153,7 +153,7 @@ void Light3D::set_projector(const Ref<Texture2D> &p_texture) { projector = p_texture; RID tex_id = projector.is_valid() ? projector->get_rid() : RID(); RS::get_singleton()->light_set_projector(light, tex_id); - update_configuration_warning(); + update_configuration_warnings(); } Ref<Texture2D> Light3D::get_projector() const { @@ -457,17 +457,14 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const { return shadow_mode; } -String OmniLight3D::get_configuration_warning() const { - String warning = Light3D::get_configuration_warning(); +TypedArray<String> OmniLight3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (!has_shadow() && get_projector().is_valid()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("Projector texture only works with shadows active."); + warnings.push_back(TTR("Projector texture only works with shadows active.")); } - return warning; + return warnings; } void OmniLight3D::_bind_methods() { @@ -491,24 +488,18 @@ OmniLight3D::OmniLight3D() : set_param(PARAM_SHADOW_NORMAL_BIAS, 2.0); } -String SpotLight3D::get_configuration_warning() const { - String warning = Light3D::get_configuration_warning(); +TypedArray<String> SpotLight3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."); + warnings.push_back(TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.")); } if (!has_shadow() && get_projector().is_valid()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("Projector texture only works with shadows active."); + warnings.push_back(TTR("Projector texture only works with shadows active.")); } - return warning; + return warnings; } void SpotLight3D::_bind_methods() { diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 311db54bce..e145b08b74 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -202,7 +202,7 @@ public: void set_shadow_mode(ShadowMode p_mode); ShadowMode get_shadow_mode() const; - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; OmniLight3D(); }; @@ -216,7 +216,7 @@ protected: static void _bind_methods(); public: - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; SpotLight3D() : Light3D(RenderingServer::LIGHT_SPOT) {} diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index b997c64b29..7623ede0fc 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -51,13 +51,13 @@ bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) { return true; } - if (p_name.operator String().begins_with("material/")) { + if (p_name.operator String().begins_with("surface_material_override/")) { int idx = p_name.operator String().get_slicec('/', 1).to_int(); - if (idx >= materials.size() || idx < 0) { + if (idx >= surface_override_materials.size() || idx < 0) { return false; } - set_surface_material(idx, p_value); + set_surface_override_material(idx, p_value); return true; } @@ -75,12 +75,12 @@ bool MeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const { return true; } - if (p_name.operator String().begins_with("material/")) { + if (p_name.operator String().begins_with("surface_material_override/")) { int idx = p_name.operator String().get_slicec('/', 1).to_int(); - if (idx >= materials.size() || idx < 0) { + if (idx >= surface_override_materials.size() || idx < 0) { return false; } - r_ret = materials[idx]; + r_ret = surface_override_materials[idx]; return true; } return false; @@ -100,7 +100,7 @@ void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const { if (mesh.is_valid()) { for (int i = 0; i < mesh->get_surface_count(); i++) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_material_override/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE)); } } } @@ -126,7 +126,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) { } mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed)); - materials.resize(mesh->get_surface_count()); + surface_override_materials.resize(mesh->get_surface_count()); set_base(mesh->get_rid()); } else { @@ -277,26 +277,26 @@ void MeshInstance3D::_notification(int p_what) { } } -int MeshInstance3D::get_surface_material_count() const { - return materials.size(); +int MeshInstance3D::get_surface_override_material_count() const { + return surface_override_materials.size(); } -void MeshInstance3D::set_surface_material(int p_surface, const Ref<Material> &p_material) { - ERR_FAIL_INDEX(p_surface, materials.size()); +void MeshInstance3D::set_surface_override_material(int p_surface, const Ref<Material> &p_material) { + ERR_FAIL_INDEX(p_surface, surface_override_materials.size()); - materials.write[p_surface] = p_material; + surface_override_materials.write[p_surface] = p_material; - if (materials[p_surface].is_valid()) { - RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid()); + if (surface_override_materials[p_surface].is_valid()) { + RS::get_singleton()->instance_set_surface_override_material(get_instance(), p_surface, surface_override_materials[p_surface]->get_rid()); } else { - RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, RID()); + RS::get_singleton()->instance_set_surface_override_material(get_instance(), p_surface, RID()); } } -Ref<Material> MeshInstance3D::get_surface_material(int p_surface) const { - ERR_FAIL_INDEX_V(p_surface, materials.size(), Ref<Material>()); +Ref<Material> MeshInstance3D::get_surface_override_material(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surface_override_materials.size(), Ref<Material>()); - return materials[p_surface]; + return surface_override_materials[p_surface]; } Ref<Material> MeshInstance3D::get_active_material(int p_surface) const { @@ -305,7 +305,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const { return material_override; } - Ref<Material> surface_material = get_surface_material(p_surface); + Ref<Material> surface_material = get_surface_override_material(p_surface); if (surface_material.is_valid()) { return surface_material; } @@ -320,7 +320,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const { void MeshInstance3D::_mesh_changed() { ERR_FAIL_COND(mesh.is_null()); - materials.resize(mesh->get_surface_count()); + surface_override_materials.resize(mesh->get_surface_count()); } void MeshInstance3D::create_debug_tangents() { @@ -408,9 +408,9 @@ void MeshInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance3D::set_skin); ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance3D::get_skin); - ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance3D::get_surface_material_count); - ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance3D::set_surface_material); - ClassDB::bind_method(D_METHOD("get_surface_material", "surface"), &MeshInstance3D::get_surface_material); + ClassDB::bind_method(D_METHOD("get_surface_override_material_count"), &MeshInstance3D::get_surface_override_material_count); + ClassDB::bind_method(D_METHOD("set_surface_override_material", "surface", "material"), &MeshInstance3D::set_surface_override_material); + ClassDB::bind_method(D_METHOD("get_surface_override_material", "surface"), &MeshInstance3D::get_surface_override_material); ClassDB::bind_method(D_METHOD("get_active_material", "surface"), &MeshInstance3D::get_active_material); ClassDB::bind_method(D_METHOD("create_trimesh_collision"), &MeshInstance3D::create_trimesh_collision); diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h index eb300784b1..8aec227337 100644 --- a/scene/3d/mesh_instance_3d.h +++ b/scene/3d/mesh_instance_3d.h @@ -52,7 +52,7 @@ protected: }; Map<StringName, BlendShapeTrack> blend_shape_tracks; - Vector<Ref<Material>> materials; + Vector<Ref<Material>> surface_override_materials; void _mesh_changed(); void _resolve_skeleton_path(); @@ -75,9 +75,9 @@ public: void set_skeleton_path(const NodePath &p_skeleton); NodePath get_skeleton_path(); - int get_surface_material_count() const; - void set_surface_material(int p_surface, const Ref<Material> &p_material); - Ref<Material> get_surface_material(int p_surface) const; + int get_surface_override_material_count() const; + void set_surface_override_material(int p_surface, const Ref<Material> &p_material); + Ref<Material> get_surface_override_material(int p_surface) const; Ref<Material> get_active_material(int p_surface) const; Node *create_trimesh_collision_node(); diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 21ca3d70dd..7346f243ba 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -245,17 +245,14 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) { emit_signal("velocity_computed", p_new_velocity); } -String NavigationAgent3D::get_configuration_warning() const { - String warning = Node::get_configuration_warning(); +TypedArray<String> NavigationAgent3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<Node3D>(get_parent())) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("The NavigationAgent3D can be used only under a spatial node."); + warnings.push_back(TTR("The NavigationAgent3D can be used only under a spatial node.")); } - return warning; + return warnings; } void NavigationAgent3D::update_navigation() { diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index 22db889618..814c0714e8 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -143,7 +143,7 @@ public: void set_velocity(Vector3 p_velocity); void _avoidance_done(Vector3 p_new_velocity); - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; private: void update_navigation(); diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index df03bca4fd..20ffc3b00e 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -76,17 +76,14 @@ NavigationObstacle3D::~NavigationObstacle3D() { agent = RID(); // Pointless } -String NavigationObstacle3D::get_configuration_warning() const { - String warning = Node::get_configuration_warning(); +TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); - if (!parent_node3d) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."); + if (!Object::cast_to<Node3D>(get_parent())) { + warnings.push_back(TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.")); } - return warning; + return warnings; } void NavigationObstacle3D::update_agent_shape() { diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h index b1bb53724a..2f78f624a4 100644 --- a/scene/3d/navigation_obstacle_3d.h +++ b/scene/3d/navigation_obstacle_3d.h @@ -52,7 +52,7 @@ public: return agent; } - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; private: void update_agent_shape(); diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 3ca704e4b8..0afad62404 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -135,7 +135,7 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes emit_signal("navigation_mesh_changed"); update_gizmo(); - update_configuration_warning(); + update_configuration_warnings(); } Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const { @@ -177,21 +177,16 @@ void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) { emit_signal("bake_finished"); } -String NavigationRegion3D::get_configuration_warning() const { - if (!is_visible_in_tree() || !is_inside_tree()) { - return String(); - } - - String warning = Node3D::get_configuration_warning(); +TypedArray<String> NavigationRegion3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); - if (!navmesh.is_valid()) { - if (!warning.is_empty()) { - warning += "\n\n"; + if (is_visible_in_tree() && is_inside_tree()) { + if (!navmesh.is_valid()) { + warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work.")); } - warning += TTR("A NavigationMesh resource must be set or created for this node to work."); } - return warning; + return warnings; } void NavigationRegion3D::_bind_methods() { @@ -217,7 +212,7 @@ void NavigationRegion3D::_bind_methods() { void NavigationRegion3D::_navigation_changed() { update_gizmo(); - update_configuration_warning(); + update_configuration_warnings(); } NavigationRegion3D::NavigationRegion3D() { diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 52fa2d6159..c2045215b1 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -66,7 +66,7 @@ public: void bake_navigation_mesh(); void _bake_finished(Ref<NavigationMesh> p_nav_mesh); - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; NavigationRegion3D(); ~NavigationRegion3D(); diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 7e2601902b..4ec4ee6207 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -50,7 +50,7 @@ void Path3D::_curve_changed() { for (int i = 0; i < get_child_count(); i++) { PathFollow3D *child = Object::cast_to<PathFollow3D>(get_child(i)); if (child) { - child->update_configuration_warning(); + child->update_configuration_warnings(); } } } @@ -241,29 +241,21 @@ void PathFollow3D::_validate_property(PropertyInfo &property) const { } } -String PathFollow3D::get_configuration_warning() const { - if (!is_visible_in_tree() || !is_inside_tree()) { - return String(); - } - - String warning = Node3D::get_configuration_warning(); +TypedArray<String> PathFollow3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); - if (!Object::cast_to<Path3D>(get_parent())) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("PathFollow3D only works when set as a child of a Path3D node."); - } else { - Path3D *path = Object::cast_to<Path3D>(get_parent()); - if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) { - if (!warning.is_empty()) { - warning += "\n\n"; + if (is_visible_in_tree() && is_inside_tree()) { + if (!Object::cast_to<Path3D>(get_parent())) { + warnings.push_back(TTR("PathFollow3D only works when set as a child of a Path3D node.")); + } else { + Path3D *path = Object::cast_to<Path3D>(get_parent()); + if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) { + warnings.push_back(TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.")); } - warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."); } } - return warning; + return warnings; } void PathFollow3D::_bind_methods() { @@ -368,7 +360,7 @@ float PathFollow3D::get_unit_offset() const { void PathFollow3D::set_rotation_mode(RotationMode p_rotation_mode) { rotation_mode = p_rotation_mode; - update_configuration_warning(); + update_configuration_warnings(); _update_transform(); } diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index 17ee47593e..8545370a4a 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -104,7 +104,7 @@ public: void set_cubic_interpolation(bool p_enable); bool get_cubic_interpolation() const; - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; PathFollow3D() {} }; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index e225c1f22d..2afbebdacc 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -444,7 +444,7 @@ void RigidBody3D::_notification(int p_what) { if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warning(); + update_configuration_warnings(); } } @@ -469,7 +469,7 @@ void RigidBody3D::set_mode(Mode p_mode) { PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC); } break; } - update_configuration_warning(); + update_configuration_warnings(); } RigidBody3D::Mode RigidBody3D::get_mode() const { @@ -709,19 +709,16 @@ Array RigidBody3D::get_colliding_bodies() const { return ret; } -String RigidBody3D::get_configuration_warning() const { +TypedArray<String> RigidBody3D::get_configuration_warnings() const { Transform t = get_transform(); - String warning = CollisionObject3D::get_configuration_warning(); + TypedArray<String> warnings = Node::get_configuration_warnings(); if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); + warnings.push_back(TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); } - return warning; + return warnings; } void RigidBody3D::_bind_methods() { diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 1450fce6a6..9515b044ab 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -238,7 +238,7 @@ public: void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); void apply_torque_impulse(const Vector3 &p_impulse); - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; RigidBody3D(); ~RigidBody3D(); diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp index de9c75621b..3d58d1c10e 100644 --- a/scene/3d/physics_joint_3d.cpp +++ b/scene/3d/physics_joint_3d.cpp @@ -65,6 +65,7 @@ void Joint3D::_update_joint(bool p_only_free) { if (p_only_free || !is_inside_tree()) { PhysicsServer3D::get_singleton()->joint_clear(joint); warning = String(); + update_configuration_warnings(); return; } @@ -75,43 +76,26 @@ void Joint3D::_update_joint(bool p_only_free) { PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b); if (node_a && !body_a && node_b && !body_b) { - PhysicsServer3D::get_singleton()->joint_clear(joint); warning = TTR("Node A and Node B must be PhysicsBody3Ds"); - update_configuration_warning(); - return; - } - - if (node_a && !body_a) { - PhysicsServer3D::get_singleton()->joint_clear(joint); + } else if (node_a && !body_a) { warning = TTR("Node A must be a PhysicsBody3D"); - update_configuration_warning(); - return; - } - - if (node_b && !body_b) { - PhysicsServer3D::get_singleton()->joint_clear(joint); + } else if (node_b && !body_b) { warning = TTR("Node B must be a PhysicsBody3D"); - update_configuration_warning(); - return; - } - - if (!body_a && !body_b) { - PhysicsServer3D::get_singleton()->joint_clear(joint); + } else if (!body_a && !body_b) { warning = TTR("Joint is not connected to any PhysicsBody3Ds"); - update_configuration_warning(); - return; + } else if (body_a == body_b) { + warning = TTR("Node A and Node B must be different PhysicsBody3Ds"); + } else { + warning = String(); } - if (body_a == body_b) { + update_configuration_warnings(); + + if (!warning.is_empty()) { PhysicsServer3D::get_singleton()->joint_clear(joint); - warning = TTR("Node A and Node B must be different PhysicsBody3Ds"); - update_configuration_warning(); return; } - warning = String(); - update_configuration_warning(); - configured = true; if (body_a) { @@ -206,17 +190,14 @@ bool Joint3D::get_exclude_nodes_from_collision() const { return exclude_from_collision; } -String Joint3D::get_configuration_warning() const { - String node_warning = Node3D::get_configuration_warning(); +TypedArray<String> Joint3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node3D::get_configuration_warnings(); if (!warning.is_empty()) { - if (!node_warning.is_empty()) { - node_warning += "\n\n"; - } - node_warning += warning; + warnings.push_back(warning); } - return node_warning; + return warnings; } void Joint3D::_bind_methods() { diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h index f624ba602b..3e0ea38a5c 100644 --- a/scene/3d/physics_joint_3d.h +++ b/scene/3d/physics_joint_3d.h @@ -63,7 +63,7 @@ protected: _FORCE_INLINE_ bool is_configured() const { return configured; } public: - virtual String get_configuration_warning() const override; + virtual TypedArray<String> get_configuration_warnings() const override; void set_node_a(const NodePath &p_node_a); NodePath get_node_a() const; diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp index 83ac813c53..29a407905b 100644 --- a/scene/3d/remote_transform_3d.cpp +++ b/scene/3d/remote_transform_3d.cpp @@ -133,7 +133,7 @@ void RemoteTransform3D::set_remote_node(const NodePath &p_remote_node) { _update_remote(); } - update_configuration_warning(); + update_configuration_warnings(); } NodePath RemoteTransform3D::get_remote_node() const { @@ -179,17 +179,14 @@ void RemoteTransform3D::force_update_cache() { _update_cache(); } -String RemoteTransform3D::get_configuration_warning() const { - String warning = Node3D::get_configuration_warning(); +TypedArray<String> RemoteTransform3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."); + warnings.push_back(TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.")); } - return warning; + return warnings; } void RemoteTransform3D::_bind_methods() { diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h index 21005d92d1..321bd3b51e 100644 --- a/scene/3d/remote_transform_3d.h +++ b/scene/3d/remote_transform_3d.h @@ -70,7 +70,7 @@ public: void force_update_cache(); - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; RemoteTransform3D(); }; diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index be62fe801f..db5fc7593e 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -439,6 +439,17 @@ String Skeleton3D::get_bone_name(int p_bone) const { return bones[p_bone].name; } +void Skeleton3D::set_bone_name(int p_bone, const String &p_name) { + ERR_FAIL_INDEX(p_bone, bones.size()); + + for (int i = 0; i < bones.size(); i++) { + if (i != p_bone) { + ERR_FAIL_COND(bones[i].name == p_name); + } + } + + bones.write[p_bone].name = p_name; +} bool Skeleton3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const { int parent_of_bone = get_bone_parent(p_bone); @@ -869,6 +880,7 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton3D::add_bone); ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton3D::find_bone); ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &Skeleton3D::get_bone_name); + ClassDB::bind_method(D_METHOD("set_bone_name", "bone_idx", "name"), &Skeleton3D::set_bone_name); ClassDB::bind_method(D_METHOD("get_bone_parent", "bone_idx"), &Skeleton3D::get_bone_parent); ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "parent_idx"), &Skeleton3D::set_bone_parent); diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 9772bfcc95..2941ac2c45 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -143,6 +143,7 @@ public: void add_bone(const String &p_name); int find_bone(const String &p_name) const; String get_bone_name(int p_bone) const; + void set_bone_name(int p_bone, const String &p_name); bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const; diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index 3fde4d6ef3..98ac6aa65e 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -249,7 +249,7 @@ void SoftBody3D::_softbody_changed() { prepare_physics_server(); _reset_points_offsets(); #ifdef TOOLS_ENABLED - update_configuration_warning(); + update_configuration_warnings(); #endif } @@ -301,7 +301,7 @@ void SoftBody3D::_notification(int p_what) { if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warning(); + update_configuration_warnings(); } } @@ -366,27 +366,19 @@ void SoftBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable"); } -String SoftBody3D::get_configuration_warning() const { - String warning = MeshInstance3D::get_configuration_warning(); +TypedArray<String> SoftBody3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (get_mesh().is_null()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - - warning += TTR("This body will be ignored until you set a mesh."); + warnings.push_back(TTR("This body will be ignored until you set a mesh.")); } Transform t = get_transform(); if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - - warning += TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); + warnings.push_back(TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); } - return warning; + return warnings; } void SoftBody3D::_update_physics_server() { @@ -460,7 +452,7 @@ void SoftBody3D::become_mesh_owner() { mesh_owner = true; Vector<Ref<Material>> copy_materials; - copy_materials.append_array(materials); + copy_materials.append_array(surface_override_materials); ERR_FAIL_COND(!mesh->get_surface_count()); @@ -480,7 +472,7 @@ void SoftBody3D::become_mesh_owner() { set_mesh(soft_mesh); for (int i = copy_materials.size() - 1; 0 <= i; --i) { - set_surface_material(i, copy_materials[i]); + set_surface_override_material(i, copy_materials[i]); } } } diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h index f98df39209..0d0d39d48f 100644 --- a/scene/3d/soft_body_3d.h +++ b/scene/3d/soft_body_3d.h @@ -113,7 +113,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; protected: void _update_physics_server(); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 0be54e7243..33b8b488c6 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -928,7 +928,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { notify_property_list_changed(); _reset_timeout(); _queue_update(); - update_configuration_warning(); + update_configuration_warnings(); } Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const { @@ -1058,17 +1058,14 @@ StringName AnimatedSprite3D::get_animation() const { return animation; } -String AnimatedSprite3D::get_configuration_warning() const { - String warning = SpriteBase3D::get_configuration_warning(); +TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (frames.is_null()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."); + warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.")); } - return warning; + return warnings; } void AnimatedSprite3D::_bind_methods() { diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index b48660eb2d..5e47e66bcb 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -203,8 +203,8 @@ class AnimatedSprite3D : public SpriteBase3D { float timeout = 0.0; - bool hflip = 1; - bool vflip = 1; + bool hflip = true; + bool vflip = true; Color modulate; @@ -236,7 +236,7 @@ public: virtual Rect2 get_item_rect() const override; - virtual String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; AnimatedSprite3D(); }; diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index 5b0b3b89d3..edd58347f0 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -102,17 +102,14 @@ void VehicleWheel3D::_notification(int p_what) { } } -String VehicleWheel3D::get_configuration_warning() const { - String warning = Node3D::get_configuration_warning(); +TypedArray<String> VehicleWheel3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<VehicleBody3D>(get_parent())) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."); + warnings.push_back(TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D.")); } - return warning; + return warnings; } void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) { diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h index 860fa7e3b7..646071a363 100644 --- a/scene/3d/vehicle_body_3d.h +++ b/scene/3d/vehicle_body_3d.h @@ -145,7 +145,7 @@ public: void set_steering(real_t p_steering); real_t get_steering() const; - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; VehicleWheel3D(); }; diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index 16718b956f..1b9ce0201f 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -344,7 +344,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material Ref<Image> img_albedo; if (albedo_tex.is_valid()) { - img_albedo = albedo_tex->get_data(); + img_albedo = albedo_tex->get_image(); mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative } else { mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive @@ -358,7 +358,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material Ref<Image> img_emission; if (emission_tex.is_valid()) { - img_emission = emission_tex->get_data(); + img_emission = emission_tex->get_image(); } if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) { diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index 214ffd6bd5..829ecc5ec2 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -65,7 +65,7 @@ void WorldEnvironment::_update_current_environment() { } else { get_viewport()->find_world_3d()->set_environment(Ref<Environment>()); } - get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warning"); + get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings"); } void WorldEnvironment::_update_current_camera_effects() { @@ -76,7 +76,7 @@ void WorldEnvironment::_update_current_camera_effects() { get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>()); } - get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warning"); + get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings"); } void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) { @@ -96,7 +96,7 @@ void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) { if (is_inside_tree()) { _update_current_environment(); } else { - update_configuration_warning(); + update_configuration_warnings(); } } @@ -121,7 +121,7 @@ void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_eff if (is_inside_tree()) { _update_current_camera_effects(); } else { - update_configuration_warning(); + update_configuration_warnings(); } } @@ -129,35 +129,26 @@ Ref<CameraEffects> WorldEnvironment::get_camera_effects() const { return camera_effects; } -String WorldEnvironment::get_configuration_warning() const { - String warning = Node::get_configuration_warning(); +TypedArray<String> WorldEnvironment::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); if (!environment.is_valid()) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."); + warnings.push_back(TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.")); } if (!is_inside_tree()) { - return warning; + return warnings; } if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() != environment) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("Only the first Environment has an effect in a scene (or set of instantiated scenes)."); + warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes).")); } if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("Only the first CameraEffects has an effect in a scene (or set of instantiated scenes)."); + warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).")); } - return warning; + return warnings; } void WorldEnvironment::_bind_methods() { diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h index e3f28d6d6b..9e85982381 100644 --- a/scene/3d/world_environment.h +++ b/scene/3d/world_environment.h @@ -55,7 +55,7 @@ public: void set_camera_effects(const Ref<CameraEffects> &p_camera_effects); Ref<CameraEffects> get_camera_effects() const; - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; WorldEnvironment(); }; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 7fed34c7c6..b5037f9be7 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -55,23 +55,18 @@ void XRCamera3D::_notification(int p_what) { }; }; -String XRCamera3D::get_configuration_warning() const { - if (!is_visible() || !is_inside_tree()) { - return String(); +TypedArray<String> XRCamera3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); + + if (is_visible() && is_inside_tree()) { + // must be child node of XROrigin3D! + XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); + if (origin == nullptr) { + warnings.push_back(TTR("XRCamera3D must have an XROrigin3D node as its parent.")); + }; } - String warning = Camera3D::get_configuration_warning(); - - // must be child node of XROrigin3D! - XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); - if (origin == nullptr) { - if (!warning.is_empty()) { - warning += "\n\n"; - } - warning += TTR("XRCamera3D must have an XROrigin3D node as its parent."); - }; - - return warning; + return warnings; }; Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const { @@ -190,8 +185,8 @@ void XRController3D::_notification(int p_what) { ERR_FAIL_NULL(xr_server); // find the tracker for our controller - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); - if (tracker == nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); + if (!tracker.is_valid()) { // this controller is currently turned off is_active = false; button_states = 0; @@ -265,7 +260,7 @@ void XRController3D::set_controller_id(int p_controller_id) { // We don't check any bounds here, this controller may not yet be active and just be a place holder until it is. // Note that setting this to 0 means this node is not bound to a controller yet. controller_id = p_controller_id; - update_configuration_warning(); + update_configuration_warnings(); }; int XRController3D::get_controller_id() const { @@ -277,8 +272,8 @@ String XRController3D::get_controller_name() const { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, String()); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); - if (tracker == nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); + if (!tracker.is_valid()) { return String("Not connected"); }; @@ -290,8 +285,8 @@ int XRController3D::get_joystick_id() const { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, 0); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); - if (tracker == nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); + if (!tracker.is_valid()) { // No tracker? no joystick id... (0 is our first joystick) return -1; }; @@ -322,8 +317,8 @@ real_t XRController3D::get_rumble() const { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, 0.0); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); - if (tracker == nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); + if (!tracker.is_valid()) { return 0.0; }; @@ -335,8 +330,8 @@ void XRController3D::set_rumble(real_t p_rumble) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); - if (tracker != nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); + if (tracker.is_valid()) { tracker->set_rumble(p_rumble); }; }; @@ -354,38 +349,30 @@ XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, XRPositionalTracker::TRACKER_HAND_UNKNOWN); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); - if (tracker == nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id); + if (!tracker.is_valid()) { return XRPositionalTracker::TRACKER_HAND_UNKNOWN; }; return tracker->get_tracker_hand(); }; -String XRController3D::get_configuration_warning() const { - if (!is_visible() || !is_inside_tree()) { - return String(); - } - - String warning = Node3D::get_configuration_warning(); +TypedArray<String> XRController3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); - // must be child node of XROrigin! - XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); - if (origin == nullptr) { - if (!warning.is_empty()) { - warning += "\n\n"; + if (is_visible() && is_inside_tree()) { + // must be child node of XROrigin! + XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); + if (origin == nullptr) { + warnings.push_back(TTR("XRController3D must have an XROrigin3D node as its parent.")); } - warning += TTR("XRController3D must have an XROrigin3D node as its parent."); - }; - if (controller_id == 0) { - if (!warning.is_empty()) { - warning += "\n\n"; + if (controller_id == 0) { + warnings.push_back(TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.")); } - warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."); - }; + } - return warning; + return warnings; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -404,8 +391,8 @@ void XRAnchor3D::_notification(int p_what) { ERR_FAIL_NULL(xr_server); // find the tracker for our anchor - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id); - if (tracker == nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id); + if (!tracker.is_valid()) { // this anchor is currently not available is_active = false; } else { @@ -459,7 +446,7 @@ void XRAnchor3D::set_anchor_id(int p_anchor_id) { // We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is. // Note that setting this to 0 means this node is not bound to an anchor yet. anchor_id = p_anchor_id; - update_configuration_warning(); + update_configuration_warnings(); }; int XRAnchor3D::get_anchor_id() const { @@ -475,8 +462,8 @@ String XRAnchor3D::get_anchor_name() const { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, String()); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id); - if (tracker == nullptr) { + Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id); + if (!tracker.is_valid()) { return String("Not connected"); }; @@ -487,30 +474,22 @@ bool XRAnchor3D::get_is_active() const { return is_active; }; -String XRAnchor3D::get_configuration_warning() const { - if (!is_visible() || !is_inside_tree()) { - return String(); - } - - String warning = Node3D::get_configuration_warning(); +TypedArray<String> XRAnchor3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); - // must be child node of XROrigin3D! - XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); - if (origin == nullptr) { - if (!warning.is_empty()) { - warning += "\n\n"; + if (is_visible() && is_inside_tree()) { + // must be child node of XROrigin3D! + XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); + if (origin == nullptr) { + warnings.push_back(TTR("XRAnchor3D must have an XROrigin3D node as its parent.")); } - warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent."); - }; - if (anchor_id == 0) { - if (!warning.is_empty()) { - warning += "\n\n"; + if (anchor_id == 0) { + warnings.push_back(TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.")); } - warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."); - }; + } - return warning; + return warnings; }; Plane XRAnchor3D::get_plane() const { @@ -528,21 +507,16 @@ Ref<Mesh> XRAnchor3D::get_mesh() const { //////////////////////////////////////////////////////////////////////////////////////////////////// -String XROrigin3D::get_configuration_warning() const { - if (!is_visible() || !is_inside_tree()) { - return String(); - } - - String warning = Node3D::get_configuration_warning(); +TypedArray<String> XROrigin3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); - if (tracked_camera == nullptr) { - if (!warning.is_empty()) { - warning += "\n\n"; + if (is_visible() && is_inside_tree()) { + if (tracked_camera == nullptr) { + warnings.push_back(TTR("XROrigin3D requires an XRCamera3D child node.")); } - warning += TTR("XROrigin3D requires an XRCamera3D child node."); } - return warning; + return warnings; }; void XROrigin3D::_bind_methods() { diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 7cd6e2ac57..90079f5fe9 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -50,7 +50,7 @@ protected: void _notification(int p_what); public: - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override; virtual Point2 unproject_position(const Vector3 &p_pos) const override; @@ -97,7 +97,7 @@ public: Ref<Mesh> get_mesh() const; - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; XRController3D() {} ~XRController3D() {} @@ -133,7 +133,7 @@ public: Ref<Mesh> get_mesh() const; - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; XRAnchor3D() {} ~XRAnchor3D() {} @@ -158,7 +158,7 @@ protected: static void _bind_methods(); public: - String get_configuration_warning() const override; + TypedArray<String> get_configuration_warnings() const override; void set_tracked_camera(XRCamera3D *p_tracked_camera); void clear_tracked_camera_if(XRCamera3D *p_tracked_camera); |