ソースを参照

Prevent crash when passing empty array to MeshEmitter

Yuri Roubinsky 3 年 前
コミット
93bb34cfb4

+ 94 - 63
scene/resources/visual_shader_particle_nodes.cpp

@@ -318,26 +318,24 @@ String VisualShaderNodeParticleMeshEmitter::get_input_port_name(int p_port) cons
 String VisualShaderNodeParticleMeshEmitter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
 	String code;
 
-	if (mesh.is_valid()) {
-		if (is_output_port_connected(0)) { // position
-			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_vx") + ";\n";
-		}
+	if (is_output_port_connected(0)) { // position
+		code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_vx") + ";\n";
+	}
 
-		if (is_output_port_connected(1)) { // normal
-			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_nm") + ";\n";
-		}
+	if (is_output_port_connected(1)) { // normal
+		code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_nm") + ";\n";
+	}
 
-		if (is_output_port_connected(2) || is_output_port_connected(3)) { // color & alpha
-			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_col") + ";\n";
-		}
+	if (is_output_port_connected(2) || is_output_port_connected(3)) { // color & alpha
+		code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_col") + ";\n";
+	}
 
-		if (is_output_port_connected(4)) { // uv
-			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv") + ";\n";
-		}
+	if (is_output_port_connected(4)) { // uv
+		code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv") + ";\n";
+	}
 
-		if (is_output_port_connected(5)) { // uv2
-			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv2") + ";\n";
-		}
+	if (is_output_port_connected(5)) { // uv2
+		code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv2") + ";\n";
 	}
 
 	return code;
@@ -503,67 +501,97 @@ void VisualShaderNodeParticleMeshEmitter::_update_textures() {
 	Vector<Vector2> uvs;
 	Vector<Vector2> uvs2;
 
+	const int surface_count = mesh->get_surface_count();
+
 	if (use_all_surfaces) {
-		for (int i = 0; i < max_surface_index; i++) {
+		for (int i = 0; i < surface_count; i++) {
+			const Array surface_arrays = mesh->surface_get_arrays(i);
+			const int surface_arrays_size = surface_arrays.size();
+
 			// position
-			Array vertex_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_VERTEX];
-			for (int j = 0; j < vertex_array.size(); j++) {
-				vertices.push_back((Vector3)vertex_array[j]);
+			if (surface_arrays_size > Mesh::ARRAY_VERTEX) {
+				Array vertex_array = surface_arrays[Mesh::ARRAY_VERTEX];
+				for (int j = 0; j < vertex_array.size(); j++) {
+					vertices.push_back((Vector3)vertex_array[j]);
+				}
 			}
 
 			// normal
-			Array normal_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_NORMAL];
-			for (int j = 0; j < normal_array.size(); j++) {
-				normals.push_back((Vector3)normal_array[j]);
+			if (surface_arrays_size > Mesh::ARRAY_NORMAL) {
+				Array normal_array = surface_arrays[Mesh::ARRAY_NORMAL];
+				for (int j = 0; j < normal_array.size(); j++) {
+					normals.push_back((Vector3)normal_array[j]);
+				}
 			}
 
 			// color
-			Array color_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_COLOR];
-			for (int j = 0; j < color_array.size(); j++) {
-				colors.push_back((Color)color_array[j]);
+			if (surface_arrays_size > Mesh::ARRAY_COLOR) {
+				Array color_array = surface_arrays[Mesh::ARRAY_COLOR];
+				for (int j = 0; j < color_array.size(); j++) {
+					colors.push_back((Color)color_array[j]);
+				}
 			}
 
 			// uv
-			Array uv_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_TEX_UV];
-			for (int j = 0; j < uv_array.size(); j++) {
-				uvs.push_back((Vector2)uv_array[j]);
+			if (surface_arrays_size > Mesh::ARRAY_TEX_UV) {
+				Array uv_array = surface_arrays[Mesh::ARRAY_TEX_UV];
+				for (int j = 0; j < uv_array.size(); j++) {
+					uvs.push_back((Vector2)uv_array[j]);
+				}
 			}
 
 			// uv2
-			Array uv2_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_TEX_UV2];
-			for (int j = 0; j < uv2_array.size(); j++) {
-				uvs2.push_back((Vector2)uv2_array[j]);
+			if (surface_arrays_size > Mesh::ARRAY_TEX_UV2) {
+				Array uv2_array = surface_arrays[Mesh::ARRAY_TEX_UV2];
+				for (int j = 0; j < uv2_array.size(); j++) {
+					uvs2.push_back((Vector2)uv2_array[j]);
+				}
 			}
 		}
 	} else {
-		// position
-		Array vertex_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_VERTEX];
-		for (int i = 0; i < vertex_array.size(); i++) {
-			vertices.push_back((Vector3)vertex_array[i]);
-		}
+		if (surface_index >= 0 && surface_index < surface_count) {
+			const Array surface_arrays = mesh->surface_get_arrays(surface_index);
+			const int surface_arrays_size = surface_arrays.size();
 
-		// normal
-		Array normal_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_NORMAL];
-		for (int i = 0; i < normal_array.size(); i++) {
-			normals.push_back((Vector3)normal_array[i]);
-		}
+			// position
+			if (surface_arrays_size > Mesh::ARRAY_VERTEX) {
+				Array vertex_array = surface_arrays[Mesh::ARRAY_VERTEX];
+				for (int i = 0; i < vertex_array.size(); i++) {
+					vertices.push_back((Vector3)vertex_array[i]);
+				}
+			}
 
-		// color
-		Array color_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_COLOR];
-		for (int i = 0; i < color_array.size(); i++) {
-			colors.push_back((Color)color_array[i]);
-		}
+			// normal
+			if (surface_arrays_size > Mesh::ARRAY_NORMAL) {
+				Array normal_array = surface_arrays[Mesh::ARRAY_NORMAL];
+				for (int i = 0; i < normal_array.size(); i++) {
+					normals.push_back((Vector3)normal_array[i]);
+				}
+			}
 
-		// uv
-		Array uv_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_TEX_UV];
-		for (int j = 0; j < uv_array.size(); j++) {
-			uvs.push_back((Vector2)uv_array[j]);
-		}
+			// color
+			if (surface_arrays_size > Mesh::ARRAY_COLOR) {
+				Array color_array = surface_arrays[Mesh::ARRAY_COLOR];
+				for (int i = 0; i < color_array.size(); i++) {
+					colors.push_back((Color)color_array[i]);
+				}
+			}
+
+			// uv
+			if (surface_arrays_size > Mesh::ARRAY_TEX_UV) {
+				Array uv_array = surface_arrays[Mesh::ARRAY_TEX_UV];
+				for (int j = 0; j < uv_array.size(); j++) {
+					uvs.push_back((Vector2)uv_array[j]);
+				}
+			}
 
-		// uv2
-		Array uv2_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_TEX_UV2];
-		for (int j = 0; j < uv2_array.size(); j++) {
-			uvs2.push_back((Vector2)uv2_array[j]);
+			// uv2
+			if (surface_arrays_size > Mesh::ARRAY_TEX_UV2) {
+				Array uv2_array = surface_arrays[Mesh::ARRAY_TEX_UV2];
+				for (int j = 0; j < uv2_array.size(); j++) {
+					uvs2.push_back((Vector2)uv2_array[j]);
+				}
+			}
 		}
 	}
 
@@ -579,12 +607,6 @@ void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref<Mesh> p_mesh) {
 		return;
 	}
 
-	if (p_mesh.is_valid()) {
-		max_surface_index = p_mesh->get_surface_count();
-	} else {
-		max_surface_index = 0;
-	}
-
 	if (mesh.is_valid()) {
 		Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures);
 
@@ -623,7 +645,16 @@ bool VisualShaderNodeParticleMeshEmitter::is_use_all_surfaces() const {
 }
 
 void VisualShaderNodeParticleMeshEmitter::set_surface_index(int p_surface_index) {
-	if (p_surface_index == surface_index || p_surface_index < 0 || p_surface_index >= max_surface_index) {
+	if (mesh.is_valid()) {
+		if (mesh->get_surface_count() > 0) {
+			p_surface_index = CLAMP(p_surface_index, 0, mesh->get_surface_count() - 1);
+		} else {
+			p_surface_index = 0;
+		}
+	} else if (p_surface_index < 0) {
+		p_surface_index = 0;
+	}
+	if (surface_index == p_surface_index) {
 		return;
 	}
 	surface_index = p_surface_index;

+ 0 - 1
scene/resources/visual_shader_particle_nodes.h

@@ -111,7 +111,6 @@ class VisualShaderNodeParticleMeshEmitter : public VisualShaderNodeParticleEmitt
 	Ref<Mesh> mesh;
 	bool use_all_surfaces = true;
 	int surface_index = 0;
-	int max_surface_index = 0;
 
 	Ref<ImageTexture> position_texture;
 	Ref<ImageTexture> normal_texture;