mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	2D GPU Particles working..
This commit is contained in:
		
							parent
							
								
									3c1fd26bb0
								
							
						
					
					
						commit
						95560e02c5
					
				
					 21 changed files with 1039 additions and 1340 deletions
				
			
		|  | @ -28,6 +28,7 @@ | ||||||
| /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | ||||||
| /*************************************************************************/ | /*************************************************************************/ | ||||||
| #include "rasterizer_canvas_gles3.h" | #include "rasterizer_canvas_gles3.h" | ||||||
|  | #include "servers/visual/visual_server_raster.h" | ||||||
| 
 | 
 | ||||||
| #include "global_config.h" | #include "global_config.h" | ||||||
| #include "os/os.h" | #include "os/os.h" | ||||||
|  | @ -607,6 +608,133 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur | ||||||
| 				} | 				} | ||||||
| 				_draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); | 				_draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); | ||||||
| 
 | 
 | ||||||
|  | 			} break; | ||||||
|  | 			case Item::Command::TYPE_PARTICLES: { | ||||||
|  | 
 | ||||||
|  | 				Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c); | ||||||
|  | 
 | ||||||
|  | 				RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles); | ||||||
|  | 				if (!particles) | ||||||
|  | 					break; | ||||||
|  | 
 | ||||||
|  | 				glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
 | ||||||
|  | 
 | ||||||
|  | 				VisualServerRaster::redraw_request(); | ||||||
|  | 
 | ||||||
|  | 				storage->particles_request_process(particles_cmd->particles); | ||||||
|  | 				//enable instancing
 | ||||||
|  | 
 | ||||||
|  | 				state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true); | ||||||
|  | 				state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true); | ||||||
|  | 				state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true); | ||||||
|  | 				//reset shader and force rebind
 | ||||||
|  | 				state.using_texture_rect = true; | ||||||
|  | 				_set_texture_rect_mode(false); | ||||||
|  | 
 | ||||||
|  | 				RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map); | ||||||
|  | 
 | ||||||
|  | 				if (texture) { | ||||||
|  | 					Size2 texpixel_size(1.0 / (texture->width / particles_cmd->h_frames), 1.0 / (texture->height / particles_cmd->v_frames)); | ||||||
|  | 					state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); | ||||||
|  | 				} else { | ||||||
|  | 					state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0)); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (!particles->use_local_coords) { | ||||||
|  | 
 | ||||||
|  | 					Transform2D inv_xf; | ||||||
|  | 					inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y)); | ||||||
|  | 					inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y)); | ||||||
|  | 					inv_xf.set_origin(Vector2(particles->emission_transform.get_origin().x, particles->emission_transform.get_origin().y)); | ||||||
|  | 					inv_xf.affine_invert(); | ||||||
|  | 
 | ||||||
|  | 					state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				state.canvas_shader.set_uniform(CanvasShaderGLES3::H_FRAMES, particles_cmd->h_frames); | ||||||
|  | 				state.canvas_shader.set_uniform(CanvasShaderGLES3::V_FRAMES, particles_cmd->v_frames); | ||||||
|  | 
 | ||||||
|  | 				glBindVertexArray(data.particle_quad_array); //use particle quad array
 | ||||||
|  | 				glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer
 | ||||||
|  | 
 | ||||||
|  | 				int stride = sizeof(float) * 4 * 6; | ||||||
|  | 
 | ||||||
|  | 				int amount = particles->amount; | ||||||
|  | 
 | ||||||
|  | 				if (particles->draw_order != VS::PARTICLES_DRAW_ORDER_LIFETIME) { | ||||||
|  | 
 | ||||||
|  | 					glEnableVertexAttribArray(8); //xform x
 | ||||||
|  | 					glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 3); | ||||||
|  | 					glVertexAttribDivisor(8, 1); | ||||||
|  | 					glEnableVertexAttribArray(9); //xform y
 | ||||||
|  | 					glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4); | ||||||
|  | 					glVertexAttribDivisor(9, 1); | ||||||
|  | 					glEnableVertexAttribArray(10); //xform z
 | ||||||
|  | 					glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5); | ||||||
|  | 					glVertexAttribDivisor(10, 1); | ||||||
|  | 					glEnableVertexAttribArray(11); //color
 | ||||||
|  | 					glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); | ||||||
|  | 					glVertexAttribDivisor(11, 1); | ||||||
|  | 					glEnableVertexAttribArray(12); //custom
 | ||||||
|  | 					glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 2); | ||||||
|  | 					glVertexAttribDivisor(12, 1); | ||||||
|  | 
 | ||||||
|  | 					glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount); | ||||||
|  | 				} else { | ||||||
|  | 					//split
 | ||||||
|  | 
 | ||||||
|  | 					int stride = sizeof(float) * 4 * 6; | ||||||
|  | 					int split = int(Math::ceil(particles->phase * particles->amount)); | ||||||
|  | 
 | ||||||
|  | 					if (amount - split > 0) { | ||||||
|  | 						glEnableVertexAttribArray(8); //xform x
 | ||||||
|  | 						glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 3); | ||||||
|  | 						glVertexAttribDivisor(8, 1); | ||||||
|  | 						glEnableVertexAttribArray(9); //xform y
 | ||||||
|  | 						glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 4); | ||||||
|  | 						glVertexAttribDivisor(9, 1); | ||||||
|  | 						glEnableVertexAttribArray(10); //xform z
 | ||||||
|  | 						glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 5); | ||||||
|  | 						glVertexAttribDivisor(10, 1); | ||||||
|  | 						glEnableVertexAttribArray(11); //color
 | ||||||
|  | 						glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + 0); | ||||||
|  | 						glVertexAttribDivisor(11, 1); | ||||||
|  | 						glEnableVertexAttribArray(12); //custom
 | ||||||
|  | 						glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 2); | ||||||
|  | 						glVertexAttribDivisor(12, 1); | ||||||
|  | 
 | ||||||
|  | 						glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (split > 0) { | ||||||
|  | 						glEnableVertexAttribArray(8); //xform x
 | ||||||
|  | 						glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 3); | ||||||
|  | 						glVertexAttribDivisor(8, 1); | ||||||
|  | 						glEnableVertexAttribArray(9); //xform y
 | ||||||
|  | 						glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4); | ||||||
|  | 						glVertexAttribDivisor(9, 1); | ||||||
|  | 						glEnableVertexAttribArray(10); //xform z
 | ||||||
|  | 						glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5); | ||||||
|  | 						glVertexAttribDivisor(10, 1); | ||||||
|  | 						glEnableVertexAttribArray(11); //color
 | ||||||
|  | 						glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); | ||||||
|  | 						glVertexAttribDivisor(11, 1); | ||||||
|  | 						glEnableVertexAttribArray(12); //custom
 | ||||||
|  | 						glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 2); | ||||||
|  | 						glVertexAttribDivisor(12, 1); | ||||||
|  | 
 | ||||||
|  | 						glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				glBindVertexArray(0); | ||||||
|  | 
 | ||||||
|  | 				state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); | ||||||
|  | 				state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); | ||||||
|  | 				state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); | ||||||
|  | 				state.using_texture_rect = true; | ||||||
|  | 				_set_texture_rect_mode(false); | ||||||
|  | 
 | ||||||
| 			} break; | 			} break; | ||||||
| 			case Item::Command::TYPE_CIRCLE: { | 			case Item::Command::TYPE_CIRCLE: { | ||||||
| 
 | 
 | ||||||
|  | @ -1351,7 +1479,39 @@ void RasterizerCanvasGLES3::initialize() { | ||||||
| 		glBindVertexArray(0); | 		glBindVertexArray(0); | ||||||
| 		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
 | 		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
 | ||||||
| 	} | 	} | ||||||
|  | 	{ | ||||||
|  | 		//particle quad buffers
 | ||||||
| 
 | 
 | ||||||
|  | 		glGenBuffers(1, &data.particle_quad_vertices); | ||||||
|  | 		glBindBuffer(GL_ARRAY_BUFFER, data.particle_quad_vertices); | ||||||
|  | 		{ | ||||||
|  | 			//quad of size 1, with pivot on the center for particles, then regular UVS. Color is general plus fetched from particle
 | ||||||
|  | 			const float qv[16] = { | ||||||
|  | 				-0.5, -0.5, | ||||||
|  | 				0.0, 0.0, | ||||||
|  | 				-0.5, 0.5, | ||||||
|  | 				0.0, 1.0, | ||||||
|  | 				0.5, 0.5, | ||||||
|  | 				1.0, 1.0, | ||||||
|  | 				0.5, -0.5, | ||||||
|  | 				1.0, 0.0 | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
 | ||||||
|  | 
 | ||||||
|  | 		glGenVertexArrays(1, &data.particle_quad_array); | ||||||
|  | 		glBindVertexArray(data.particle_quad_array); | ||||||
|  | 		glBindBuffer(GL_ARRAY_BUFFER, data.particle_quad_vertices); | ||||||
|  | 		glEnableVertexAttribArray(VS::ARRAY_VERTEX); | ||||||
|  | 		glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); | ||||||
|  | 		glEnableVertexAttribArray(VS::ARRAY_TEX_UV); | ||||||
|  | 		glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (float *)0 + 2); | ||||||
|  | 		glBindVertexArray(0); | ||||||
|  | 		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
 | ||||||
|  | 	} | ||||||
| 	{ | 	{ | ||||||
| 
 | 
 | ||||||
| 		uint32_t poly_size = GLOBAL_DEF("rendering/buffers/canvas_polygon_buffer_size_kb", 128); | 		uint32_t poly_size = GLOBAL_DEF("rendering/buffers/canvas_polygon_buffer_size_kb", 128); | ||||||
|  | @ -1428,6 +1588,9 @@ void RasterizerCanvasGLES3::finalize() { | ||||||
| 	glDeleteBuffers(1, &data.canvas_quad_vertices); | 	glDeleteBuffers(1, &data.canvas_quad_vertices); | ||||||
| 	glDeleteVertexArrays(1, &data.canvas_quad_array); | 	glDeleteVertexArrays(1, &data.canvas_quad_array); | ||||||
| 
 | 
 | ||||||
|  | 	glDeleteBuffers(1, &data.canvas_quad_vertices); | ||||||
|  | 	glDeleteVertexArrays(1, &data.canvas_quad_array); | ||||||
|  | 
 | ||||||
| 	glDeleteVertexArrays(1, &data.polygon_buffer_pointer_array); | 	glDeleteVertexArrays(1, &data.polygon_buffer_pointer_array); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -51,6 +51,10 @@ public: | ||||||
| 		GLuint polygon_buffer_quad_arrays[4]; | 		GLuint polygon_buffer_quad_arrays[4]; | ||||||
| 		GLuint polygon_buffer_pointer_array; | 		GLuint polygon_buffer_pointer_array; | ||||||
| 		GLuint polygon_index_buffer; | 		GLuint polygon_index_buffer; | ||||||
|  | 
 | ||||||
|  | 		GLuint particle_quad_vertices; | ||||||
|  | 		GLuint particle_quad_array; | ||||||
|  | 
 | ||||||
| 		uint32_t polygon_buffer_size; | 		uint32_t polygon_buffer_size; | ||||||
| 
 | 
 | ||||||
| 	} data; | 	} data; | ||||||
|  |  | ||||||
|  | @ -2326,6 +2326,9 @@ void RasterizerStorageGLES3::_update_material(Material *material) { | ||||||
| 			if (E->get().order < 0) | 			if (E->get().order < 0) | ||||||
| 				continue; // texture, does not go here
 | 				continue; // texture, does not go here
 | ||||||
| 
 | 
 | ||||||
|  | 			//if (material->shader->mode == VS::SHADER_PARTICLES) {
 | ||||||
|  | 			//	print_line("uniform " + String(E->key()) + " order " + itos(E->get().order) + " offset " + itos(material->shader->ubo_offsets[E->get().order]));
 | ||||||
|  | 			//}
 | ||||||
| 			//regular uniform
 | 			//regular uniform
 | ||||||
| 			uint8_t *data = &local_ubo[material->shader->ubo_offsets[E->get().order]]; | 			uint8_t *data = &local_ubo[material->shader->ubo_offsets[E->get().order]]; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -361,6 +361,8 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { | ||||||
| 		ERR_FAIL_V(NULL); | 		ERR_FAIL_V(NULL); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	//_display_error_with_code("pepo", strings);
 | ||||||
|  | 
 | ||||||
| 	/* FRAGMENT SHADER */ | 	/* FRAGMENT SHADER */ | ||||||
| 
 | 
 | ||||||
| 	strings.resize(strings_base_size); | 	strings.resize(strings_base_size); | ||||||
|  |  | ||||||
|  | @ -11,11 +11,26 @@ uniform vec4 src_rect; | ||||||
| 
 | 
 | ||||||
| #else | #else | ||||||
| 
 | 
 | ||||||
|  | #ifdef USE_INSTANCING | ||||||
|  | 
 | ||||||
|  | layout(location=8) in highp vec4 instance_xform0; | ||||||
|  | layout(location=9) in highp vec4 instance_xform1; | ||||||
|  | layout(location=10) in highp vec4 instance_xform2; | ||||||
|  | layout(location=11) in lowp vec4 instance_color; | ||||||
|  | 
 | ||||||
|  | #ifdef USE_INSTANCE_CUSTOM | ||||||
|  | layout(location=12) in highp vec4 instance_custom_data; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| layout(location=4) in highp vec2 uv_attrib; | layout(location=4) in highp vec2 uv_attrib; | ||||||
| 
 | 
 | ||||||
| //skeletn | //skeletn | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | uniform highp vec2 color_texpixel_size; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| layout(std140) uniform CanvasItemData { //ubo:0 | layout(std140) uniform CanvasItemData { //ubo:0 | ||||||
| 
 | 
 | ||||||
|  | @ -64,7 +79,10 @@ const bool at_light_pass = true; | ||||||
| const bool at_light_pass = false; | const bool at_light_pass = false; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 
 | #ifdef USE_PARTICLES | ||||||
|  | uniform int h_frames; | ||||||
|  | uniform int v_frames; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| VERTEX_SHADER_GLOBALS | VERTEX_SHADER_GLOBALS | ||||||
| 
 | 
 | ||||||
|  | @ -82,6 +100,12 @@ void main() { | ||||||
| 
 | 
 | ||||||
| 	vec4 vertex_color = color_attrib; | 	vec4 vertex_color = color_attrib; | ||||||
| 
 | 
 | ||||||
|  | #ifdef USE_INSTANCING | ||||||
|  | 	mat4 extra_matrix2 = extra_matrix * transpose(mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0))); | ||||||
|  | 	vertex_color*=instance_color; | ||||||
|  | #else | ||||||
|  | 	mat4 extra_matrix2 = extra_matrix; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef USE_TEXTURE_RECT | #ifdef USE_TEXTURE_RECT | ||||||
| 
 | 
 | ||||||
|  | @ -95,6 +119,22 @@ void main() { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #ifdef USE_PARTICLES | ||||||
|  | 	//scale by texture size | ||||||
|  | 	outvec.xy/=color_texpixel_size; | ||||||
|  | 
 | ||||||
|  | 	//compute h and v frames and adjust UV interp for animation | ||||||
|  | 	int total_frames = h_frames * v_frames; | ||||||
|  | 	int frame = min(int(float(total_frames) *instance_custom_data.z),total_frames-1); | ||||||
|  | 	float frame_w = 1.0/float(h_frames); | ||||||
|  | 	float frame_h = 1.0/float(v_frames); | ||||||
|  | 	uv_interp.x = uv_interp.x * frame_w + frame_w * float(frame % h_frames); | ||||||
|  | 	uv_interp.y = uv_interp.y * frame_h + frame_h * float(frame / v_frames); | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define extra_matrix extra_matrix2 | ||||||
|  | 
 | ||||||
| { | { | ||||||
| 	vec2 src_vtx=outvec.xy; | 	vec2 src_vtx=outvec.xy; | ||||||
| 
 | 
 | ||||||
|  | @ -107,6 +147,8 @@ VERTEX_SHADER_CODE | ||||||
| 	outvec = modelview_matrix * outvec; | 	outvec = modelview_matrix * outvec; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #undef extra_matrix | ||||||
|  | 
 | ||||||
| 	color_interp = vertex_color; | 	color_interp = vertex_color; | ||||||
| 
 | 
 | ||||||
| #ifdef USE_PIXEL_SNAP | #ifdef USE_PIXEL_SNAP | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 443 B | 
|  | @ -31,8 +31,8 @@ | ||||||
| 
 | 
 | ||||||
| #include "canvas_item_editor_plugin.h" | #include "canvas_item_editor_plugin.h" | ||||||
| #include "io/image_loader.h" | #include "io/image_loader.h" | ||||||
|  | #include "scene/3d/particles.h" | ||||||
| #include "scene/gui/separator.h" | #include "scene/gui/separator.h" | ||||||
| 
 |  | ||||||
| void Particles2DEditorPlugin::edit(Object *p_object) { | void Particles2DEditorPlugin::edit(Object *p_object) { | ||||||
| 
 | 
 | ||||||
| 	if (p_object) { | 	if (p_object) { | ||||||
|  | @ -62,65 +62,16 @@ void Particles2DEditorPlugin::_file_selected(const String &p_file) { | ||||||
| 
 | 
 | ||||||
| 	print_line("file: " + p_file); | 	print_line("file: " + p_file); | ||||||
| 
 | 
 | ||||||
| 	int epc = epoints->get_value(); | 	source_emission_file = p_file; | ||||||
| 
 | 	emission_mask->popup_centered_minsize(); | ||||||
| 	Ref<Image> img; |  | ||||||
| 	img.instance(); |  | ||||||
| 	Error err = ImageLoader::load_image(p_file, img); |  | ||||||
| 	ERR_EXPLAIN(TTR("Error loading image:") + " " + p_file); |  | ||||||
| 	ERR_FAIL_COND(err != OK); |  | ||||||
| 
 |  | ||||||
| 	img->convert(Image::FORMAT_LA8); |  | ||||||
| 	ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8); |  | ||||||
| 	Size2i s = Size2(img->get_width(), img->get_height()); |  | ||||||
| 	ERR_FAIL_COND(s.width == 0 || s.height == 0); |  | ||||||
| 
 |  | ||||||
| 	PoolVector<uint8_t> data = img->get_data(); |  | ||||||
| 	PoolVector<uint8_t>::Read r = data.read(); |  | ||||||
| 
 |  | ||||||
| 	Vector<Point2i> valid_positions; |  | ||||||
| 	valid_positions.resize(s.width * s.height); |  | ||||||
| 	int vpc = 0; |  | ||||||
| 
 |  | ||||||
| 	for (int i = 0; i < s.width * s.height; i++) { |  | ||||||
| 
 |  | ||||||
| 		uint8_t a = r[i * 2 + 1]; |  | ||||||
| 		if (a > 128) { |  | ||||||
| 			valid_positions[vpc++] = Point2i(i % s.width, i / s.width); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	valid_positions.resize(vpc); |  | ||||||
| 
 |  | ||||||
| 	ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image..")); |  | ||||||
| 	ERR_FAIL_COND(valid_positions.size() == 0); |  | ||||||
| 
 |  | ||||||
| 	PoolVector<Point2> epoints; |  | ||||||
| 	epoints.resize(epc); |  | ||||||
| 	PoolVector<Point2>::Write w = epoints.write(); |  | ||||||
| 
 |  | ||||||
| 	Size2 extents = Size2(img->get_width() * 0.5, img->get_height() * 0.5); |  | ||||||
| 
 |  | ||||||
| 	for (int i = 0; i < epc; i++) { |  | ||||||
| 
 |  | ||||||
| 		Point2 p = valid_positions[Math::rand() % vpc]; |  | ||||||
| 		p -= s / 2; |  | ||||||
| 		w[i] = p / extents; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	w = PoolVector<Point2>::Write(); |  | ||||||
| 
 |  | ||||||
| 	undo_redo->create_action(TTR("Set Emission Mask")); |  | ||||||
| 	undo_redo->add_do_method(particles, "set_emission_points", epoints); |  | ||||||
| 	undo_redo->add_do_method(particles, "set_emission_half_extents", extents); |  | ||||||
| 	undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points()); |  | ||||||
| 	undo_redo->add_undo_method(particles, "set_emission_half_extents", particles->get_emission_half_extents()); |  | ||||||
| 	undo_redo->commit_action(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Particles2DEditorPlugin::_menu_callback(int p_idx) { | void Particles2DEditorPlugin::_menu_callback(int p_idx) { | ||||||
| 
 | 
 | ||||||
| 	switch (p_idx) { | 	switch (p_idx) { | ||||||
|  | 		case MENU_GENERATE_VISIBILITY_RECT: { | ||||||
|  | 			generate_aabb->popup_centered_minsize(); | ||||||
|  | 		} break; | ||||||
| 		case MENU_LOAD_EMISSION_MASK: { | 		case MENU_LOAD_EMISSION_MASK: { | ||||||
| 
 | 
 | ||||||
| 			file->popup_centered_ratio(); | 			file->popup_centered_ratio(); | ||||||
|  | @ -128,14 +79,249 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) { | ||||||
| 		} break; | 		} break; | ||||||
| 		case MENU_CLEAR_EMISSION_MASK: { | 		case MENU_CLEAR_EMISSION_MASK: { | ||||||
| 
 | 
 | ||||||
| 			undo_redo->create_action(TTR("Clear Emission Mask")); | 			emission_mask->popup_centered_minsize(); | ||||||
|  | 
 | ||||||
|  | 			/*undo_redo->create_action(TTR("Clear Emission Mask"));
 | ||||||
| 			undo_redo->add_do_method(particles, "set_emission_points", PoolVector<Vector2>()); | 			undo_redo->add_do_method(particles, "set_emission_points", PoolVector<Vector2>()); | ||||||
| 			undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points()); | 			undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points()); | ||||||
| 			undo_redo->commit_action(); | 			undo_redo->commit_action();*/ | ||||||
| 		} break; | 		} break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Particles2DEditorPlugin::_generate_visibility_rect() { | ||||||
|  | 
 | ||||||
|  | 	float time = generate_seconds->get_value(); | ||||||
|  | 
 | ||||||
|  | 	float running = 0.0; | ||||||
|  | 
 | ||||||
|  | 	EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time)); | ||||||
|  | 
 | ||||||
|  | 	Rect2 rect; | ||||||
|  | 	while (running < time) { | ||||||
|  | 
 | ||||||
|  | 		uint64_t ticks = OS::get_singleton()->get_ticks_usec(); | ||||||
|  | 		ep.step("Generating..", int(running), true); | ||||||
|  | 		OS::get_singleton()->delay_usec(1000); | ||||||
|  | 
 | ||||||
|  | 		Rect2 capture = particles->capture_rect(); | ||||||
|  | 		if (rect == Rect2()) | ||||||
|  | 			rect = capture; | ||||||
|  | 		else | ||||||
|  | 			rect = rect.merge(capture); | ||||||
|  | 
 | ||||||
|  | 		running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	particles->set_visibility_rect(rect); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Particles2DEditorPlugin::_generate_emission_mask() { | ||||||
|  | 
 | ||||||
|  | 	Ref<ParticlesMaterial> pm = particles->get_process_material(); | ||||||
|  | 	if (!pm.is_valid()) { | ||||||
|  | 		EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material")); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Ref<Image> img; | ||||||
|  | 	img.instance(); | ||||||
|  | 	Error err = ImageLoader::load_image(source_emission_file, img); | ||||||
|  | 	ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file); | ||||||
|  | 	ERR_FAIL_COND(err != OK); | ||||||
|  | 
 | ||||||
|  | 	if (img->is_compressed()) { | ||||||
|  | 		img->decompress(); | ||||||
|  | 	} | ||||||
|  | 	img->convert(Image::FORMAT_RGBA8); | ||||||
|  | 	ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8); | ||||||
|  | 	Size2i s = Size2(img->get_width(), img->get_height()); | ||||||
|  | 	ERR_FAIL_COND(s.width == 0 || s.height == 0); | ||||||
|  | 
 | ||||||
|  | 	Vector<Point2> valid_positions; | ||||||
|  | 	Vector<Point2> valid_normals; | ||||||
|  | 	Vector<uint8_t> valid_colors; | ||||||
|  | 
 | ||||||
|  | 	valid_positions.resize(s.width * s.height); | ||||||
|  | 
 | ||||||
|  | 	EmissionMode emode = (EmissionMode)emission_mask_mode->get_selected(); | ||||||
|  | 
 | ||||||
|  | 	if (emode == EMISSION_MODE_BORDER_DIRECTED) { | ||||||
|  | 		valid_normals.resize(s.width * s.height); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool capture_colors = emission_colors->is_pressed(); | ||||||
|  | 
 | ||||||
|  | 	if (capture_colors) { | ||||||
|  | 		valid_colors.resize(s.width * s.height * 4); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	int vpc = 0; | ||||||
|  | 
 | ||||||
|  | 	{ | ||||||
|  | 		PoolVector<uint8_t> data = img->get_data(); | ||||||
|  | 		PoolVector<uint8_t>::Read r = data.read(); | ||||||
|  | 
 | ||||||
|  | 		for (int i = 0; i < s.width; i++) { | ||||||
|  | 			for (int j = 0; j < s.height; j++) { | ||||||
|  | 
 | ||||||
|  | 				uint8_t a = r[(j * s.width + i) * 4 + 3]; | ||||||
|  | 
 | ||||||
|  | 				if (a > 128) { | ||||||
|  | 
 | ||||||
|  | 					if (emode == EMISSION_MODE_SOLID) { | ||||||
|  | 
 | ||||||
|  | 						if (capture_colors) { | ||||||
|  | 							valid_colors[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; | ||||||
|  | 							valid_colors[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; | ||||||
|  | 							valid_colors[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; | ||||||
|  | 							valid_colors[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; | ||||||
|  | 						} | ||||||
|  | 						valid_positions[vpc++] = Point2(i, j); | ||||||
|  | 
 | ||||||
|  | 					} else { | ||||||
|  | 
 | ||||||
|  | 						bool on_border = false; | ||||||
|  | 						for (int x = i - 1; x <= i + 1; x++) { | ||||||
|  | 							for (int y = j - 1; y <= j + 1; y++) { | ||||||
|  | 
 | ||||||
|  | 								if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) { | ||||||
|  | 									on_border = true; | ||||||
|  | 									break; | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  | 
 | ||||||
|  | 							if (on_border) | ||||||
|  | 								break; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						if (on_border) { | ||||||
|  | 							valid_positions[vpc] = Point2(i, j); | ||||||
|  | 
 | ||||||
|  | 							if (emode == EMISSION_MODE_BORDER_DIRECTED) { | ||||||
|  | 								Vector2 normal; | ||||||
|  | 								for (int x = i - 2; x <= i + 2; x++) { | ||||||
|  | 									for (int y = j - 2; y <= j + 2; y++) { | ||||||
|  | 
 | ||||||
|  | 										if (x == i && y == j) | ||||||
|  | 											continue; | ||||||
|  | 
 | ||||||
|  | 										if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) { | ||||||
|  | 											normal += Vector2(x - i, y - j).normalized(); | ||||||
|  | 										} | ||||||
|  | 									} | ||||||
|  | 								} | ||||||
|  | 
 | ||||||
|  | 								normal.normalize(); | ||||||
|  | 								valid_normals[vpc] = normal; | ||||||
|  | 							} | ||||||
|  | 
 | ||||||
|  | 							if (capture_colors) { | ||||||
|  | 								valid_colors[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; | ||||||
|  | 								valid_colors[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; | ||||||
|  | 								valid_colors[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; | ||||||
|  | 								valid_colors[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; | ||||||
|  | 							} | ||||||
|  | 
 | ||||||
|  | 							vpc++; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	valid_positions.resize(vpc); | ||||||
|  | 	if (valid_normals.size()) { | ||||||
|  | 		valid_normals.resize(vpc); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image..")); | ||||||
|  | 	ERR_FAIL_COND(valid_positions.size() == 0); | ||||||
|  | 
 | ||||||
|  | 	PoolVector<uint8_t> texdata; | ||||||
|  | 
 | ||||||
|  | 	int w = 2048; | ||||||
|  | 	int h = (vpc / 2048) + 1; | ||||||
|  | 
 | ||||||
|  | 	texdata.resize(w * h * 2 * sizeof(float)); | ||||||
|  | 
 | ||||||
|  | 	{ | ||||||
|  | 		PoolVector<uint8_t>::Write tw = texdata.write(); | ||||||
|  | 		float *twf = (float *)tw.ptr(); | ||||||
|  | 		for (int i = 0; i < vpc; i++) { | ||||||
|  | 
 | ||||||
|  | 			twf[i * 2 + 0] = valid_positions[i].x; | ||||||
|  | 			twf[i * 2 + 1] = valid_positions[i].y; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	img.instance(); | ||||||
|  | 	img->create(w, h, false, Image::FORMAT_RGF, texdata); | ||||||
|  | 
 | ||||||
|  | 	Ref<ImageTexture> imgt; | ||||||
|  | 	imgt.instance(); | ||||||
|  | 	imgt->create_from_image(img, 0); | ||||||
|  | 
 | ||||||
|  | 	pm->set_emission_point_texture(imgt); | ||||||
|  | 	pm->set_emission_point_count(vpc); | ||||||
|  | 
 | ||||||
|  | 	if (capture_colors) { | ||||||
|  | 
 | ||||||
|  | 		PoolVector<uint8_t> colordata; | ||||||
|  | 		colordata.resize(w * h * 4); //use RG texture
 | ||||||
|  | 
 | ||||||
|  | 		{ | ||||||
|  | 			PoolVector<uint8_t>::Write tw = colordata.write(); | ||||||
|  | 			for (int i = 0; i < vpc * 4; i++) { | ||||||
|  | 
 | ||||||
|  | 				tw[i] = valid_colors[i]; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		img.instance(); | ||||||
|  | 		img->create(w, h, false, Image::FORMAT_RGBA8, colordata); | ||||||
|  | 
 | ||||||
|  | 		imgt.instance(); | ||||||
|  | 		imgt->create_from_image(img, 0); | ||||||
|  | 		pm->set_emission_color_texture(imgt); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (valid_normals.size()) { | ||||||
|  | 		pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS); | ||||||
|  | 
 | ||||||
|  | 		PoolVector<uint8_t> normdata; | ||||||
|  | 		normdata.resize(w * h * 2 * sizeof(float)); //use RG texture
 | ||||||
|  | 
 | ||||||
|  | 		{ | ||||||
|  | 			PoolVector<uint8_t>::Write tw = normdata.write(); | ||||||
|  | 			float *twf = (float *)tw.ptr(); | ||||||
|  | 			for (int i = 0; i < vpc; i++) { | ||||||
|  | 				twf[i * 2 + 0] = valid_normals[i].x; | ||||||
|  | 				twf[i * 2 + 1] = valid_normals[i].y; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		img.instance(); | ||||||
|  | 		img->create(w, h, false, Image::FORMAT_RGF, normdata); | ||||||
|  | 
 | ||||||
|  | 		imgt.instance(); | ||||||
|  | 		imgt->create_from_image(img, 0); | ||||||
|  | 		pm->set_emission_normal_texture(imgt); | ||||||
|  | 
 | ||||||
|  | 	} else { | ||||||
|  | 		pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*undo_redo->create_action(TTR("Set Emission Mask"));
 | ||||||
|  | 	undo_redo->add_do_method(particles, "set_emission_points", epoints); | ||||||
|  | 	undo_redo->add_do_method(particles, "set_emission_half_extents", extents); | ||||||
|  | 	undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points()); | ||||||
|  | 	undo_redo->add_undo_method(particles, "set_emission_half_extents", particles->get_emission_half_extents()); | ||||||
|  | 	undo_redo->commit_action(); | ||||||
|  | 	*/ | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Particles2DEditorPlugin::_notification(int p_what) { | void Particles2DEditorPlugin::_notification(int p_what) { | ||||||
| 
 | 
 | ||||||
| 	if (p_what == NOTIFICATION_ENTER_TREE) { | 	if (p_what == NOTIFICATION_ENTER_TREE) { | ||||||
|  | @ -150,6 +336,8 @@ void Particles2DEditorPlugin::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("_menu_callback"), &Particles2DEditorPlugin::_menu_callback); | 	ClassDB::bind_method(D_METHOD("_menu_callback"), &Particles2DEditorPlugin::_menu_callback); | ||||||
| 	ClassDB::bind_method(D_METHOD("_file_selected"), &Particles2DEditorPlugin::_file_selected); | 	ClassDB::bind_method(D_METHOD("_file_selected"), &Particles2DEditorPlugin::_file_selected); | ||||||
|  | 	ClassDB::bind_method(D_METHOD("_generate_visibility_rect"), &Particles2DEditorPlugin::_generate_visibility_rect); | ||||||
|  | 	ClassDB::bind_method(D_METHOD("_generate_emission_mask"), &Particles2DEditorPlugin::_generate_emission_mask); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { | Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { | ||||||
|  | @ -165,8 +353,10 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { | ||||||
| 	toolbar->add_child(memnew(VSeparator)); | 	toolbar->add_child(memnew(VSeparator)); | ||||||
| 
 | 
 | ||||||
| 	menu = memnew(MenuButton); | 	menu = memnew(MenuButton); | ||||||
|  | 	menu->get_popup()->add_item(TTR("Generate Visibility Rect"), MENU_GENERATE_VISIBILITY_RECT); | ||||||
|  | 	menu->get_popup()->add_separator(); | ||||||
| 	menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); | 	menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); | ||||||
| 	menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK); | 	//	menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
 | ||||||
| 	menu->set_text("Particles"); | 	menu->set_text("Particles"); | ||||||
| 	toolbar->add_child(menu); | 	toolbar->add_child(menu); | ||||||
| 
 | 
 | ||||||
|  | @ -185,6 +375,37 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { | ||||||
| 	epoints->set_step(1); | 	epoints->set_step(1); | ||||||
| 	epoints->set_value(512); | 	epoints->set_value(512); | ||||||
| 	file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints); | 	file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints); | ||||||
|  | 
 | ||||||
|  | 	generate_aabb = memnew(ConfirmationDialog); | ||||||
|  | 	generate_aabb->set_title(TTR("Generate Visibility Rect")); | ||||||
|  | 	VBoxContainer *genvb = memnew(VBoxContainer); | ||||||
|  | 	generate_aabb->add_child(genvb); | ||||||
|  | 	generate_seconds = memnew(SpinBox); | ||||||
|  | 	genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds); | ||||||
|  | 	generate_seconds->set_min(0.1); | ||||||
|  | 	generate_seconds->set_max(25); | ||||||
|  | 	generate_seconds->set_value(2); | ||||||
|  | 
 | ||||||
|  | 	toolbar->add_child(generate_aabb); | ||||||
|  | 
 | ||||||
|  | 	generate_aabb->connect("confirmed", this, "_generate_visibility_rect"); | ||||||
|  | 
 | ||||||
|  | 	emission_mask = memnew(ConfirmationDialog); | ||||||
|  | 	emission_mask->set_title(TTR("Generate Visibility Rect")); | ||||||
|  | 	VBoxContainer *emvb = memnew(VBoxContainer); | ||||||
|  | 	emission_mask->add_child(emvb); | ||||||
|  | 	emission_mask_mode = memnew(OptionButton); | ||||||
|  | 	emvb->add_margin_child(TTR("Emission Mask"), emission_mask_mode); | ||||||
|  | 	emission_mask_mode->add_item("Solid Pixels", EMISSION_MODE_SOLID); | ||||||
|  | 	emission_mask_mode->add_item("Border Pixels", EMISSION_MODE_BORDER); | ||||||
|  | 	emission_mask_mode->add_item("Directed Border Pixels", EMISSION_MODE_BORDER_DIRECTED); | ||||||
|  | 	emission_colors = memnew(CheckBox); | ||||||
|  | 	emission_colors->set_text(TTR("Capture from Pixel")); | ||||||
|  | 	emvb->add_margin_child(TTR("Emission Colors"), emission_colors); | ||||||
|  | 
 | ||||||
|  | 	toolbar->add_child(emission_mask); | ||||||
|  | 
 | ||||||
|  | 	emission_mask->connect("confirmed", this, "_generate_emission_mask"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Particles2DEditorPlugin::~Particles2DEditorPlugin() { | Particles2DEditorPlugin::~Particles2DEditorPlugin() { | ||||||
|  |  | ||||||
|  | @ -44,10 +44,17 @@ class Particles2DEditorPlugin : public EditorPlugin { | ||||||
| 
 | 
 | ||||||
| 	enum { | 	enum { | ||||||
| 
 | 
 | ||||||
|  | 		MENU_GENERATE_VISIBILITY_RECT, | ||||||
| 		MENU_LOAD_EMISSION_MASK, | 		MENU_LOAD_EMISSION_MASK, | ||||||
| 		MENU_CLEAR_EMISSION_MASK | 		MENU_CLEAR_EMISSION_MASK | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | 	enum EmissionMode { | ||||||
|  | 		EMISSION_MODE_SOLID, | ||||||
|  | 		EMISSION_MODE_BORDER, | ||||||
|  | 		EMISSION_MODE_BORDER_DIRECTED | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| 	Particles2D *particles; | 	Particles2D *particles; | ||||||
| 
 | 
 | ||||||
| 	EditorFileDialog *file; | 	EditorFileDialog *file; | ||||||
|  | @ -58,9 +65,20 @@ class Particles2DEditorPlugin : public EditorPlugin { | ||||||
| 
 | 
 | ||||||
| 	SpinBox *epoints; | 	SpinBox *epoints; | ||||||
| 
 | 
 | ||||||
|  | 	ConfirmationDialog *generate_aabb; | ||||||
|  | 	SpinBox *generate_seconds; | ||||||
|  | 
 | ||||||
|  | 	ConfirmationDialog *emission_mask; | ||||||
|  | 	OptionButton *emission_mask_mode; | ||||||
|  | 	CheckBox *emission_colors; | ||||||
|  | 
 | ||||||
|  | 	String source_emission_file; | ||||||
|  | 
 | ||||||
| 	UndoRedo *undo_redo; | 	UndoRedo *undo_redo; | ||||||
| 	void _file_selected(const String &p_file); | 	void _file_selected(const String &p_file); | ||||||
| 	void _menu_callback(int p_idx); | 	void _menu_callback(int p_idx); | ||||||
|  | 	void _generate_visibility_rect(); | ||||||
|  | 	void _generate_emission_mask(); | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	void _notification(int p_what); | 	void _notification(int p_what); | ||||||
|  |  | ||||||
|  | @ -417,14 +417,22 @@ void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color | ||||||
| 	VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased); | 	VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color) { | void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled) { | ||||||
| 
 | 
 | ||||||
| 	if (!drawing) { | 	if (!drawing) { | ||||||
| 		ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); | 		ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); | ||||||
| 		ERR_FAIL(); | 		ERR_FAIL(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (p_filled) { | ||||||
|  | 
 | ||||||
| 		VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color); | 		VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color); | ||||||
|  | 	} else { | ||||||
|  | 		VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position, p_rect.position + Size2(p_rect.size.width, 0), p_color); | ||||||
|  | 		VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position, p_rect.position + Size2(0, p_rect.size.height), p_color); | ||||||
|  | 		VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position + Point2(0, p_rect.size.height), p_rect.position + p_rect.size, p_color); | ||||||
|  | 		VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position + Point2(p_rect.size.width, 0), p_rect.position + p_rect.size, p_color); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) { | void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) { | ||||||
|  | @ -754,7 +762,7 @@ void CanvasItem::_bind_methods() { | ||||||
| 	//ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
 | 	//ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
 | ||||||
| 
 | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false)); | 	ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false)); | ||||||
| 	ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color"), &CanvasItem::draw_rect); | 	ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled"), &CanvasItem::draw_rect, DEFVAL(true)); | ||||||
| 	ClassDB::bind_method(D_METHOD("draw_circle", "pos", "radius", "color"), &CanvasItem::draw_circle); | 	ClassDB::bind_method(D_METHOD("draw_circle", "pos", "radius", "color"), &CanvasItem::draw_circle); | ||||||
| 	ClassDB::bind_method(D_METHOD("draw_texture", "texture:Texture", "pos", "modulate", "normal_map:Texture"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant())); | 	ClassDB::bind_method(D_METHOD("draw_texture", "texture:Texture", "pos", "modulate", "normal_map:Texture"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant())); | ||||||
| 	ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture:Texture", "rect", "tile", "modulate", "transpose", "normal_map:Texture"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant())); | 	ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture:Texture", "rect", "tile", "modulate", "transpose", "normal_map:Texture"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant())); | ||||||
|  |  | ||||||
|  | @ -156,7 +156,7 @@ public: | ||||||
| 	/* DRAWING API */ | 	/* DRAWING API */ | ||||||
| 
 | 
 | ||||||
| 	void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); | 	void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); | ||||||
| 	void draw_rect(const Rect2 &p_rect, const Color &p_color); | 	void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true); | ||||||
| 	void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color); | 	void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color); | ||||||
| 	void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>()); | 	void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>()); | ||||||
| 	void draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()); | 	void draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()); | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -34,235 +34,98 @@ | ||||||
| #include "scene/resources/color_ramp.h" | #include "scene/resources/color_ramp.h" | ||||||
| #include "scene/resources/texture.h" | #include "scene/resources/texture.h" | ||||||
| 
 | 
 | ||||||
| class Particles2D; |  | ||||||
| class ParticleAttractor2D : public Node2D { |  | ||||||
| 
 |  | ||||||
| 	GDCLASS(ParticleAttractor2D, Node2D); |  | ||||||
| 
 |  | ||||||
| 	friend class Particles2D; |  | ||||||
| 	bool enabled; |  | ||||||
| 	float radius; |  | ||||||
| 	float disable_radius; |  | ||||||
| 	float gravity; |  | ||||||
| 	float absorption; |  | ||||||
| 	NodePath path; |  | ||||||
| 
 |  | ||||||
| 	Particles2D *owner; |  | ||||||
| 
 |  | ||||||
| 	void _update_owner(); |  | ||||||
| 	void _owner_exited(); |  | ||||||
| 	void _set_owner(Particles2D *p_owner); |  | ||||||
| 
 |  | ||||||
| 	void _notification(int p_what); |  | ||||||
| 	static void _bind_methods(); |  | ||||||
| 
 |  | ||||||
| public: |  | ||||||
| 	void set_enabled(bool p_enabled); |  | ||||||
| 	bool is_enabled() const; |  | ||||||
| 
 |  | ||||||
| 	void set_radius(float p_radius); |  | ||||||
| 	float get_radius() const; |  | ||||||
| 
 |  | ||||||
| 	void set_disable_radius(float p_disable_radius); |  | ||||||
| 	float get_disable_radius() const; |  | ||||||
| 
 |  | ||||||
| 	void set_gravity(float p_gravity); |  | ||||||
| 	float get_gravity() const; |  | ||||||
| 
 |  | ||||||
| 	void set_absorption(float p_absorption); |  | ||||||
| 	float get_absorption() const; |  | ||||||
| 
 |  | ||||||
| 	void set_particles_path(NodePath p_path); |  | ||||||
| 	NodePath get_particles_path() const; |  | ||||||
| 
 |  | ||||||
| 	virtual String get_configuration_warning() const; |  | ||||||
| 
 |  | ||||||
| 	ParticleAttractor2D(); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class Particles2D : public Node2D { | class Particles2D : public Node2D { | ||||||
| 
 | private: | ||||||
| 	GDCLASS(Particles2D, Node2D); | 	GDCLASS(Particles2D, Node2D) | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	enum Parameter { | 	enum DrawOrder { | ||||||
| 		PARAM_DIRECTION, | 		DRAW_ORDER_INDEX, | ||||||
| 		PARAM_SPREAD, | 		DRAW_ORDER_LIFETIME, | ||||||
| 		PARAM_LINEAR_VELOCITY, |  | ||||||
| 		PARAM_SPIN_VELOCITY, |  | ||||||
| 		PARAM_ORBIT_VELOCITY, |  | ||||||
| 		PARAM_GRAVITY_DIRECTION, |  | ||||||
| 		PARAM_GRAVITY_STRENGTH, |  | ||||||
| 		PARAM_RADIAL_ACCEL, |  | ||||||
| 		PARAM_TANGENTIAL_ACCEL, |  | ||||||
| 		PARAM_DAMPING, |  | ||||||
| 		PARAM_INITIAL_ANGLE, |  | ||||||
| 		PARAM_INITIAL_SIZE, |  | ||||||
| 		PARAM_FINAL_SIZE, |  | ||||||
| 		PARAM_HUE_VARIATION, |  | ||||||
| 		PARAM_ANIM_SPEED_SCALE, |  | ||||||
| 		PARAM_ANIM_INITIAL_POS, |  | ||||||
| 		PARAM_MAX |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	enum { |  | ||||||
| 		MAX_COLOR_PHASES = 4 |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	enum ProcessMode { |  | ||||||
| 		PROCESS_FIXED, |  | ||||||
| 		PROCESS_IDLE, |  | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	float param[PARAM_MAX]; | 	RID particles; | ||||||
| 	float randomness[PARAM_MAX]; |  | ||||||
| 
 | 
 | ||||||
| 	struct Particle { |  | ||||||
| 		bool active; |  | ||||||
| 		Point2 pos; |  | ||||||
| 		Vector2 velocity; |  | ||||||
| 		float rot; |  | ||||||
| 		float frame; |  | ||||||
| 		uint64_t seed; |  | ||||||
| 		Particle() { |  | ||||||
| 			active = false; |  | ||||||
| 			seed = 123465789; |  | ||||||
| 			rot = 0; |  | ||||||
| 			frame = 0; |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	Vector<Particle> particles; |  | ||||||
| 
 |  | ||||||
| 	struct AttractorCache { |  | ||||||
| 
 |  | ||||||
| 		Vector2 pos; |  | ||||||
| 		ParticleAttractor2D *attractor; |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	Vector<AttractorCache> attractor_cache; |  | ||||||
| 
 |  | ||||||
| 	float explosiveness; |  | ||||||
| 	float preprocess; |  | ||||||
| 	float lifetime; |  | ||||||
| 	bool emitting; | 	bool emitting; | ||||||
| 	bool local_space; | 	int amount; | ||||||
| 	float emit_timeout; | 	float lifetime; | ||||||
| 	float time_to_live; | 	float pre_process_time; | ||||||
| 	float time_scale; | 	float explosiveness_ratio; | ||||||
| 	bool flip_h; | 	float randomness_ratio; | ||||||
| 	bool flip_v; | 	float speed_scale; | ||||||
| 	int h_frames; | 	Rect2 visibility_rect; | ||||||
|  | 	bool local_coords; | ||||||
|  | 	int fixed_fps; | ||||||
|  | 	bool fractional_delta; | ||||||
| 	int v_frames; | 	int v_frames; | ||||||
| 	Point2 emissor_offset; | 	int h_frames; | ||||||
| 	Vector2 initial_velocity; |  | ||||||
| 	Vector2 extents; |  | ||||||
| 	PoolVector<Vector2> emission_points; |  | ||||||
| 
 | 
 | ||||||
| 	ProcessMode process_mode; | 	Ref<Material> process_material; | ||||||
| 
 | 
 | ||||||
| 	float time; | 	DrawOrder draw_order; | ||||||
| 	int active_count; |  | ||||||
| 
 | 
 | ||||||
| 	Ref<Texture> texture; | 	Ref<Texture> texture; | ||||||
|  | 	Ref<Texture> normal_map; | ||||||
| 
 | 
 | ||||||
| 	//If no color ramp is set then default color is used. Created as simple alternative to color_ramp.
 | 	void _update_particle_emission_transform(); | ||||||
| 	Color default_color; |  | ||||||
| 	Ref<Gradient> gradient; |  | ||||||
| 
 |  | ||||||
| 	void _process_particles(float p_delta); |  | ||||||
| 	friend class ParticleAttractor2D; |  | ||||||
| 
 |  | ||||||
| 	Set<ParticleAttractor2D *> attractors; |  | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
| 	void _notification(int p_what); |  | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
|  | 	virtual void _validate_property(PropertyInfo &property) const; | ||||||
|  | 	void _notification(int p_what); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 	void set_emitting(bool p_emitting); | 	void set_emitting(bool p_emitting); | ||||||
| 	bool is_emitting() const; |  | ||||||
| 
 |  | ||||||
| 	void set_process_mode(ProcessMode p_mode); |  | ||||||
| 	ProcessMode get_process_mode() const; |  | ||||||
| 
 |  | ||||||
| 	void set_amount(int p_amount); | 	void set_amount(int p_amount); | ||||||
| 	int get_amount() const; |  | ||||||
| 
 |  | ||||||
| 	void set_lifetime(float p_lifetime); | 	void set_lifetime(float p_lifetime); | ||||||
|  | 	void set_pre_process_time(float p_time); | ||||||
|  | 	void set_explosiveness_ratio(float p_ratio); | ||||||
|  | 	void set_randomness_ratio(float p_ratio); | ||||||
|  | 	void set_visibility_rect(const Rect2 &p_aabb); | ||||||
|  | 	void set_use_local_coordinates(bool p_enable); | ||||||
|  | 	void set_process_material(const Ref<Material> &p_material); | ||||||
|  | 	void set_speed_scale(float p_scale); | ||||||
|  | 
 | ||||||
|  | 	bool is_emitting() const; | ||||||
|  | 	int get_amount() const; | ||||||
| 	float get_lifetime() const; | 	float get_lifetime() const; | ||||||
| 
 |  | ||||||
| 	void set_time_scale(float p_time_scale); |  | ||||||
| 	float get_time_scale() const; |  | ||||||
| 
 |  | ||||||
| 	void set_pre_process_time(float p_pre_process_time); |  | ||||||
| 	float get_pre_process_time() const; | 	float get_pre_process_time() const; | ||||||
|  | 	float get_explosiveness_ratio() const; | ||||||
|  | 	float get_randomness_ratio() const; | ||||||
|  | 	Rect2 get_visibility_rect() const; | ||||||
|  | 	bool get_use_local_coordinates() const; | ||||||
|  | 	Ref<Material> get_process_material() const; | ||||||
|  | 	float get_speed_scale() const; | ||||||
| 
 | 
 | ||||||
| 	void set_emit_timeout(float p_timeout); | 	void set_fixed_fps(int p_count); | ||||||
| 	float get_emit_timeout() const; | 	int get_fixed_fps() const; | ||||||
| 
 | 
 | ||||||
| 	void set_emission_half_extents(const Vector2 &p_extents); | 	void set_fractional_delta(bool p_enable); | ||||||
| 	Vector2 get_emission_half_extents() const; | 	bool get_fractional_delta() const; | ||||||
| 
 | 
 | ||||||
| 	void set_param(Parameter p_param, float p_value); | 	void set_draw_order(DrawOrder p_order); | ||||||
| 	float get_param(Parameter p_param) const; | 	DrawOrder get_draw_order() const; | ||||||
| 
 |  | ||||||
| 	void set_randomness(Parameter p_randomness, float p_value); |  | ||||||
| 	float get_randomness(Parameter p_randomness) const; |  | ||||||
| 
 |  | ||||||
| 	void set_explosiveness(float p_value); |  | ||||||
| 	float get_explosiveness() const; |  | ||||||
| 
 |  | ||||||
| 	void set_flip_h(bool p_flip); |  | ||||||
| 	bool is_flipped_h() const; |  | ||||||
| 
 |  | ||||||
| 	void set_flip_v(bool p_flip); |  | ||||||
| 	bool is_flipped_v() const; |  | ||||||
| 
 |  | ||||||
| 	void set_h_frames(int p_frames); |  | ||||||
| 	int get_h_frames() const; |  | ||||||
| 
 |  | ||||||
| 	void set_v_frames(int p_frames); |  | ||||||
| 	int get_v_frames() const; |  | ||||||
| 
 |  | ||||||
| 	void set_color_phases(int p_phases); |  | ||||||
| 	int get_color_phases() const; |  | ||||||
| 
 |  | ||||||
| 	void set_color_phase_color(int p_phase, const Color &p_color); |  | ||||||
| 	Color get_color_phase_color(int p_phase) const; |  | ||||||
| 
 |  | ||||||
| 	void set_color_phase_pos(int p_phase, float p_pos); |  | ||||||
| 	float get_color_phase_pos(int p_phase) const; |  | ||||||
| 
 | 
 | ||||||
| 	void set_texture(const Ref<Texture> &p_texture); | 	void set_texture(const Ref<Texture> &p_texture); | ||||||
| 	Ref<Texture> get_texture() const; | 	Ref<Texture> get_texture() const; | ||||||
| 
 | 
 | ||||||
| 	void set_color(const Color &p_color); | 	void set_normal_map(const Ref<Texture> &p_normal_map); | ||||||
| 	Color get_color() const; | 	Ref<Texture> get_normal_map() const; | ||||||
| 
 | 
 | ||||||
| 	void set_gradient(const Ref<Gradient> &p_texture); | 	virtual String get_configuration_warning() const; | ||||||
| 	Ref<Gradient> get_gradient() const; |  | ||||||
| 
 | 
 | ||||||
| 	void set_emissor_offset(const Point2 &p_offset); | 	void set_v_frames(int p_count); | ||||||
| 	Point2 get_emissor_offset() const; | 	int get_v_frames() const; | ||||||
| 
 | 
 | ||||||
| 	void set_use_local_space(bool p_use); | 	void set_h_frames(int p_count); | ||||||
| 	bool is_using_local_space() const; | 	int get_h_frames() const; | ||||||
| 
 |  | ||||||
| 	void set_initial_velocity(const Vector2 &p_velocity); |  | ||||||
| 	Vector2 get_initial_velocity() const; |  | ||||||
| 
 |  | ||||||
| 	void set_emission_points(const PoolVector<Vector2> &p_points); |  | ||||||
| 	PoolVector<Vector2> get_emission_points() const; |  | ||||||
| 
 |  | ||||||
| 	void pre_process(float p_delta); |  | ||||||
| 	void reset(); |  | ||||||
| 
 | 
 | ||||||
|  | 	Rect2 capture_rect() const; | ||||||
| 	Particles2D(); | 	Particles2D(); | ||||||
|  | 	~Particles2D(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| VARIANT_ENUM_CAST(Particles2D::ProcessMode); | VARIANT_ENUM_CAST(Particles2D::DrawOrder) | ||||||
| VARIANT_ENUM_CAST(Particles2D::Parameter); |  | ||||||
| 
 | 
 | ||||||
| #endif // PARTICLES_FRAME_H
 | #endif // PARTICLES_FRAME_H
 | ||||||
|  |  | ||||||
|  | @ -404,6 +404,7 @@ void ParticlesMaterial::init_shaders() { | ||||||
| 	shader_names->emission_texture_point_count = "emission_texture_point_count"; | 	shader_names->emission_texture_point_count = "emission_texture_point_count"; | ||||||
| 	shader_names->emission_texture_points = "emission_texture_points"; | 	shader_names->emission_texture_points = "emission_texture_points"; | ||||||
| 	shader_names->emission_texture_normal = "emission_texture_normal"; | 	shader_names->emission_texture_normal = "emission_texture_normal"; | ||||||
|  | 	shader_names->emission_texture_color = "emission_texture_color"; | ||||||
| 
 | 
 | ||||||
| 	shader_names->trail_divisor = "trail_divisor"; | 	shader_names->trail_divisor = "trail_divisor"; | ||||||
| 	shader_names->trail_size_modifier = "trail_size_modifier"; | 	shader_names->trail_size_modifier = "trail_size_modifier"; | ||||||
|  | @ -481,6 +482,28 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 	code += "uniform float anim_speed_random;\n"; | 	code += "uniform float anim_speed_random;\n"; | ||||||
| 	code += "uniform float anim_offset_random;\n"; | 	code += "uniform float anim_offset_random;\n"; | ||||||
| 
 | 
 | ||||||
|  | 	switch (emission_shape) { | ||||||
|  | 		case EMISSION_SHAPE_POINT: { | ||||||
|  | 			//do none
 | ||||||
|  | 		} break; | ||||||
|  | 		case EMISSION_SHAPE_SPHERE: { | ||||||
|  | 			code += "uniform float emission_sphere_radius;\n"; | ||||||
|  | 		} break; | ||||||
|  | 		case EMISSION_SHAPE_BOX: { | ||||||
|  | 			code += "uniform vec3 emission_box_extents;\n"; | ||||||
|  | 		} break; | ||||||
|  | 		case EMISSION_SHAPE_DIRECTED_POINTS: { | ||||||
|  | 			code += "uniform sampler2D emission_texture_normal : hint_black;\n"; | ||||||
|  | 		} //fallthrough
 | ||||||
|  | 		case EMISSION_SHAPE_POINTS: { | ||||||
|  | 			code += "uniform sampler2D emission_texture_points : hint_black;\n"; | ||||||
|  | 			code += "uniform int emission_texture_point_count;\n"; | ||||||
|  | 			if (emission_color_texture.is_valid()) { | ||||||
|  | 				code += "uniform sampler2D emission_texture_color : hint_white;\n"; | ||||||
|  | 			} | ||||||
|  | 		} break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	code += "uniform vec4 color_value : hint_color;\n"; | 	code += "uniform vec4 color_value : hint_color;\n"; | ||||||
| 
 | 
 | ||||||
| 	code += "uniform int trail_divisor;\n"; | 	code += "uniform int trail_divisor;\n"; | ||||||
|  | @ -515,25 +538,6 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 	if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) | 	if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) | ||||||
| 		code += "uniform sampler2D anim_offset_texture;\n"; | 		code += "uniform sampler2D anim_offset_texture;\n"; | ||||||
| 
 | 
 | ||||||
| 	switch (emission_shape) { |  | ||||||
| 		case EMISSION_SHAPE_POINT: { |  | ||||||
| 			//do none
 |  | ||||||
| 		} break; |  | ||||||
| 		case EMISSION_SHAPE_SPHERE: { |  | ||||||
| 			code += "uniform float emission_sphere_radius;\n"; |  | ||||||
| 		} break; |  | ||||||
| 		case EMISSION_SHAPE_BOX: { |  | ||||||
| 			code += "uniform vec3 emission_box_extents;\n"; |  | ||||||
| 		} break; |  | ||||||
| 		case EMISSION_SHAPE_DIRECTED_POINTS: { |  | ||||||
| 			code += "uniform sampler2D emission_texture_normal : hint_black;\n"; |  | ||||||
| 		} //fallthrough
 |  | ||||||
| 		case EMISSION_SHAPE_POINTS: { |  | ||||||
| 			code += "uniform sampler2D emission_texture_points : hint_black;\n"; |  | ||||||
| 			code += "uniform int emission_texture_point_count;\n"; |  | ||||||
| 		} break; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (trail_size_modifier.is_valid()) { | 	if (trail_size_modifier.is_valid()) { | ||||||
| 		code += "uniform sampler2D trail_size_modifier;\n"; | 		code += "uniform sampler2D trail_size_modifier;\n"; | ||||||
| 	} | 	} | ||||||
|  | @ -576,6 +580,11 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 	code += "\n"; | 	code += "\n"; | ||||||
| 	code += "\n"; | 	code += "\n"; | ||||||
| 	code += "\n"; | 	code += "\n"; | ||||||
|  | 	if (emission_shape >= EMISSION_SHAPE_POINTS) { | ||||||
|  | 		code += " int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; | ||||||
|  | 		code += " ivec2 emission_tex_size = textureSize( emission_texture_points, 0 );\n"; | ||||||
|  | 		code += " ivec2 emission_tex_ofs = ivec2( point % emission_tex_size.x, point / emission_tex_size.x );\n"; | ||||||
|  | 	} | ||||||
| 	code += " if (RESTART) {\n"; | 	code += " if (RESTART) {\n"; | ||||||
| 
 | 
 | ||||||
| 	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) | 	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) | ||||||
|  | @ -593,11 +602,21 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 	else | 	else | ||||||
| 		code += "    float tex_anim_offset = 0.0;\n"; | 		code += "    float tex_anim_offset = 0.0;\n"; | ||||||
| 
 | 
 | ||||||
|  | 	if (flags[FLAG_DISABLE_Z]) { | ||||||
|  | 
 | ||||||
|  | 		code += "    float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n"; | ||||||
|  | 		code += "    vec3 rot=vec3( cos(angle1), sin(angle1),0.0 );\n"; | ||||||
|  | 		code += "    VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n"; | ||||||
|  | 
 | ||||||
|  | 	} else { | ||||||
|  | 		//initiate velocity spread in 3D
 | ||||||
| 		code += "    float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n"; | 		code += "    float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n"; | ||||||
| 		code += "    float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n"; | 		code += "    float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n"; | ||||||
| 		code += "    vec3 rot_xz=vec3( sin(angle1), 0.0, cos(angle1) );\n"; | 		code += "    vec3 rot_xz=vec3( sin(angle1), 0.0, cos(angle1) );\n"; | ||||||
| 		code += "    vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n"; | 		code += "    vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n"; | ||||||
| 		code += "    VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n"; | 		code += "    VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n"; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	code += "    float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n"; | 	code += "    float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n"; | ||||||
| 	code += "    CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle
 | 	code += "    CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle
 | ||||||
| 	code += "    CUSTOM.y=0.0;\n"; //phase
 | 	code += "    CUSTOM.y=0.0;\n"; //phase
 | ||||||
|  | @ -614,21 +633,31 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 		} break; | 		} break; | ||||||
| 		case EMISSION_SHAPE_POINTS: | 		case EMISSION_SHAPE_POINTS: | ||||||
| 		case EMISSION_SHAPE_DIRECTED_POINTS: { | 		case EMISSION_SHAPE_DIRECTED_POINTS: { | ||||||
| 			code += "    int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; | 			code += "    TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs,0).xyz;\n"; | ||||||
| 			code += "    ivec2 tex_size = textureSize( emission_texture_points, 0 );\n"; | 
 | ||||||
| 			code += "    ivec2 tex_ofs = ivec2( point % tex_size.x, point / tex_size.x );\n"; |  | ||||||
| 			code += "    TRANSFORM[3].xyz = texelFetch(emission_texture_points, tex_ofs,0).xyz;\n"; |  | ||||||
| 			if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { | 			if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { | ||||||
| 				code += "    vec3 normal = texelFetch(emission_texture_normal, tex_ofs,0).xyz;\n"; | 				if (flags[FLAG_DISABLE_Z]) { | ||||||
|  | 
 | ||||||
|  | 					code += "    mat2 rotm;"; | ||||||
|  | 					code += "    rotm[0]=texelFetch(emission_texture_normal, emission_tex_ofs,0).xy;\n"; | ||||||
|  | 					code += "    rotm[1]=rotm[0].yx * vec2(1.0,-1.0);\n"; | ||||||
|  | 					code += "    VELOCITY.xy = rotm * VELOCITY.xy;\n"; | ||||||
|  | 				} else { | ||||||
|  | 					code += "    vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs,0).xyz;\n"; | ||||||
| 					code += "    vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n"; | 					code += "    vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n"; | ||||||
| 					code += "    vec3 tangent = normalize(cross(v0, normal));\n"; | 					code += "    vec3 tangent = normalize(cross(v0, normal));\n"; | ||||||
| 					code += "    vec3 bitangent = normalize(cross(tangent, normal));\n"; | 					code += "    vec3 bitangent = normalize(cross(tangent, normal));\n"; | ||||||
| 					code += "    VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n"; | 					code += "    VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n"; | ||||||
| 				} | 				} | ||||||
|  | 			} | ||||||
| 		} break; | 		} break; | ||||||
| 	} | 	} | ||||||
| 	code += "    VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n"; | 	code += "    VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n"; | ||||||
| 	code += "    TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; | 	code += "    TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; | ||||||
|  | 	if (flags[FLAG_DISABLE_Z]) { | ||||||
|  | 		code += "    VELOCITY.z=0.0;\n"; | ||||||
|  | 		code += "    TRANSFORM[3].z=0.0;\n"; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	code += " } else {\n"; | 	code += " } else {\n"; | ||||||
| 
 | 
 | ||||||
|  | @ -685,6 +714,9 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 
 | 
 | ||||||
| 	code += "    vec3 force = gravity; \n"; | 	code += "    vec3 force = gravity; \n"; | ||||||
| 	code += "    vec3 pos = TRANSFORM[3].xyz; \n"; | 	code += "    vec3 pos = TRANSFORM[3].xyz; \n"; | ||||||
|  | 	if (flags[FLAG_DISABLE_Z]) { | ||||||
|  | 		code += "    pos.z=0.0; \n"; | ||||||
|  | 	} | ||||||
| 	code += "    //apply linear acceleration\n"; | 	code += "    //apply linear acceleration\n"; | ||||||
| 	code += "    force+=normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random);\n"; | 	code += "    force+=normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random);\n"; | ||||||
| 	code += "    //apply radial acceleration\n"; | 	code += "    //apply radial acceleration\n"; | ||||||
|  | @ -693,11 +725,17 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 	code += "	//org=p_transform.origin;\n"; | 	code += "	//org=p_transform.origin;\n"; | ||||||
| 	code += "    force+=normalize(pos-org) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random);\n"; | 	code += "    force+=normalize(pos-org) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random);\n"; | ||||||
| 	code += "    //apply tangential acceleration;\n"; | 	code += "    //apply tangential acceleration;\n"; | ||||||
|  | 	if (flags[FLAG_DISABLE_Z]) { | ||||||
|  | 		code += "    force+=vec3(normalize((pos-org).yx * vec2(-1.0,1.0)),0.0) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n"; | ||||||
|  | 
 | ||||||
|  | 	} else { | ||||||
| 		code += "    force+=normalize(cross(normalize(pos-org),normalize(gravity))) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n"; | 		code += "    force+=normalize(cross(normalize(pos-org),normalize(gravity))) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n"; | ||||||
|  | 	} | ||||||
| 	code += "    //apply attractor forces\n"; | 	code += "    //apply attractor forces\n"; | ||||||
| 	code += "    VELOCITY+=force * DELTA;\n"; | 	code += "    VELOCITY+=force * DELTA;\n"; | ||||||
| 	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) | 	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { | ||||||
| 		code += "    VELOCITY=normalize(VELOCITY)*tex_linear_velocity;\n"; | 		code += "    VELOCITY=normalize(VELOCITY)*tex_linear_velocity;\n"; | ||||||
|  | 	} | ||||||
| 	code += "    if (damping+tex_damping>0.0) {\n"; | 	code += "    if (damping+tex_damping>0.0) {\n"; | ||||||
| 	code += "    \n"; | 	code += "    \n"; | ||||||
| 	code += "    	float v = length(VELOCITY);\n"; | 	code += "    	float v = length(VELOCITY);\n"; | ||||||
|  | @ -709,9 +747,16 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 	code += "    		VELOCITY=normalize(VELOCITY) * v;\n"; | 	code += "    		VELOCITY=normalize(VELOCITY) * v;\n"; | ||||||
| 	code += "	}\n"; | 	code += "	}\n"; | ||||||
| 	code += "    }\n"; | 	code += "    }\n"; | ||||||
| 	code += "    float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random)*3.1416/180.0;\n"; | 	code += "    float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n"; | ||||||
| 	code += "    CUSTOM.x=((base_angle+tex_angle)+CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random))*3.1416/180.0;\n"; //angle
 | 	code += "    base_angle+=CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random);\n"; | ||||||
| 	code += "    CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*LIFETIME*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle
 | 	code += "    CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle
 | ||||||
|  | 	code += "    CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle
 | ||||||
|  | 	if (flags[FLAG_ANIM_LOOP]) { | ||||||
|  | 		code += "    CUSTOM.z=mod(CUSTOM.z,1.0);\n"; //loop
 | ||||||
|  | 
 | ||||||
|  | 	} else { | ||||||
|  | 		code += "    CUSTOM.z=clamp(CUSTOM.z,0.0,1.0);\n"; //0 to 1 only
 | ||||||
|  | 	} | ||||||
| 	code += "  }\n"; | 	code += "  }\n"; | ||||||
| 	//apply color
 | 	//apply color
 | ||||||
| 	//apply hue rotation
 | 	//apply hue rotation
 | ||||||
|  | @ -747,10 +792,21 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 	} else { | 	} else { | ||||||
| 		code += " COLOR = color_value * hue_rot_mat;\n"; | 		code += " COLOR = color_value * hue_rot_mat;\n"; | ||||||
| 	} | 	} | ||||||
|  | 	if (emission_color_texture.is_valid() && emission_shape >= EMISSION_SHAPE_POINTS) { | ||||||
|  | 		code += " COLOR*= texelFetch(emission_texture_color,emission_tex_ofs,0);\n"; | ||||||
|  | 	} | ||||||
| 	if (trail_color_modifier.is_valid()) { | 	if (trail_color_modifier.is_valid()) { | ||||||
| 		code += "if (trail_divisor>1) { COLOR*=textureLod(trail_color_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0); }\n"; | 		code += "if (trail_divisor>1) { COLOR*=textureLod(trail_color_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0); }\n"; | ||||||
| 	} | 	} | ||||||
| 	code += "\n"; | 	code += "\n"; | ||||||
|  | 
 | ||||||
|  | 	if (flags[FLAG_DISABLE_Z]) { | ||||||
|  | 
 | ||||||
|  | 		code += " TRANSFORM[0]=vec4(cos(CUSTOM.x),-sin(CUSTOM.x),0.0,0.0);\n"; | ||||||
|  | 		code += " TRANSFORM[1]=vec4(sin(CUSTOM.x),cos(CUSTOM.x),0.0,0.0);\n"; | ||||||
|  | 		code += " TRANSFORM[2]=vec4(0.0,0.0,1.0,0.0);\n"; | ||||||
|  | 
 | ||||||
|  | 	} else { | ||||||
| 		//orient particle Y towards velocity
 | 		//orient particle Y towards velocity
 | ||||||
| 		if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { | 		if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { | ||||||
| 			code += " if (length(VELOCITY)>0.0) {TRANSFORM[1].xyz=normalize(VELOCITY);} else {TRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);}\n"; | 			code += " if (length(VELOCITY)>0.0) {TRANSFORM[1].xyz=normalize(VELOCITY);} else {TRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);}\n"; | ||||||
|  | @ -770,6 +826,7 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 		if (flags[FLAG_ROTATE_Y]) { | 		if (flags[FLAG_ROTATE_Y]) { | ||||||
| 			code += "\tTRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n"; | 			code += "\tTRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n"; | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	//scale by scale
 | 	//scale by scale
 | ||||||
| 	code += " float base_scale=mix(scale*tex_scale,1.0,scale_random*scale_rand);\n"; | 	code += " float base_scale=mix(scale*tex_scale,1.0,scale_random*scale_rand);\n"; | ||||||
| 	if (trail_size_modifier.is_valid()) { | 	if (trail_size_modifier.is_valid()) { | ||||||
|  | @ -779,6 +836,10 @@ void ParticlesMaterial::_update_shader() { | ||||||
| 	code += " TRANSFORM[0].xyz*=base_scale;\n"; | 	code += " TRANSFORM[0].xyz*=base_scale;\n"; | ||||||
| 	code += " TRANSFORM[1].xyz*=base_scale;\n"; | 	code += " TRANSFORM[1].xyz*=base_scale;\n"; | ||||||
| 	code += " TRANSFORM[2].xyz*=base_scale;\n"; | 	code += " TRANSFORM[2].xyz*=base_scale;\n"; | ||||||
|  | 	if (flags[FLAG_DISABLE_Z]) { | ||||||
|  | 		code += " VELOCITY.z=0.0;\n"; | ||||||
|  | 		code += " TRANSFORM[3].z=0.0;\n"; | ||||||
|  | 	} | ||||||
| 	code += "}\n"; | 	code += "}\n"; | ||||||
| 	code += "\n"; | 	code += "\n"; | ||||||
| 
 | 
 | ||||||
|  | @ -1130,6 +1191,16 @@ void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normal | ||||||
| 	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture); | 	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ParticlesMaterial::set_emission_color_texture(const Ref<Texture> &p_colors) { | ||||||
|  | 
 | ||||||
|  | 	emission_color_texture = p_colors; | ||||||
|  | 	RID texture; | ||||||
|  | 	if (p_colors.is_valid()) | ||||||
|  | 		texture = p_colors->get_rid(); | ||||||
|  | 	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, texture); | ||||||
|  | 	_queue_shader_change(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ParticlesMaterial::set_emission_point_count(int p_count) { | void ParticlesMaterial::set_emission_point_count(int p_count) { | ||||||
| 
 | 
 | ||||||
| 	emission_point_count = p_count; | 	emission_point_count = p_count; | ||||||
|  | @ -1158,6 +1229,11 @@ Ref<Texture> ParticlesMaterial::get_emission_normal_texture() const { | ||||||
| 	return emission_normal_texture; | 	return emission_normal_texture; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Ref<Texture> ParticlesMaterial::get_emission_color_texture() const { | ||||||
|  | 
 | ||||||
|  | 	return emission_color_texture; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int ParticlesMaterial::get_emission_point_count() const { | int ParticlesMaterial::get_emission_point_count() const { | ||||||
| 
 | 
 | ||||||
| 	return emission_point_count; | 	return emission_point_count; | ||||||
|  | @ -1247,7 +1323,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { | ||||||
| 		property.usage = 0; | 		property.usage = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (property.name == "emission_point_texture" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { | 	if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { | ||||||
| 		property.usage = 0; | 		property.usage = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1301,6 +1377,9 @@ void ParticlesMaterial::_bind_methods() { | ||||||
| 	ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture:Texture"), &ParticlesMaterial::set_emission_normal_texture); | 	ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture:Texture"), &ParticlesMaterial::set_emission_normal_texture); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_emission_normal_texture:Texture"), &ParticlesMaterial::get_emission_normal_texture); | 	ClassDB::bind_method(D_METHOD("get_emission_normal_texture:Texture"), &ParticlesMaterial::get_emission_normal_texture); | ||||||
| 
 | 
 | ||||||
|  | 	ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture:Texture"), &ParticlesMaterial::set_emission_color_texture); | ||||||
|  | 	ClassDB::bind_method(D_METHOD("get_emission_color_texture:Texture"), &ParticlesMaterial::get_emission_color_texture); | ||||||
|  | 
 | ||||||
| 	ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count); | 	ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count); | ||||||
| 	ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count); | 	ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count); | ||||||
| 
 | 
 | ||||||
|  | @ -1326,10 +1405,12 @@ void ParticlesMaterial::_bind_methods() { | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents"); | 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents"); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_point_texture", "get_emission_point_texture"); | 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_point_texture", "get_emission_point_texture"); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture"); | 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture"); | ||||||
|  | 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_color_texture", "get_emission_color_texture"); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count"); | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count"); | ||||||
| 	ADD_GROUP("Flags", "flag_"); | 	ADD_GROUP("Flags", "flag_"); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY); | 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y); | 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y); | ||||||
|  | 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_flag", "get_flag", FLAG_DISABLE_Z); | ||||||
| 	ADD_GROUP("Spread", ""); | 	ADD_GROUP("Spread", ""); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); | ||||||
| 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); | ||||||
|  | @ -1379,12 +1460,13 @@ void ParticlesMaterial::_bind_methods() { | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION); | 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION); | 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION); | ||||||
| 	ADD_GROUP("Animation", "anim_"); | 	ADD_GROUP("Animation", "anim_"); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED); | 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED); | 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED); | 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET); | 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); | 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); | ||||||
| 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); | 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); | ||||||
|  | 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_flag", "get_flag", FLAG_ANIM_LOOP); | ||||||
| 
 | 
 | ||||||
| 	BIND_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); | 	BIND_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); | ||||||
| 	BIND_CONSTANT(PARAM_ANGULAR_VELOCITY); | 	BIND_CONSTANT(PARAM_ANGULAR_VELOCITY); | ||||||
|  |  | ||||||
|  | @ -154,6 +154,8 @@ public: | ||||||
| 	enum Flags { | 	enum Flags { | ||||||
| 		FLAG_ALIGN_Y_TO_VELOCITY, | 		FLAG_ALIGN_Y_TO_VELOCITY, | ||||||
| 		FLAG_ROTATE_Y, | 		FLAG_ROTATE_Y, | ||||||
|  | 		FLAG_DISABLE_Z, | ||||||
|  | 		FLAG_ANIM_LOOP, | ||||||
| 		FLAG_MAX | 		FLAG_MAX | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | @ -171,11 +173,12 @@ private: | ||||||
| 		struct { | 		struct { | ||||||
| 			uint32_t texture_mask : 16; | 			uint32_t texture_mask : 16; | ||||||
| 			uint32_t texture_color : 1; | 			uint32_t texture_color : 1; | ||||||
| 			uint32_t flags : 2; | 			uint32_t flags : 4; | ||||||
| 			uint32_t emission_shape : 2; | 			uint32_t emission_shape : 2; | ||||||
| 			uint32_t trail_size_texture : 1; | 			uint32_t trail_size_texture : 1; | ||||||
| 			uint32_t trail_color_texture : 1; | 			uint32_t trail_color_texture : 1; | ||||||
| 			uint32_t invalid_key : 1; | 			uint32_t invalid_key : 1; | ||||||
|  | 			uint32_t has_emission_color : 1; | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		uint32_t key; | 		uint32_t key; | ||||||
|  | @ -213,6 +216,7 @@ private: | ||||||
| 		mk.emission_shape = emission_shape; | 		mk.emission_shape = emission_shape; | ||||||
| 		mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0; | 		mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0; | ||||||
| 		mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0; | 		mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0; | ||||||
|  | 		mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid(); | ||||||
| 
 | 
 | ||||||
| 		return mk; | 		return mk; | ||||||
| 	} | 	} | ||||||
|  | @ -269,6 +273,7 @@ private: | ||||||
| 		StringName emission_texture_point_count; | 		StringName emission_texture_point_count; | ||||||
| 		StringName emission_texture_points; | 		StringName emission_texture_points; | ||||||
| 		StringName emission_texture_normal; | 		StringName emission_texture_normal; | ||||||
|  | 		StringName emission_texture_color; | ||||||
| 
 | 
 | ||||||
| 		StringName trail_divisor; | 		StringName trail_divisor; | ||||||
| 		StringName trail_size_modifier; | 		StringName trail_size_modifier; | ||||||
|  | @ -302,8 +307,11 @@ private: | ||||||
| 	Vector3 emission_box_extents; | 	Vector3 emission_box_extents; | ||||||
| 	Ref<Texture> emission_point_texture; | 	Ref<Texture> emission_point_texture; | ||||||
| 	Ref<Texture> emission_normal_texture; | 	Ref<Texture> emission_normal_texture; | ||||||
|  | 	Ref<Texture> emission_color_texture; | ||||||
| 	int emission_point_count; | 	int emission_point_count; | ||||||
| 
 | 
 | ||||||
|  | 	bool anim_loop; | ||||||
|  | 
 | ||||||
| 	int trail_divisor; | 	int trail_divisor; | ||||||
| 
 | 
 | ||||||
| 	Ref<CurveTexture> trail_size_modifier; | 	Ref<CurveTexture> trail_size_modifier; | ||||||
|  | @ -347,6 +355,7 @@ public: | ||||||
| 	void set_emission_box_extents(Vector3 p_extents); | 	void set_emission_box_extents(Vector3 p_extents); | ||||||
| 	void set_emission_point_texture(const Ref<Texture> &p_points); | 	void set_emission_point_texture(const Ref<Texture> &p_points); | ||||||
| 	void set_emission_normal_texture(const Ref<Texture> &p_normals); | 	void set_emission_normal_texture(const Ref<Texture> &p_normals); | ||||||
|  | 	void set_emission_color_texture(const Ref<Texture> &p_colors); | ||||||
| 	void set_emission_point_count(int p_count); | 	void set_emission_point_count(int p_count); | ||||||
| 
 | 
 | ||||||
| 	EmissionShape get_emission_shape() const; | 	EmissionShape get_emission_shape() const; | ||||||
|  | @ -354,6 +363,7 @@ public: | ||||||
| 	Vector3 get_emission_box_extents() const; | 	Vector3 get_emission_box_extents() const; | ||||||
| 	Ref<Texture> get_emission_point_texture() const; | 	Ref<Texture> get_emission_point_texture() const; | ||||||
| 	Ref<Texture> get_emission_normal_texture() const; | 	Ref<Texture> get_emission_normal_texture() const; | ||||||
|  | 	Ref<Texture> get_emission_color_texture() const; | ||||||
| 	int get_emission_point_count() const; | 	int get_emission_point_count() const; | ||||||
| 
 | 
 | ||||||
| 	void set_trail_divisor(int p_divisor); | 	void set_trail_divisor(int p_divisor); | ||||||
|  |  | ||||||
|  | @ -471,7 +471,7 @@ void register_scene_types() { | ||||||
| 	ClassDB::register_virtual_class<CanvasItem>(); | 	ClassDB::register_virtual_class<CanvasItem>(); | ||||||
| 	ClassDB::register_class<Node2D>(); | 	ClassDB::register_class<Node2D>(); | ||||||
| 	ClassDB::register_class<Particles2D>(); | 	ClassDB::register_class<Particles2D>(); | ||||||
| 	ClassDB::register_class<ParticleAttractor2D>(); | 	//ClassDB::register_class<ParticleAttractor2D>();
 | ||||||
| 	ClassDB::register_class<Sprite>(); | 	ClassDB::register_class<Sprite>(); | ||||||
| 	//ClassDB::register_type<ViewportSprite>();
 | 	//ClassDB::register_type<ViewportSprite>();
 | ||||||
| 	ClassDB::register_class<SpriteFrames>(); | 	ClassDB::register_class<SpriteFrames>(); | ||||||
|  |  | ||||||
|  | @ -612,6 +612,7 @@ public: | ||||||
| 				TYPE_POLYGON, | 				TYPE_POLYGON, | ||||||
| 				TYPE_MESH, | 				TYPE_MESH, | ||||||
| 				TYPE_MULTIMESH, | 				TYPE_MULTIMESH, | ||||||
|  | 				TYPE_PARTICLES, | ||||||
| 				TYPE_CIRCLE, | 				TYPE_CIRCLE, | ||||||
| 				TYPE_TRANSFORM, | 				TYPE_TRANSFORM, | ||||||
| 				TYPE_CLIP_IGNORE, | 				TYPE_CLIP_IGNORE, | ||||||
|  | @ -707,6 +708,16 @@ public: | ||||||
| 			CommandMultiMesh() { type = TYPE_MULTIMESH; } | 			CommandMultiMesh() { type = TYPE_MULTIMESH; } | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
|  | 		struct CommandParticles : public Command { | ||||||
|  | 
 | ||||||
|  | 			RID particles; | ||||||
|  | 			RID texture; | ||||||
|  | 			RID normal_map; | ||||||
|  | 			int h_frames; | ||||||
|  | 			int v_frames; | ||||||
|  | 			CommandParticles() { type = TYPE_PARTICLES; } | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
| 		struct CommandCircle : public Command { | 		struct CommandCircle : public Command { | ||||||
| 
 | 
 | ||||||
| 			Point2 pos; | 			Point2 pos; | ||||||
|  | @ -844,6 +855,15 @@ public: | ||||||
| 
 | 
 | ||||||
| 						r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); | 						r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); | ||||||
| 
 | 
 | ||||||
|  | 					} break; | ||||||
|  | 					case Item::Command::TYPE_PARTICLES: { | ||||||
|  | 
 | ||||||
|  | 						const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c); | ||||||
|  | 						if (particles_cmd->particles.is_valid()) { | ||||||
|  | 							Rect3 aabb = RasterizerStorage::base_singleton->particles_get_aabb(particles_cmd->particles); | ||||||
|  | 							r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
| 					} break; | 					} break; | ||||||
| 					case Item::Command::TYPE_CIRCLE: { | 					case Item::Command::TYPE_CIRCLE: { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -637,6 +637,25 @@ void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID | ||||||
| 
 | 
 | ||||||
| 	canvas_item->commands.push_back(m); | 	canvas_item->commands.push_back(m); | ||||||
| } | } | ||||||
|  | void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames) { | ||||||
|  | 
 | ||||||
|  | 	Item *canvas_item = canvas_item_owner.getornull(p_item); | ||||||
|  | 	ERR_FAIL_COND(!canvas_item); | ||||||
|  | 
 | ||||||
|  | 	Item::CommandParticles *part = memnew(Item::CommandParticles); | ||||||
|  | 	ERR_FAIL_COND(!part); | ||||||
|  | 	part->particles = p_particles; | ||||||
|  | 	part->texture = p_texture; | ||||||
|  | 	part->normal_map = p_normal; | ||||||
|  | 	part->h_frames = p_h_frames; | ||||||
|  | 	part->v_frames = p_v_frames; | ||||||
|  | 
 | ||||||
|  | 	//take the chance and request processing for them, at least once until they become visible again
 | ||||||
|  | 	VSG::storage->particles_request_process(p_particles); | ||||||
|  | 
 | ||||||
|  | 	canvas_item->commands.push_back(part); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void VisualServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton) { | void VisualServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton) { | ||||||
| 
 | 
 | ||||||
| 	Item *canvas_item = canvas_item_owner.getornull(p_item); | 	Item *canvas_item = canvas_item_owner.getornull(p_item); | ||||||
|  |  | ||||||
|  | @ -173,6 +173,7 @@ public: | ||||||
| 	void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()); | 	void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()); | ||||||
| 	void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_skeleton = RID()); | 	void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_skeleton = RID()); | ||||||
| 	void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton = RID()); | 	void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton = RID()); | ||||||
|  | 	void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames); | ||||||
| 	void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform); | 	void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform); | ||||||
| 	void canvas_item_add_clip_ignore(RID p_item, bool p_ignore); | 	void canvas_item_add_clip_ignore(RID p_item, bool p_ignore); | ||||||
| 	void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable); | 	void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable); | ||||||
|  |  | ||||||
|  | @ -877,7 +877,8 @@ public: | ||||||
| 	BIND2(particles_set_draw_passes, RID, int) | 	BIND2(particles_set_draw_passes, RID, int) | ||||||
| 	BIND3(particles_set_draw_pass_mesh, RID, int, RID) | 	BIND3(particles_set_draw_pass_mesh, RID, int, RID) | ||||||
| 
 | 
 | ||||||
| 	BIND1R(Rect3, particles_get_current_aabb, RID); | 	BIND1R(Rect3, particles_get_current_aabb, RID) | ||||||
|  | 	BIND2(particles_set_emission_transform, RID, const Transform &) | ||||||
| 
 | 
 | ||||||
| #undef BINDBASE | #undef BINDBASE | ||||||
| //from now on, calls forwarded to this singleton
 | //from now on, calls forwarded to this singleton
 | ||||||
|  | @ -1049,6 +1050,7 @@ public: | ||||||
| 	BIND8(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, int, RID) | 	BIND8(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, int, RID) | ||||||
| 	BIND3(canvas_item_add_mesh, RID, const RID &, RID) | 	BIND3(canvas_item_add_mesh, RID, const RID &, RID) | ||||||
| 	BIND3(canvas_item_add_multimesh, RID, RID, RID) | 	BIND3(canvas_item_add_multimesh, RID, RID, RID) | ||||||
|  | 	BIND6(canvas_item_add_particles, RID, RID, RID, RID, int, int) | ||||||
| 	BIND2(canvas_item_add_set_transform, RID, const Transform2D &) | 	BIND2(canvas_item_add_set_transform, RID, const Transform2D &) | ||||||
| 	BIND2(canvas_item_add_clip_ignore, RID, bool) | 	BIND2(canvas_item_add_clip_ignore, RID, bool) | ||||||
| 	BIND2(canvas_item_set_sort_children_by_y, RID, bool) | 	BIND2(canvas_item_set_sort_children_by_y, RID, bool) | ||||||
|  |  | ||||||
|  | @ -320,6 +320,7 @@ public: | ||||||
| 
 | 
 | ||||||
| 	FUNC2(particles_set_draw_passes, RID, int) | 	FUNC2(particles_set_draw_passes, RID, int) | ||||||
| 	FUNC3(particles_set_draw_pass_mesh, RID, int, RID) | 	FUNC3(particles_set_draw_pass_mesh, RID, int, RID) | ||||||
|  | 	FUNC2(particles_set_emission_transform, RID, const Transform &) | ||||||
| 
 | 
 | ||||||
| 	FUNC1R(Rect3, particles_get_current_aabb, RID) | 	FUNC1R(Rect3, particles_get_current_aabb, RID) | ||||||
| 
 | 
 | ||||||
|  | @ -476,6 +477,7 @@ public: | ||||||
| 	FUNC8(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, int, RID) | 	FUNC8(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, int, RID) | ||||||
| 	FUNC3(canvas_item_add_mesh, RID, const RID &, RID) | 	FUNC3(canvas_item_add_mesh, RID, const RID &, RID) | ||||||
| 	FUNC3(canvas_item_add_multimesh, RID, RID, RID) | 	FUNC3(canvas_item_add_multimesh, RID, RID, RID) | ||||||
|  | 	FUNC6(canvas_item_add_particles, RID, RID, RID, RID, int, int) | ||||||
| 	FUNC2(canvas_item_add_set_transform, RID, const Transform2D &) | 	FUNC2(canvas_item_add_set_transform, RID, const Transform2D &) | ||||||
| 	FUNC2(canvas_item_add_clip_ignore, RID, bool) | 	FUNC2(canvas_item_add_clip_ignore, RID, bool) | ||||||
| 	FUNC2(canvas_item_set_sort_children_by_y, RID, bool) | 	FUNC2(canvas_item_set_sort_children_by_y, RID, bool) | ||||||
|  |  | ||||||
|  | @ -501,6 +501,8 @@ public: | ||||||
| 
 | 
 | ||||||
| 	virtual Rect3 particles_get_current_aabb(RID p_particles) = 0; | 	virtual Rect3 particles_get_current_aabb(RID p_particles) = 0; | ||||||
| 
 | 
 | ||||||
|  | 	virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; //this is only used for 2D, in 3D it's automatic
 | ||||||
|  | 
 | ||||||
| 	/* CAMERA API */ | 	/* CAMERA API */ | ||||||
| 
 | 
 | ||||||
| 	virtual RID camera_create() = 0; | 	virtual RID camera_create() = 0; | ||||||
|  | @ -793,6 +795,7 @@ public: | ||||||
| 	virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0; | 	virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0; | ||||||
| 	virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_skeleton = RID()) = 0; | 	virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_skeleton = RID()) = 0; | ||||||
| 	virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton = RID()) = 0; | 	virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_skeleton = RID()) = 0; | ||||||
|  | 	virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, int p_h_frames, int p_v_frames) = 0; | ||||||
| 	virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0; | 	virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0; | ||||||
| 	virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0; | 	virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0; | ||||||
| 	virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0; | 	virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Juan Linietsky
						Juan Linietsky