Browse Source

Merge pull request #54038 from nekomatata/fix-soft-body-memory-corruption-3.x

Rémi Verschelde 3 years ago
parent
commit
8923e2d449
2 changed files with 46 additions and 46 deletions
  1. 39 38
      scene/3d/soft_body.cpp
  2. 7 8
      scene/3d/soft_body.h

+ 39 - 38
scene/3d/soft_body.cpp

@@ -251,7 +251,7 @@ bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Var
 }
 
 void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) {
-	prepare_physics_server();
+	_prepare_physics_server();
 	_reset_points_offsets();
 #ifdef TOOLS_ENABLED
 	if (p_changed == this) {
@@ -269,7 +269,7 @@ void SoftBody::_notification(int p_what) {
 
 			RID space = get_world()->get_space();
 			PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space);
-			prepare_physics_server();
+			_prepare_physics_server();
 		} break;
 		case NOTIFICATION_READY: {
 			if (!parent_collision_ignore.is_empty()) {
@@ -396,7 +396,7 @@ void SoftBody::_bind_methods() {
 String SoftBody::get_configuration_warning() const {
 	String warning = MeshInstance::get_configuration_warning();
 
-	if (get_mesh().is_null()) {
+	if (mesh.is_null()) {
 		if (!warning.empty()) {
 			warning += "\n\n";
 		}
@@ -433,11 +433,17 @@ void SoftBody::_update_physics_server() {
 }
 
 void SoftBody::_draw_soft_mesh() {
-	if (get_mesh().is_null()) {
+	if (mesh.is_null()) {
 		return;
 	}
 
-	const RID mesh_rid = get_mesh()->get_rid();
+	RID mesh_rid = mesh->get_rid();
+	if (owned_mesh != mesh_rid) {
+		_become_mesh_owner();
+		mesh_rid = mesh->get_rid();
+		PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, mesh);
+	}
+
 	if (!visual_server_handler.is_ready(mesh_rid)) {
 		visual_server_handler.prepare(mesh_rid, 0);
 
@@ -456,10 +462,10 @@ void SoftBody::_draw_soft_mesh() {
 	visual_server_handler.commit_changes();
 }
 
-void SoftBody::prepare_physics_server() {
+void SoftBody::_prepare_physics_server() {
 	if (Engine::get_singleton()->is_editor_hint()) {
-		if (get_mesh().is_valid()) {
-			PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+		if (mesh.is_valid()) {
+			PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, mesh);
 		} else {
 			PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
 		}
@@ -467,9 +473,11 @@ void SoftBody::prepare_physics_server() {
 		return;
 	}
 
-	if (get_mesh().is_valid() && physics_enabled) {
-		become_mesh_owner();
-		PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+	if (mesh.is_valid() && physics_enabled) {
+		if (owned_mesh != mesh->get_rid()) {
+			_become_mesh_owner();
+		}
+		PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, mesh);
 		VS::get_singleton()->connect("frame_pre_draw", this, "_draw_soft_mesh");
 	} else {
 		PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
@@ -479,38 +487,32 @@ void SoftBody::prepare_physics_server() {
 	}
 }
 
-void SoftBody::become_mesh_owner() {
-	if (mesh.is_null()) {
-		return;
-	}
-
-	if (!mesh_owner) {
-		mesh_owner = true;
+void SoftBody::_become_mesh_owner() {
+	Vector<Ref<Material>> copy_materials;
+	copy_materials.append_array(materials);
 
-		Vector<Ref<Material>> copy_materials;
-		copy_materials.append_array(materials);
+	ERR_FAIL_COND(!mesh->get_surface_count());
 
-		ERR_FAIL_COND(!mesh->get_surface_count());
+	// Get current mesh array and create new mesh array with necessary flag for softbody
+	Array surface_arrays = mesh->surface_get_arrays(0);
+	Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
+	uint32_t surface_format = mesh->surface_get_format(0);
 
-		// Get current mesh array and create new mesh array with necessary flag for softbody
-		Array surface_arrays = mesh->surface_get_arrays(0);
-		Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
-		uint32_t surface_format = mesh->surface_get_format(0);
+	surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL);
+	surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
 
-		surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL);
-		surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
+	Ref<ArrayMesh> soft_mesh;
+	soft_mesh.instance();
+	soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format);
+	soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
 
-		Ref<ArrayMesh> soft_mesh;
-		soft_mesh.instance();
-		soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format);
-		soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
+	set_mesh(soft_mesh);
 
-		set_mesh(soft_mesh);
-
-		for (int i = copy_materials.size() - 1; 0 <= i; --i) {
-			set_surface_material(i, copy_materials[i]);
-		}
+	for (int i = copy_materials.size() - 1; 0 <= i; --i) {
+		set_surface_material(i, copy_materials[i]);
 	}
+
+	owned_mesh = soft_mesh->get_rid();
 }
 
 void SoftBody::set_collision_mask(uint32_t p_mask) {
@@ -578,7 +580,7 @@ void SoftBody::set_physics_enabled(bool p_enabled) {
 	physics_enabled = p_enabled;
 
 	if (is_inside_tree()) {
-		prepare_physics_server();
+		_prepare_physics_server();
 	}
 }
 
@@ -730,7 +732,6 @@ bool SoftBody::is_ray_pickable() const {
 
 SoftBody::SoftBody() :
 		physics_rid(PhysicsServer::get_singleton()->soft_body_create()),
-		mesh_owner(false),
 		collision_mask(1),
 		collision_layer(1),
 		simulation_started(false),

+ 7 - 8
scene/3d/soft_body.h

@@ -84,7 +84,7 @@ private:
 
 	bool physics_enabled = true;
 
-	bool mesh_owner;
+	RID owned_mesh;
 	uint32_t collision_mask;
 	uint32_t collision_layer;
 	NodePath parent_collision_ignore;
@@ -100,6 +100,12 @@ private:
 
 	void _update_pickable();
 
+	void _update_physics_server();
+	void _draw_soft_mesh();
+
+	void _prepare_physics_server();
+	void _become_mesh_owner();
+
 protected:
 	bool _set(const StringName &p_name, const Variant &p_value);
 	bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -116,14 +122,7 @@ protected:
 
 	virtual String get_configuration_warning() const;
 
-protected:
-	void _update_physics_server();
-	void _draw_soft_mesh();
-
 public:
-	void prepare_physics_server();
-	void become_mesh_owner();
-
 	void set_collision_mask(uint32_t p_mask);
 	uint32_t get_collision_mask() const;