浏览代码

Ability to restart particle system with a function call

Juan Linietsky 8 年之前
父节点
当前提交
83ae9a5e28

+ 31 - 0
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -5068,6 +5068,14 @@ void RasterizerStorageGLES3::particles_set_lifetime(RID p_particles, float p_lif
 	ERR_FAIL_COND(!particles);
 	ERR_FAIL_COND(!particles);
 	particles->lifetime = p_lifetime;
 	particles->lifetime = p_lifetime;
 }
 }
+
+void RasterizerStorageGLES3::particles_set_one_shot(RID p_particles, bool p_one_shot) {
+
+	Particles *particles = particles_owner.getornull(p_particles);
+	ERR_FAIL_COND(!particles);
+	particles->one_shot = p_one_shot;
+}
+
 void RasterizerStorageGLES3::particles_set_pre_process_time(RID p_particles, float p_time) {
 void RasterizerStorageGLES3::particles_set_pre_process_time(RID p_particles, float p_time) {
 
 
 	Particles *particles = particles_owner.getornull(p_particles);
 	Particles *particles = particles_owner.getornull(p_particles);
@@ -5199,6 +5207,14 @@ void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p
 	particles->draw_passes[p_pass] = p_mesh;
 	particles->draw_passes[p_pass] = p_mesh;
 }
 }
 
 
+void RasterizerStorageGLES3::particles_restart(RID p_particles) {
+
+	Particles *particles = particles_owner.getornull(p_particles);
+	ERR_FAIL_COND(!particles);
+
+	particles->restart_request = true;
+}
+
 void RasterizerStorageGLES3::particles_request_process(RID p_particles) {
 void RasterizerStorageGLES3::particles_request_process(RID p_particles) {
 
 
 	Particles *particles = particles_owner.getornull(p_particles);
 	Particles *particles = particles_owner.getornull(p_particles);
@@ -5290,6 +5306,10 @@ void RasterizerStorageGLES3::_particles_process(Particles *particles, float p_de
 		particles->cycle_number = 0;
 		particles->cycle_number = 0;
 		particles->random_seed = Math::rand();
 		particles->random_seed = Math::rand();
 	} else if (new_phase < particles->phase) {
 	} else if (new_phase < particles->phase) {
+		if (particles->one_shot) {
+			particles->emitting = false;
+			shaders.particles.set_uniform(ParticlesShaderGLES3::EMITTING, false);
+		}
 		particles->cycle_number++;
 		particles->cycle_number++;
 	}
 	}
 
 
@@ -5356,6 +5376,17 @@ void RasterizerStorageGLES3::update_particles() {
 
 
 		Particles *particles = particle_update_list.first()->self();
 		Particles *particles = particle_update_list.first()->self();
 
 
+		if (particles->restart_request) {
+			particles->emitting = true; //restart from zero
+			particles->prev_ticks = 0;
+			particles->phase = 0;
+			particles->prev_phase = 0;
+			particles->clear = true;
+			particles->particle_valid_histories[0] = false;
+			particles->particle_valid_histories[1] = false;
+			particles->restart_request = false;
+		}
+
 		if (particles->inactive && !particles->emitting) {
 		if (particles->inactive && !particles->emitting) {
 
 
 			particle_update_list.remove(particle_update_list.first());
 			particle_update_list.remove(particle_update_list.first());

+ 7 - 0
drivers/gles3/rasterizer_storage_gles3.h

@@ -1036,11 +1036,13 @@ public:
 		bool inactive;
 		bool inactive;
 		float inactive_time;
 		float inactive_time;
 		bool emitting;
 		bool emitting;
+		bool one_shot;
 		int amount;
 		int amount;
 		float lifetime;
 		float lifetime;
 		float pre_process_time;
 		float pre_process_time;
 		float explosiveness;
 		float explosiveness;
 		float randomness;
 		float randomness;
+		bool restart_request;
 		Rect3 custom_aabb;
 		Rect3 custom_aabb;
 		bool use_local_coords;
 		bool use_local_coords;
 		RID process_material;
 		RID process_material;
@@ -1080,6 +1082,7 @@ public:
 			: particle_element(this) {
 			: particle_element(this) {
 			cycle_number = 0;
 			cycle_number = 0;
 			emitting = false;
 			emitting = false;
+			one_shot = false;
 			amount = 0;
 			amount = 0;
 			lifetime = 1.0;
 			lifetime = 1.0;
 			pre_process_time = 0.0;
 			pre_process_time = 0.0;
@@ -1093,6 +1096,8 @@ public:
 			speed_scale = 1.0;
 			speed_scale = 1.0;
 			random_seed = 0;
 			random_seed = 0;
 
 
+			restart_request = false;
+
 			custom_aabb = Rect3(Vector3(-4, -4, -4), Vector3(8, 8, 8));
 			custom_aabb = Rect3(Vector3(-4, -4, -4), Vector3(8, 8, 8));
 
 
 			draw_order = VS::PARTICLES_DRAW_ORDER_INDEX;
 			draw_order = VS::PARTICLES_DRAW_ORDER_INDEX;
@@ -1131,6 +1136,7 @@ public:
 	virtual void particles_set_emitting(RID p_particles, bool p_emitting);
 	virtual void particles_set_emitting(RID p_particles, bool p_emitting);
 	virtual void particles_set_amount(RID p_particles, int p_amount);
 	virtual void particles_set_amount(RID p_particles, int p_amount);
 	virtual void particles_set_lifetime(RID p_particles, float p_lifetime);
 	virtual void particles_set_lifetime(RID p_particles, float p_lifetime);
+	virtual void particles_set_one_shot(RID p_particles, bool p_one_shot);
 	virtual void particles_set_pre_process_time(RID p_particles, float p_time);
 	virtual void particles_set_pre_process_time(RID p_particles, float p_time);
 	virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio);
 	virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio);
 	virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio);
 	virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio);
@@ -1140,6 +1146,7 @@ public:
 	virtual void particles_set_process_material(RID p_particles, RID p_material);
 	virtual void particles_set_process_material(RID p_particles, RID p_material);
 	virtual void particles_set_fixed_fps(RID p_particles, int p_fps);
 	virtual void particles_set_fixed_fps(RID p_particles, int p_fps);
 	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable);
 	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable);
+	virtual void particles_restart(RID p_particles);
 
 
 	virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order);
 	virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order);
 
 

+ 1 - 1
editor/import/resource_importer_texture.cpp

@@ -202,7 +202,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/anisotropic"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/anisotropic"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable,Detect"), 2));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable,Detect"), 2));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D ? true : false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D ? true : false));
-	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), true));
+	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "stream"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "stream"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));

+ 15 - 4
scene/2d/canvas_item.cpp

@@ -96,8 +96,8 @@ void CanvasItemMaterial::_update_shader() {
 
 
 	switch (light_mode) {
 	switch (light_mode) {
 		case LIGHT_MODE_NORMAL: break;
 		case LIGHT_MODE_NORMAL: break;
-		case LIGHT_MODE_UNSHADED: code += "unshaded"; break;
-		case LIGHT_MODE_LIGHT_ONLY: code += "light_only"; break;
+		case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
+		case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
 	}
 	}
 	code += ";\n"; //thats it.
 	code += ";\n"; //thats it.
 
 
@@ -367,7 +367,9 @@ Transform2D CanvasItem::get_global_transform_with_canvas() const {
 }
 }
 
 
 Transform2D CanvasItem::get_global_transform() const {
 Transform2D CanvasItem::get_global_transform() const {
-
+#ifdef DEBUG_ENABLED
+	ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
+#endif
 	if (global_invalid) {
 	if (global_invalid) {
 
 
 		const CanvasItem *pi = get_parent_item();
 		const CanvasItem *pi = get_parent_item();
@@ -765,8 +767,9 @@ float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const
 
 
 void CanvasItem::_notify_transform(CanvasItem *p_node) {
 void CanvasItem::_notify_transform(CanvasItem *p_node) {
 
 
-	if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid)
+	if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
 		return; //nothing to do
 		return; //nothing to do
+	}
 
 
 	p_node->global_invalid = true;
 	p_node->global_invalid = true;
 
 
@@ -1067,7 +1070,15 @@ bool CanvasItem::is_local_transform_notification_enabled() const {
 }
 }
 
 
 void CanvasItem::set_notify_transform(bool p_enable) {
 void CanvasItem::set_notify_transform(bool p_enable) {
+	if (notify_transform == p_enable)
+		return;
+
 	notify_transform = p_enable;
 	notify_transform = p_enable;
+
+	if (notify_transform && is_inside_tree()) {
+		//this ensures that invalid globals get resolved, so notifications can be received
+		get_global_transform();
+	}
 }
 }
 
 
 bool CanvasItem::is_transform_notification_enabled() const {
 bool CanvasItem::is_transform_notification_enabled() const {

+ 22 - 1
scene/2d/particles_2d.cpp

@@ -50,6 +50,12 @@ void Particles2D::set_lifetime(float p_lifetime) {
 	lifetime = p_lifetime;
 	lifetime = p_lifetime;
 	VS::get_singleton()->particles_set_lifetime(particles, lifetime);
 	VS::get_singleton()->particles_set_lifetime(particles, lifetime);
 }
 }
+
+void Particles2D::set_one_shot(bool p_enable) {
+
+	one_shot = p_enable;
+	VS::get_singleton()->particles_set_one_shot(particles, one_shot);
+}
 void Particles2D::set_pre_process_time(float p_time) {
 void Particles2D::set_pre_process_time(float p_time) {
 
 
 	pre_process_time = p_time;
 	pre_process_time = p_time;
@@ -84,7 +90,7 @@ void Particles2D::set_use_local_coordinates(bool p_enable) {
 	local_coords = p_enable;
 	local_coords = p_enable;
 	VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
 	VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
 	set_notify_transform(!p_enable);
 	set_notify_transform(!p_enable);
-	if (!p_enable) {
+	if (!p_enable && is_inside_tree()) {
 		_update_particle_emission_transform();
 		_update_particle_emission_transform();
 	}
 	}
 }
 }
@@ -135,6 +141,11 @@ float Particles2D::get_lifetime() const {
 
 
 	return lifetime;
 	return lifetime;
 }
 }
+
+bool Particles2D::get_one_shot() const {
+
+	return one_shot;
+}
 float Particles2D::get_pre_process_time() const {
 float Particles2D::get_pre_process_time() const {
 
 
 	return pre_process_time;
 	return pre_process_time;
@@ -264,6 +275,10 @@ int Particles2D::get_h_frames() const {
 	return h_frames;
 	return h_frames;
 }
 }
 
 
+void Particles2D::restart() {
+	VS::get_singleton()->particles_restart(particles);
+}
+
 void Particles2D::_notification(int p_what) {
 void Particles2D::_notification(int p_what) {
 
 
 	if (p_what == NOTIFICATION_DRAW) {
 	if (p_what == NOTIFICATION_DRAW) {
@@ -295,6 +310,7 @@ void Particles2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting);
 	ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting);
 	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount);
 	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount);
 	ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime);
 	ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime);
+	ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &Particles2D::set_one_shot);
 	ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time);
 	ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time);
 	ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio);
 	ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio);
 	ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio);
 	ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio);
@@ -308,6 +324,7 @@ void Particles2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting);
 	ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting);
 	ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount);
 	ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount);
 	ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime);
 	ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime);
+	ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles2D::get_one_shot);
 	ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time);
 	ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time);
 	ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio);
 	ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio);
 	ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio);
 	ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio);
@@ -335,10 +352,13 @@ void Particles2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_h_frames", "frames"), &Particles2D::set_h_frames);
 	ClassDB::bind_method(D_METHOD("set_h_frames", "frames"), &Particles2D::set_h_frames);
 	ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames);
 	ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames);
 
 
+	ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
+
 	ADD_GROUP("Parameters", "");
 	ADD_GROUP("Parameters", "");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
@@ -365,6 +385,7 @@ Particles2D::Particles2D() {
 	particles = VS::get_singleton()->particles_create();
 	particles = VS::get_singleton()->particles_create();
 
 
 	set_emitting(true);
 	set_emitting(true);
+	set_one_shot(false);
 	set_amount(8);
 	set_amount(8);
 	set_lifetime(1);
 	set_lifetime(1);
 	set_fixed_fps(0);
 	set_fixed_fps(0);

+ 4 - 0
scene/2d/particles_2d.h

@@ -48,6 +48,7 @@ private:
 	RID particles;
 	RID particles;
 
 
 	bool emitting;
 	bool emitting;
+	bool one_shot;
 	int amount;
 	int amount;
 	float lifetime;
 	float lifetime;
 	float pre_process_time;
 	float pre_process_time;
@@ -79,6 +80,7 @@ public:
 	void set_emitting(bool p_emitting);
 	void set_emitting(bool p_emitting);
 	void set_amount(int p_amount);
 	void set_amount(int p_amount);
 	void set_lifetime(float p_lifetime);
 	void set_lifetime(float p_lifetime);
+	void set_one_shot(bool p_enabled);
 	void set_pre_process_time(float p_time);
 	void set_pre_process_time(float p_time);
 	void set_explosiveness_ratio(float p_ratio);
 	void set_explosiveness_ratio(float p_ratio);
 	void set_randomness_ratio(float p_ratio);
 	void set_randomness_ratio(float p_ratio);
@@ -90,6 +92,7 @@ public:
 	bool is_emitting() const;
 	bool is_emitting() const;
 	int get_amount() const;
 	int get_amount() const;
 	float get_lifetime() const;
 	float get_lifetime() const;
+	bool get_one_shot() const;
 	float get_pre_process_time() const;
 	float get_pre_process_time() const;
 	float get_explosiveness_ratio() const;
 	float get_explosiveness_ratio() const;
 	float get_randomness_ratio() const;
 	float get_randomness_ratio() const;
@@ -121,6 +124,7 @@ public:
 	void set_h_frames(int p_count);
 	void set_h_frames(int p_count);
 	int get_h_frames() const;
 	int get_h_frames() const;
 
 
+	void restart();
 	Rect2 capture_rect() const;
 	Rect2 capture_rect() const;
 	Particles2D();
 	Particles2D();
 	~Particles2D();
 	~Particles2D();

+ 22 - 0
scene/3d/particles.cpp

@@ -58,6 +58,13 @@ void Particles::set_lifetime(float p_lifetime) {
 	lifetime = p_lifetime;
 	lifetime = p_lifetime;
 	VS::get_singleton()->particles_set_lifetime(particles, lifetime);
 	VS::get_singleton()->particles_set_lifetime(particles, lifetime);
 }
 }
+
+void Particles::set_one_shot(bool p_one_shot) {
+
+	one_shot = p_one_shot;
+	VS::get_singleton()->particles_set_one_shot(particles, one_shot);
+}
+
 void Particles::set_pre_process_time(float p_time) {
 void Particles::set_pre_process_time(float p_time) {
 
 
 	pre_process_time = p_time;
 	pre_process_time = p_time;
@@ -114,6 +121,11 @@ float Particles::get_lifetime() const {
 
 
 	return lifetime;
 	return lifetime;
 }
 }
+bool Particles::get_one_shot() const {
+
+	return one_shot;
+}
+
 float Particles::get_pre_process_time() const {
 float Particles::get_pre_process_time() const {
 
 
 	return pre_process_time;
 	return pre_process_time;
@@ -233,6 +245,11 @@ String Particles::get_configuration_warning() const {
 	return warnings;
 	return warnings;
 }
 }
 
 
+void Particles::restart() {
+
+	VisualServer::get_singleton()->particles_restart(particles);
+}
+
 Rect3 Particles::capture_aabb() const {
 Rect3 Particles::capture_aabb() const {
 
 
 	return VS::get_singleton()->particles_get_current_aabb(particles);
 	return VS::get_singleton()->particles_get_current_aabb(particles);
@@ -254,6 +271,7 @@ void Particles::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles::set_emitting);
 	ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles::set_emitting);
 	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles::set_amount);
 	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles::set_amount);
 	ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles::set_lifetime);
 	ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles::set_lifetime);
+	ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &Particles::set_one_shot);
 	ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles::set_pre_process_time);
 	ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles::set_pre_process_time);
 	ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles::set_explosiveness_ratio);
 	ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles::set_explosiveness_ratio);
 	ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles::set_randomness_ratio);
 	ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles::set_randomness_ratio);
@@ -267,6 +285,7 @@ void Particles::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("is_emitting"), &Particles::is_emitting);
 	ClassDB::bind_method(D_METHOD("is_emitting"), &Particles::is_emitting);
 	ClassDB::bind_method(D_METHOD("get_amount"), &Particles::get_amount);
 	ClassDB::bind_method(D_METHOD("get_amount"), &Particles::get_amount);
 	ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles::get_lifetime);
 	ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles::get_lifetime);
+	ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles::get_one_shot);
 	ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles::get_pre_process_time);
 	ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles::get_pre_process_time);
 	ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles::get_explosiveness_ratio);
 	ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles::get_explosiveness_ratio);
 	ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles::get_randomness_ratio);
 	ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles::get_randomness_ratio);
@@ -287,12 +306,14 @@ void Particles::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_draw_passes"), &Particles::get_draw_passes);
 	ClassDB::bind_method(D_METHOD("get_draw_passes"), &Particles::get_draw_passes);
 	ClassDB::bind_method(D_METHOD("get_draw_pass_mesh:Mesh", "pass"), &Particles::get_draw_pass_mesh);
 	ClassDB::bind_method(D_METHOD("get_draw_pass_mesh:Mesh", "pass"), &Particles::get_draw_pass_mesh);
 
 
+	ClassDB::bind_method(D_METHOD("restart"), &Particles::restart);
 	ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
 	ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
 
 
 	ADD_GROUP("Parameters", "");
 	ADD_GROUP("Parameters", "");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
@@ -322,6 +343,7 @@ Particles::Particles() {
 	particles = VS::get_singleton()->particles_create();
 	particles = VS::get_singleton()->particles_create();
 	set_base(particles);
 	set_base(particles);
 	set_emitting(true);
 	set_emitting(true);
+	set_one_shot(false);
 	set_amount(8);
 	set_amount(8);
 	set_lifetime(1);
 	set_lifetime(1);
 	set_fixed_fps(0);
 	set_fixed_fps(0);

+ 5 - 0
scene/3d/particles.h

@@ -58,6 +58,7 @@ private:
 	RID particles;
 	RID particles;
 
 
 	bool emitting;
 	bool emitting;
+	bool one_shot;
 	int amount;
 	int amount;
 	float lifetime;
 	float lifetime;
 	float pre_process_time;
 	float pre_process_time;
@@ -86,6 +87,7 @@ public:
 	void set_emitting(bool p_emitting);
 	void set_emitting(bool p_emitting);
 	void set_amount(int p_amount);
 	void set_amount(int p_amount);
 	void set_lifetime(float p_lifetime);
 	void set_lifetime(float p_lifetime);
+	void set_one_shot(bool p_enabled);
 	void set_pre_process_time(float p_time);
 	void set_pre_process_time(float p_time);
 	void set_explosiveness_ratio(float p_ratio);
 	void set_explosiveness_ratio(float p_ratio);
 	void set_randomness_ratio(float p_ratio);
 	void set_randomness_ratio(float p_ratio);
@@ -97,6 +99,7 @@ public:
 	bool is_emitting() const;
 	bool is_emitting() const;
 	int get_amount() const;
 	int get_amount() const;
 	float get_lifetime() const;
 	float get_lifetime() const;
+	bool get_one_shot() const;
 	float get_pre_process_time() const;
 	float get_pre_process_time() const;
 	float get_explosiveness_ratio() const;
 	float get_explosiveness_ratio() const;
 	float get_randomness_ratio() const;
 	float get_randomness_ratio() const;
@@ -122,6 +125,8 @@ public:
 
 
 	virtual String get_configuration_warning() const;
 	virtual String get_configuration_warning() const;
 
 
+	void restart();
+
 	Rect3 capture_aabb() const;
 	Rect3 capture_aabb() const;
 	Particles();
 	Particles();
 	~Particles();
 	~Particles();

+ 2 - 0
servers/visual/rasterizer.h

@@ -448,6 +448,7 @@ public:
 	virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
 	virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
 	virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
 	virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
 	virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
 	virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
+	virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
 	virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
 	virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
 	virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
 	virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
 	virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
 	virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
@@ -457,6 +458,7 @@ public:
 	virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
 	virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
 	virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
 	virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
 	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
 	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
+	virtual void particles_restart(RID p_particles) = 0;
 
 
 	virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) = 0;
 	virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) = 0;
 
 

+ 2 - 0
servers/visual/visual_server_raster.h

@@ -862,6 +862,7 @@ public:
 	BIND2(particles_set_emitting, RID, bool)
 	BIND2(particles_set_emitting, RID, bool)
 	BIND2(particles_set_amount, RID, int)
 	BIND2(particles_set_amount, RID, int)
 	BIND2(particles_set_lifetime, RID, float)
 	BIND2(particles_set_lifetime, RID, float)
+	BIND2(particles_set_one_shot, RID, bool)
 	BIND2(particles_set_pre_process_time, RID, float)
 	BIND2(particles_set_pre_process_time, RID, float)
 	BIND2(particles_set_explosiveness_ratio, RID, float)
 	BIND2(particles_set_explosiveness_ratio, RID, float)
 	BIND2(particles_set_randomness_ratio, RID, float)
 	BIND2(particles_set_randomness_ratio, RID, float)
@@ -871,6 +872,7 @@ public:
 	BIND2(particles_set_process_material, RID, RID)
 	BIND2(particles_set_process_material, RID, RID)
 	BIND2(particles_set_fixed_fps, RID, int)
 	BIND2(particles_set_fixed_fps, RID, int)
 	BIND2(particles_set_fractional_delta, RID, bool)
 	BIND2(particles_set_fractional_delta, RID, bool)
+	BIND1(particles_restart, RID)
 
 
 	BIND2(particles_set_draw_order, RID, VS::ParticlesDrawOrder)
 	BIND2(particles_set_draw_order, RID, VS::ParticlesDrawOrder)
 
 

+ 2 - 0
servers/visual/visual_server_wrap_mt.h

@@ -306,6 +306,7 @@ public:
 	FUNC2(particles_set_emitting, RID, bool)
 	FUNC2(particles_set_emitting, RID, bool)
 	FUNC2(particles_set_amount, RID, int)
 	FUNC2(particles_set_amount, RID, int)
 	FUNC2(particles_set_lifetime, RID, float)
 	FUNC2(particles_set_lifetime, RID, float)
+	FUNC2(particles_set_one_shot, RID, bool)
 	FUNC2(particles_set_pre_process_time, RID, float)
 	FUNC2(particles_set_pre_process_time, RID, float)
 	FUNC2(particles_set_explosiveness_ratio, RID, float)
 	FUNC2(particles_set_explosiveness_ratio, RID, float)
 	FUNC2(particles_set_randomness_ratio, RID, float)
 	FUNC2(particles_set_randomness_ratio, RID, float)
@@ -315,6 +316,7 @@ public:
 	FUNC2(particles_set_process_material, RID, RID)
 	FUNC2(particles_set_process_material, RID, RID)
 	FUNC2(particles_set_fixed_fps, RID, int)
 	FUNC2(particles_set_fixed_fps, RID, int)
 	FUNC2(particles_set_fractional_delta, RID, bool)
 	FUNC2(particles_set_fractional_delta, RID, bool)
+	FUNC1(particles_restart, RID)
 
 
 	FUNC2(particles_set_draw_order, RID, VS::ParticlesDrawOrder)
 	FUNC2(particles_set_draw_order, RID, VS::ParticlesDrawOrder)
 
 

+ 2 - 0
servers/visual_server.h

@@ -478,6 +478,7 @@ public:
 	virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
 	virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
 	virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
 	virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
 	virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
 	virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
+	virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
 	virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
 	virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
 	virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
 	virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
 	virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
 	virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
@@ -487,6 +488,7 @@ public:
 	virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
 	virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
 	virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
 	virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
 	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
 	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
+	virtual void particles_restart(RID p_particles) = 0;
 
 
 	enum ParticlesDrawOrder {
 	enum ParticlesDrawOrder {
 		PARTICLES_DRAW_ORDER_INDEX,
 		PARTICLES_DRAW_ORDER_INDEX,