Browse Source

New particle system, mostly working, some small features missing.

Juan Linietsky 8 years ago
parent
commit
74808ac4d9
76 changed files with 5393 additions and 1799 deletions
  1. 0 23
      core/math/transform.h
  2. 1 1
      core/variant_parser.cpp
  3. 3 3
      drivers/gles2/rasterizer_gles2.cpp
  4. 3 3
      drivers/gles2/rasterizer_gles2.h
  5. 1 1
      drivers/gles3/rasterizer_canvas_gles3.cpp
  6. 89 67
      drivers/gles3/rasterizer_scene_gles3.cpp
  7. 0 1
      drivers/gles3/rasterizer_scene_gles3.h
  8. 190 78
      drivers/gles3/rasterizer_storage_gles3.cpp
  9. 30 28
      drivers/gles3/rasterizer_storage_gles3.h
  10. 66 10
      drivers/gles3/shader_compiler_gles3.cpp
  11. 1 0
      drivers/gles3/shader_compiler_gles3.h
  12. 93 22
      drivers/gles3/shaders/particles.glsl
  13. 50 29
      drivers/gles3/shaders/scene.glsl
  14. 1 1
      editor/editor_file_system.cpp
  15. 5 1
      editor/editor_node.cpp
  16. 17 17
      editor/import/editor_import_collada.cpp
  17. 18 16
      editor/import/resource_importer_scene.cpp
  18. 15 15
      editor/io_plugins/editor_scene_import_plugin.cpp
  19. 12 12
      editor/io_plugins/editor_scene_importer_fbxconv.cpp
  20. 5 5
      editor/plugins/baked_light_baker.cpp
  21. 10 10
      editor/plugins/collision_polygon_editor_plugin.cpp
  22. 2 2
      editor/plugins/collision_polygon_editor_plugin.h
  23. 519 0
      editor/plugins/curve_editor_plugin.cpp
  24. 66 0
      editor/plugins/curve_editor_plugin.h
  25. 504 0
      editor/plugins/gradient_texture_editor_plugin.cpp
  26. 69 0
      editor/plugins/gradient_texture_editor_plugin.h
  27. 193 159
      editor/plugins/particles_editor_plugin.cpp
  28. 7 15
      editor/plugins/particles_editor_plugin.h
  29. 6 6
      editor/plugins/path_editor_plugin.cpp
  30. 2 2
      editor/plugins/path_editor_plugin.h
  31. 26 3
      editor/plugins/shader_editor_plugin.cpp
  32. 2 0
      editor/plugins/shader_editor_plugin.h
  33. 19 19
      editor/plugins/spatial_editor_plugin.cpp
  34. 4 4
      editor/plugins/spatial_editor_plugin.h
  35. 1 1
      editor/plugins/tile_set_editor_plugin.cpp
  36. 92 87
      editor/spatial_editor_gizmos.cpp
  37. 35 32
      editor/spatial_editor_gizmos.h
  38. 3 1
      main/tests/test_shader_lang.cpp
  39. 9 9
      modules/gridmap/grid_map_editor_plugin.cpp
  40. 3 3
      modules/gridmap/grid_map_editor_plugin.h
  41. 8 8
      platform/iphone/rasterizer_iphone.cpp
  42. 10 10
      platform/iphone/rasterizer_iphone.h
  43. 6 124
      scene/2d/canvas_item.cpp
  44. 3 35
      scene/2d/canvas_item.h
  45. 2 2
      scene/2d/tile_map.cpp
  46. 7 7
      scene/3d/baked_light_instance.cpp
  47. 7 7
      scene/3d/gi_probe.cpp
  48. 1184 363
      scene/3d/particles.cpp
  49. 290 84
      scene/3d/particles.h
  50. 0 14
      scene/3d/spatial.cpp
  51. 0 6
      scene/3d/spatial.h
  52. 0 6
      scene/3d/visual_instance.cpp
  53. 0 3
      scene/3d/visual_instance.h
  54. 15 15
      scene/main/scene_main_loop.cpp
  55. 16 12
      scene/register_scene_types.cpp
  56. 1 1
      scene/resources/default_theme/default_theme.cpp
  57. 396 145
      scene/resources/material.cpp
  58. 71 17
      scene/resources/material.h
  59. 74 0
      scene/resources/mesh.cpp
  60. 16 0
      scene/resources/mesh.h
  61. 16 3
      scene/resources/shader.cpp
  62. 1 28
      scene/resources/shader.h
  63. 468 0
      scene/resources/texture.cpp
  64. 141 0
      scene/resources/texture.h
  65. 6 6
      scene/resources/tile_set.cpp
  66. 3 3
      scene/resources/tile_set.h
  67. 49 49
      servers/visual/rasterizer.cpp
  68. 33 42
      servers/visual/rasterizer.h
  69. 309 45
      servers/visual/shader_language.cpp
  70. 18 3
      servers/visual/shader_language.h
  71. 19 4
      servers/visual/shader_types.cpp
  72. 3 0
      servers/visual/shader_types.h
  73. 18 16
      servers/visual/visual_server_raster.cpp
  74. 7 12
      servers/visual/visual_server_raster.h
  75. 20 16
      servers/visual/visual_server_scene.cpp
  76. 4 27
      servers/visual_server.h

+ 0 - 23
core/math/transform.h

@@ -229,27 +229,4 @@ _FORCE_INLINE_ Rect3 Transform::xform_inv(const Rect3 &p_aabb) const {
 	return ret;
 }
 
-#ifdef OPTIMIZED_TRANSFORM_IMPL_OVERRIDE
-
-#else
-
-struct OptimizedTransform {
-
-	Transform transform;
-
-	_FORCE_INLINE_ void invert() { transform.invert(); }
-	_FORCE_INLINE_ void affine_invert() { transform.affine_invert(); }
-	_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec) const { return transform.xform(p_vec); };
-	_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vec) const { return transform.xform_inv(p_vec); };
-	_FORCE_INLINE_ OptimizedTransform operator*(const OptimizedTransform &p_ot) const { return OptimizedTransform(transform * p_ot.transform); }
-	_FORCE_INLINE_ Transform get_transform() const { return transform; }
-	_FORCE_INLINE_ void set_transform(const Transform &p_transform) { transform = p_transform; }
-
-	OptimizedTransform(const Transform &p_transform) {
-		transform = p_transform;
-	}
-};
-
-#endif
-
 #endif

+ 1 - 1
core/variant_parser.cpp

@@ -755,7 +755,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
 			Image::Format format = Image::FORMAT_MAX;
 
 			for (int i = 0; i < Image::FORMAT_MAX; i++) {
-				if (Image::get_format_name(format) == sformat) {
+				if (Image::get_format_name(Image::Format(i)) == sformat) {
 					format = Image::Format(i);
 				}
 			}

+ 3 - 3
drivers/gles2/rasterizer_gles2.cpp

@@ -8699,7 +8699,7 @@ void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item, CanvasIte
 	}
 }
 
-void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material, Shader *shader) {
+void RasterizerGLES2::_canvas_item_setup_shader_params(ShaderMaterial *material, Shader *shader) {
 
 	if (canvas_shader.bind())
 		rebind_texpixel_size = true;
@@ -8748,7 +8748,7 @@ void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *mater
 	uses_texpixel_size = shader->uses_texpixel_size;
 }
 
-void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItemMaterial *material, Shader *shader) {
+void RasterizerGLES2::_canvas_item_setup_shader_uniforms(ShaderMaterial *material, Shader *shader) {
 
 	//this can be optimized..
 	int tex_id = 1;
@@ -8925,7 +8925,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list, int p_z, cons
 
 		//begin rect
 		CanvasItem *material_owner = ci->material_owner ? ci->material_owner : ci;
-		CanvasItemMaterial *material = material_owner->material;
+		ShaderMaterial *material = material_owner->material;
 
 		if (material != canvas_last_material || rebind_shader) {
 

+ 3 - 3
drivers/gles2/rasterizer_gles2.h

@@ -1224,7 +1224,7 @@ class RasterizerGLES2 : public Rasterizer {
 	bool uses_texpixel_size;
 	bool rebind_texpixel_size;
 	Transform canvas_transform;
-	CanvasItemMaterial *canvas_last_material;
+	ShaderMaterial *canvas_last_material;
 	bool canvas_texscreen_used;
 	Vector2 normal_flip;
 	_FORCE_INLINE_ void _canvas_normal_set_flip(const Vector2 &p_flip);
@@ -1288,8 +1288,8 @@ class RasterizerGLES2 : public Rasterizer {
 
 	template <bool use_normalmap>
 	_FORCE_INLINE_ void _canvas_item_render_commands(CanvasItem *p_item, CanvasItem *current_clip, bool &reclip);
-	_FORCE_INLINE_ void _canvas_item_setup_shader_params(CanvasItemMaterial *material, Shader *p_shader);
-	_FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItemMaterial *material, Shader *p_shader);
+	_FORCE_INLINE_ void _canvas_item_setup_shader_params(ShaderMaterial *material, Shader *p_shader);
+	_FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(ShaderMaterial *material, Shader *p_shader);
 
 public:
 	/* TEXTURE API */

+ 1 - 1
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -687,7 +687,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
 }
 
 #if 0
-void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* shader) {
+void RasterizerGLES2::_canvas_item_setup_shader_params(ShaderMaterial *material,Shader* shader) {
 
 	if (canvas_shader.bind())
 		rebind_texpixel_size=true;

+ 89 - 67
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -1283,6 +1283,35 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) {
 			}
 
 		} break;
+		case VS::INSTANCE_PARTICLES: {
+
+			RasterizerStorageGLES3::Particles *particles = static_cast<RasterizerStorageGLES3::Particles *>(e->owner);
+			RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry);
+
+			glBindVertexArray(s->instancing_array_id); // use the instancing array ID
+			glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //modify the buffer
+
+			int stride = sizeof(float) * 4 * 6;
+
+			//transform
+
+			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);
+
+		} break;
 	}
 }
 
@@ -1451,6 +1480,30 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
 				restore_tex = false;
 			}
 		} break;
+		case VS::INSTANCE_PARTICLES: {
+
+			RasterizerStorageGLES3::Particles *particles = static_cast<RasterizerStorageGLES3::Particles *>(e->owner);
+			RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry);
+
+			if (!particles->use_local_coords) //not using local coordinates? then clear transform..
+				state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, Transform());
+
+			int amount = particles->amount;
+
+			if (s->index_array_len > 0) {
+
+				glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount);
+
+				storage->info.render_vertices_count += s->index_array_len * amount;
+
+			} else {
+
+				glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount);
+
+				storage->info.render_vertices_count += s->array_len * amount;
+			}
+
+		} break;
 	}
 }
 
@@ -1556,61 +1609,6 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform
 	}
 }
 
-void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance, const Transform &p_view_transform, const CameraMatrix &p_projection) {
-
-	if (p_instance->billboard || p_instance->billboard_y || p_instance->depth_scale) {
-
-		Transform xf = p_instance->transform;
-		if (p_instance->depth_scale) {
-
-			if (p_projection.matrix[3][3]) {
-				//orthogonal matrix, try to do about the same
-				//with viewport size
-				//real_t w = Math::abs( 1.0/(2.0*(p_projection.matrix[0][0])) );
-				real_t h = Math::abs(1.0 / (2.0 * p_projection.matrix[1][1]));
-				float sc = (h * 2.0); //consistent with Y-fov
-				xf.basis.scale(Vector3(sc, sc, sc));
-			} else {
-				//just scale by depth
-				real_t sc = Plane(p_view_transform.origin, -p_view_transform.get_basis().get_axis(2)).distance_to(xf.origin);
-				xf.basis.scale(Vector3(sc, sc, sc));
-			}
-		}
-
-		if (p_instance->billboard && storage->frame.current_rt) {
-
-			Vector3 scale = xf.basis.get_scale();
-
-			if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) {
-				xf.set_look_at(xf.origin, xf.origin + p_view_transform.get_basis().get_axis(2), -p_view_transform.get_basis().get_axis(1));
-			} else {
-				xf.set_look_at(xf.origin, xf.origin + p_view_transform.get_basis().get_axis(2), p_view_transform.get_basis().get_axis(1));
-			}
-
-			xf.basis.scale(scale);
-		}
-
-		if (p_instance->billboard_y && storage->frame.current_rt) {
-
-			Vector3 scale = xf.basis.get_scale();
-			Vector3 look_at = p_view_transform.get_origin();
-			look_at.y = 0.0;
-			Vector3 look_at_norm = look_at.normalized();
-
-			if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) {
-				xf.set_look_at(xf.origin, xf.origin + look_at_norm, Vector3(0.0, -1.0, 0.0));
-			} else {
-				xf.set_look_at(xf.origin, xf.origin + look_at_norm, Vector3(0.0, 1.0, 0.0));
-			}
-			xf.basis.scale(scale);
-		}
-		state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, xf);
-
-	} else {
-		state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, p_instance->transform);
-	}
-}
-
 void RasterizerSceneGLES3::_set_cull(bool p_front, bool p_reverse_cull) {
 
 	bool front = p_front;
@@ -1677,6 +1675,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
 	state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, true); //by default unshaded (easier to set)
 
 	bool first = true;
+	bool prev_use_instancing = false;
 
 	storage->info.render_object_count += p_element_count;
 
@@ -1804,10 +1803,10 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
 			}
 		}
 
+		bool use_instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH || e->instance->base_type == VS::INSTANCE_PARTICLES;
 
-
-		if ((prev_base_type == VS::INSTANCE_MULTIMESH) != (e->instance->base_type == VS::INSTANCE_MULTIMESH)) {
-			state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING, e->instance->base_type == VS::INSTANCE_MULTIMESH);
+		if (use_instancing != prev_use_instancing) {
+			state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING, use_instancing);
 			rebind = true;
 		}
 
@@ -1820,7 +1819,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
 			if (skeleton.is_valid()) {
 				RasterizerStorageGLES3::Skeleton *sk = storage->skeleton_owner.getornull(skeleton);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6);
-				glBindTexture(GL_TEXTURE_2D,sk->texture);
+				glBindTexture(GL_TEXTURE_2D, sk->texture);
 			}
 		}
 
@@ -1835,8 +1834,6 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
 			}
 		}
 
-
-
 		if (!(e->sort_key & RenderList::SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) {
 			_setup_light(e, p_view_transform);
 		}
@@ -1850,8 +1847,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
 		_set_cull(e->sort_key & RenderList::SORT_KEY_MIRROR_FLAG, p_reverse_cull);
 
 		state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror ? -1.0 : 1.0);
-
-		_setup_transform(e->instance, p_view_transform, p_projection);
+		state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform);
 
 		_render_geometry(e);
 
@@ -1861,6 +1857,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
 		prev_owner = e->owner;
 		prev_shading = shading;
 		prev_skeleton = skeleton;
+		prev_use_instancing = use_instancing;
 		first = false;
 	}
 
@@ -1930,7 +1927,7 @@ void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geo
 		if (has_blend_alpha || (has_base_alpha && m->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))
 			return; //bye
 
-		if (!m->shader->spatial.uses_vertex && !m->shader->spatial.uses_discard && m->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
+		if (!m->shader->spatial.writes_modelview_or_projection && !m->shader->spatial.uses_vertex && !m->shader->spatial.uses_discard && m->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
 			//shader does not use discard and does not write a vertex position, use generic material
 			if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED)
 				m = storage->material_owner.getptr(default_material_twosided);
@@ -2729,6 +2726,30 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p
 			} break;
 			case VS::INSTANCE_IMMEDIATE: {
 
+			} break;
+			case VS::INSTANCE_PARTICLES: {
+
+				RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getptr(inst->base);
+				ERR_CONTINUE(!particles);
+
+				for (int i = 0; i < particles->draw_passes.size(); i++) {
+
+					RID pmesh = particles->draw_passes[i];
+					if (!pmesh.is_valid())
+						continue;
+					RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.get(pmesh);
+					if (!mesh)
+						continue; //mesh not assigned
+
+					int ssize = mesh->surfaces.size();
+
+					for (int j = 0; j < ssize; j++) {
+
+						RasterizerStorageGLES3::Surface *s = mesh->surfaces[j];
+						_add_geometry(s, inst, particles, -1, p_shadow);
+					}
+				}
+
 			} break;
 		}
 	}
@@ -4419,13 +4440,14 @@ void RasterizerSceneGLES3::initialize() {
 
 	state.scene_shader.init();
 
-	default_shader = storage->shader_create(VS::SHADER_SPATIAL);
+	default_shader = storage->shader_create();
+	storage->shader_set_code(default_shader, "shader_type spatial;\n");
 	default_material = storage->material_create();
 	storage->material_set_shader(default_material, default_shader);
 
-	default_shader_twosided = storage->shader_create(VS::SHADER_SPATIAL);
+	default_shader_twosided = storage->shader_create();
 	default_material_twosided = storage->material_create();
-	storage->shader_set_code(default_shader_twosided, "render_mode cull_disabled;\n");
+	storage->shader_set_code(default_shader_twosided, "shader_type spatial; render_mode cull_disabled;\n");
 	storage->material_set_shader(default_material_twosided, default_shader_twosided);
 
 	glGenBuffers(1, &state.scene_ubo);

+ 0 - 1
drivers/gles3/rasterizer_scene_gles3.h

@@ -691,7 +691,6 @@ public:
 	_FORCE_INLINE_ void _set_cull(bool p_front, bool p_reverse_cull);
 
 	_FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material *p_material, bool p_alpha_pass);
-	_FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance, const Transform &p_view_transform, const CameraMatrix &p_projection);
 	_FORCE_INLINE_ void _setup_geometry(RenderList::Element *e);
 	_FORCE_INLINE_ void _render_geometry(RenderList::Element *e);
 	_FORCE_INLINE_ void _setup_light(RenderList::Element *e, const Transform &p_view_transform);

+ 190 - 78
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -1338,12 +1338,12 @@ void RasterizerStorageGLES3::skybox_set_texture(RID p_skybox, RID p_cube_map, in
 
 /* SHADER API */
 
-RID RasterizerStorageGLES3::shader_create(VS::ShaderMode p_mode) {
+RID RasterizerStorageGLES3::shader_create() {
 
 	Shader *shader = memnew(Shader);
-	shader->mode = p_mode;
+	shader->mode = VS::SHADER_SPATIAL;
+	shader->shader = &scene->state.scene_shader;
 	RID rid = shader_owner.make_rid(shader);
-	shader_set_mode(rid, p_mode);
 	_shader_make_dirty(shader);
 	shader->self = rid;
 
@@ -1358,22 +1358,30 @@ void RasterizerStorageGLES3::_shader_make_dirty(Shader *p_shader) {
 	_shader_dirty_list.add(&p_shader->dirty_list);
 }
 
-void RasterizerStorageGLES3::shader_set_mode(RID p_shader, VS::ShaderMode p_mode) {
+void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String &p_code) {
 
-	ERR_FAIL_INDEX(p_mode, VS::SHADER_MAX);
 	Shader *shader = shader_owner.get(p_shader);
 	ERR_FAIL_COND(!shader);
 
-	if (shader->custom_code_id && p_mode == shader->mode)
-		return;
+	shader->code = p_code;
+
+	String mode_string = ShaderLanguage::get_shader_type(p_code);
+	VS::ShaderMode mode;
 
-	if (shader->custom_code_id) {
+	if (mode_string == "canvas_item")
+		mode = VS::SHADER_CANVAS_ITEM;
+	else if (mode_string == "particles")
+		mode = VS::SHADER_PARTICLES;
+	else
+		mode = VS::SHADER_SPATIAL;
+
+	if (shader->custom_code_id && mode != shader->mode) {
 
 		shader->shader->free_custom_shader(shader->custom_code_id);
 		shader->custom_code_id = 0;
 	}
 
-	shader->mode = p_mode;
+	shader->mode = mode;
 
 	ShaderGLES3 *shaders[VS::SHADER_MAX] = {
 		&scene->state.scene_shader,
@@ -1382,25 +1390,12 @@ void RasterizerStorageGLES3::shader_set_mode(RID p_shader, VS::ShaderMode p_mode
 
 	};
 
-	shader->shader = shaders[p_mode];
-
-	shader->custom_code_id = shader->shader->create_custom_shader();
-
-	_shader_make_dirty(shader);
-}
-VS::ShaderMode RasterizerStorageGLES3::shader_get_mode(RID p_shader) const {
-
-	const Shader *shader = shader_owner.get(p_shader);
-	ERR_FAIL_COND_V(!shader, VS::SHADER_MAX);
-
-	return shader->mode;
-}
-void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String &p_code) {
+	shader->shader = shaders[mode];
 
-	Shader *shader = shader_owner.get(p_shader);
-	ERR_FAIL_COND(!shader);
+	if (shader->custom_code_id == 0) {
+		shader->custom_code_id = shader->shader->create_custom_shader();
+	}
 
-	shader->code = p_code;
 	_shader_make_dirty(shader);
 }
 String RasterizerStorageGLES3::shader_get_code(RID p_shader) const {
@@ -1453,6 +1448,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const {
 			p_shader->spatial.ontop = false;
 			p_shader->spatial.uses_sss = false;
 			p_shader->spatial.uses_vertex = false;
+			p_shader->spatial.writes_modelview_or_projection = false;
 
 			shaders.actions_scene.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_ADD);
 			shaders.actions_scene.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MIX);
@@ -1477,6 +1473,9 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const {
 			shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"] = &p_shader->spatial.uses_sss;
 			shaders.actions_scene.usage_flag_pointers["DISCARD"] = &p_shader->spatial.uses_discard;
 
+			shaders.actions_scene.write_flag_pointers["MODELVIEW_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection;
+			shaders.actions_scene.write_flag_pointers["PROJECTION_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection;
+
 			actions = &shaders.actions_scene;
 			actions->uniforms = &p_shader->uniforms;
 
@@ -4861,6 +4860,8 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount)
 	Particles *particles = particles_owner.getornull(p_particles);
 	ERR_FAIL_COND(!particles);
 
+	particles->amount = p_amount;
+
 	int floats = p_amount * 24;
 	float *data = memnew_arr(float, floats);
 
@@ -4868,17 +4869,25 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount)
 		data[i] = 0;
 	}
 
-	glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]);
-	glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_DRAW);
+	for (int i = 0; i < 2; i++) {
 
-	glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[1]);
-	glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_DRAW);
+		glBindVertexArray(particles->particle_vaos[i]);
 
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
+		glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[i]);
+		glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_DRAW);
+
+		for (int i = 0; i < 6; i++) {
+			glEnableVertexAttribArray(i);
+			glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (i * 16));
+		}
+	}
+
+	glBindVertexArray(0);
 
 	particles->prev_ticks = 0;
 	particles->phase = 0;
 	particles->prev_phase = 0;
+	particles->clear = true;
 
 	memdelete_arr(data);
 }
@@ -4927,41 +4936,29 @@ void RasterizerStorageGLES3::particles_set_use_local_coordinates(RID p_particles
 
 	particles->use_local_coords = p_enable;
 }
-void RasterizerStorageGLES3::particles_set_process_material(RID p_particles, RID p_material) {
-
-	Particles *particles = particles_owner.getornull(p_particles);
-	ERR_FAIL_COND(!particles);
 
-	particles->process_material = p_material;
-}
-
-void RasterizerStorageGLES3::particles_set_emission_shape(RID p_particles, VS::ParticlesEmissionShape p_shape) {
+void RasterizerStorageGLES3::particles_set_fixed_fps(RID p_particles, int p_fps) {
 
 	Particles *particles = particles_owner.getornull(p_particles);
 	ERR_FAIL_COND(!particles);
 
-	particles->emission_shape = p_shape;
+	particles->fixed_fps = p_fps;
 }
-void RasterizerStorageGLES3::particles_set_emission_sphere_radius(RID p_particles, float p_radius) {
 
-	Particles *particles = particles_owner.getornull(p_particles);
-	ERR_FAIL_COND(!particles);
-
-	particles->emission_sphere_radius = p_radius;
-}
-void RasterizerStorageGLES3::particles_set_emission_box_extents(RID p_particles, const Vector3 &p_extents) {
+void RasterizerStorageGLES3::particles_set_fractional_delta(RID p_particles, bool p_enable) {
 
 	Particles *particles = particles_owner.getornull(p_particles);
 	ERR_FAIL_COND(!particles);
 
-	particles->emission_box_extents = p_extents;
+	particles->fractional_delta = p_enable;
 }
-void RasterizerStorageGLES3::particles_set_emission_points(RID p_particles, const PoolVector<Vector3> &p_points) {
+
+void RasterizerStorageGLES3::particles_set_process_material(RID p_particles, RID p_material) {
 
 	Particles *particles = particles_owner.getornull(p_particles);
 	ERR_FAIL_COND(!particles);
 
-	particles->emission_points = p_points;
+	particles->process_material = p_material;
 }
 
 void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) {
@@ -4972,26 +4969,30 @@ void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles, VS::Parti
 	particles->draw_order = p_order;
 }
 
-void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles, int p_count) {
+void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles, int p_passes) {
 
 	Particles *particles = particles_owner.getornull(p_particles);
 	ERR_FAIL_COND(!particles);
 
-	particles->draw_passes.resize(p_count);
+	particles->draw_passes.resize(p_passes);
 }
-void RasterizerStorageGLES3::particles_set_draw_pass_material(RID p_particles, int p_pass, RID p_material) {
+
+void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
 
 	Particles *particles = particles_owner.getornull(p_particles);
 	ERR_FAIL_COND(!particles);
 	ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
-	particles->draw_passes[p_pass].material = p_material;
+	particles->draw_passes[p_pass] = p_mesh;
 }
-void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
+
+void RasterizerStorageGLES3::particles_request_process(RID p_particles) {
 
 	Particles *particles = particles_owner.getornull(p_particles);
 	ERR_FAIL_COND(!particles);
-	ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
-	particles->draw_passes[p_pass].mesh = p_mesh;
+
+	if (!particles->particle_element.in_list()) {
+		particle_update_list.add(&particles->particle_element);
+	}
 }
 
 Rect3 RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) {
@@ -5002,10 +5003,86 @@ Rect3 RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) {
 	return particles->computed_aabb;
 }
 
+Rect3 RasterizerStorageGLES3::particles_get_aabb(RID p_particles) const {
+
+	const Particles *particles = particles_owner.getornull(p_particles);
+	ERR_FAIL_COND_V(!particles, Rect3());
+
+	return Rect3(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+}
+
+void RasterizerStorageGLES3::particles_set_emission_transform(RID p_particles, const Transform &p_transform) {
+
+	Particles *particles = particles_owner.getornull(p_particles);
+	ERR_FAIL_COND(!particles);
+
+	particles->emission_transform = p_transform;
+}
+
+void RasterizerStorageGLES3::_particles_process(Particles *particles, float p_delta) {
+
+	float new_phase = Math::fmod((float)particles->phase + (p_delta / particles->lifetime), (float)1.0);
+
+	if (particles->clear) {
+		particles->cycle_number = 0;
+	} else if (new_phase < particles->phase) {
+		particles->cycle_number++;
+	}
+
+	shaders.particles.set_uniform(ParticlesShaderGLES3::SYSTEM_PHASE, new_phase);
+	shaders.particles.set_uniform(ParticlesShaderGLES3::PREV_SYSTEM_PHASE, particles->phase);
+	particles->phase = new_phase;
+
+	shaders.particles.set_uniform(ParticlesShaderGLES3::DELTA, p_delta);
+	shaders.particles.set_uniform(ParticlesShaderGLES3::CLEAR, particles->clear);
+	if (particles->use_local_coords)
+		shaders.particles.set_uniform(ParticlesShaderGLES3::EMISSION_TRANSFORM, Transform());
+	else
+		shaders.particles.set_uniform(ParticlesShaderGLES3::EMISSION_TRANSFORM, particles->emission_transform);
+
+	glUniform1ui(shaders.particles.get_uniform(ParticlesShaderGLES3::CYCLE), particles->cycle_number);
+
+	particles->clear = false;
+
+	glBindVertexArray(particles->particle_vaos[0]);
+
+	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->particle_buffers[1]);
+
+	//		GLint size = 0;
+	//		glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
+
+	glBeginTransformFeedback(GL_POINTS);
+	glDrawArrays(GL_POINTS, 0, particles->amount);
+	glEndTransformFeedback();
+
+	SWAP(particles->particle_buffers[0], particles->particle_buffers[1]);
+	SWAP(particles->particle_vaos[0], particles->particle_vaos[1]);
+
+	glBindVertexArray(0);
+	/* //debug particles :D
+	glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]);
+
+	float *data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT);
+	for (int i = 0; i < particles->amount; i++) {
+		int ofs = i * 24;
+		print_line(itos(i) + ":");
+		print_line("\tColor: " + Color(data[ofs + 0], data[ofs + 1], data[ofs + 2], data[ofs + 3]));
+		print_line("\tVelocity: " + Vector3(data[ofs + 4], data[ofs + 5], data[ofs + 6]));
+		print_line("\tActive: " + itos(data[ofs + 7]));
+		print_line("\tCustom: " + Color(data[ofs + 8], data[ofs + 9], data[ofs + 10], data[ofs + 11]));
+		print_line("\tXF X: " + Color(data[ofs + 12], data[ofs + 13], data[ofs + 14], data[ofs + 15]));
+		print_line("\tXF Y: " + Color(data[ofs + 16], data[ofs + 17], data[ofs + 18], data[ofs + 19]));
+		print_line("\tXF Z: " + Color(data[ofs + 20], data[ofs + 21], data[ofs + 22], data[ofs + 23]));
+	}
+
+	glUnmapBuffer(GL_ARRAY_BUFFER);
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+	//*/
+}
+
 void RasterizerStorageGLES3::update_particles() {
 
 	glEnable(GL_RASTERIZER_DISCARD);
-	glBindVertexArray(0);
 
 	while (particle_update_list.first()) {
 
@@ -5068,38 +5145,61 @@ void RasterizerStorageGLES3::update_particles() {
 			}
 		}
 
-		shaders.particles.bind();
-
-		shaders.particles.set_uniform(ParticlesShaderGLES3::ORIGIN, particles->origin);
-
-		float new_phase = Math::fmod((float)particles->phase + (frame.delta / particles->lifetime), (float)1.0);
+		shaders.particles.set_conditional(ParticlesShaderGLES3::USE_FRACTIONAL_DELTA, particles->fractional_delta);
 
-		shaders.particles.set_uniform(ParticlesShaderGLES3::SYSTEM_PHASE, new_phase);
-		shaders.particles.set_uniform(ParticlesShaderGLES3::PREV_SYSTEM_PHASE, particles->phase);
-		particles->phase = new_phase;
+		shaders.particles.bind();
 
 		shaders.particles.set_uniform(ParticlesShaderGLES3::TOTAL_PARTICLES, particles->amount);
-		shaders.particles.set_uniform(ParticlesShaderGLES3::TIME, 0.0);
+		shaders.particles.set_uniform(ParticlesShaderGLES3::TIME, Color(frame.time[0], frame.time[1], frame.time[2], frame.time[3]));
 		shaders.particles.set_uniform(ParticlesShaderGLES3::EXPLOSIVENESS, particles->explosiveness);
-		shaders.particles.set_uniform(ParticlesShaderGLES3::DELTA, frame.delta);
+		shaders.particles.set_uniform(ParticlesShaderGLES3::LIFETIME, particles->lifetime);
 		shaders.particles.set_uniform(ParticlesShaderGLES3::GRAVITY, particles->gravity);
 		shaders.particles.set_uniform(ParticlesShaderGLES3::ATTRACTOR_COUNT, 0);
+		shaders.particles.set_uniform(ParticlesShaderGLES3::EMITTING, particles->emitting);
+		shaders.particles.set_uniform(ParticlesShaderGLES3::RANDOMNESS, particles->randomness);
 
-		glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]);
-		glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->particle_buffers[1]);
+		if (particles->clear && particles->pre_process_time > 0.0) {
 
-		for (int i = 0; i < 6; i++) {
-			glEnableVertexAttribArray(i);
-			glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (i * 16));
+			float frame_time;
+			if (particles->fixed_fps > 0)
+				frame_time = 1.0 / particles->fixed_fps;
+			else
+				frame_time = 1.0 / 30.0;
+
+			float delta = particles->pre_process_time;
+			if (delta > 0.1) { //avoid recursive stalls if fps goes below 10
+				delta = 0.1;
+			}
+			float todo = delta;
+
+			while (todo >= frame_time) {
+				_particles_process(particles, frame_time);
+				todo -= frame_time;
+			}
 		}
 
-		glBeginTransformFeedback(GL_POINTS);
-		glDrawArrays(GL_POINTS, 0, particles->amount);
-		glEndTransformFeedback();
+		if (particles->fixed_fps > 0) {
+			float frame_time = 1.0 / particles->fixed_fps;
+			float delta = frame.delta;
+			if (delta > 0.1) { //avoid recursive stalls if fps goes below 10
+				delta = 0.1;
+			} else if (delta <= 0.0) { //unlikely but..
+				delta = 0.001;
+			}
+			float todo = particles->frame_remainder + delta;
 
-		particle_update_list.remove(particle_update_list.first());
+			while (todo >= frame_time) {
+				_particles_process(particles, frame_time);
+				todo -= frame_time;
+			}
+
+			particles->frame_remainder = todo;
+
+		} else {
+			_particles_process(particles, frame.delta);
+		}
 
-		SWAP(particles->particle_buffers[0], particles->particle_buffers[1]);
+		particle_update_list.remove(particle_update_list.first());
 	}
 
 	glDisable(GL_RASTERIZER_DISCARD);
@@ -5143,6 +5243,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene
 			inst = immediate_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
 		} break;
+		case VS::INSTANCE_PARTICLES: {
+			inst = particles_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
 		case VS::INSTANCE_REFLECTION_PROBE: {
 			inst = reflection_probe_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
@@ -5182,6 +5286,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base, RasterizerSc
 			inst = immediate_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
 		} break;
+		case VS::INSTANCE_PARTICLES: {
+			inst = particles_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
 		case VS::INSTANCE_REFLECTION_PROBE: {
 			inst = reflection_probe_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
@@ -5856,6 +5964,10 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
 		return VS::INSTANCE_IMMEDIATE;
 	}
 
+	if (particles_owner.owns(p_rid)) {
+		return VS::INSTANCE_PARTICLES;
+	}
+
 	if (light_owner.owns(p_rid)) {
 		return VS::INSTANCE_LIGHT;
 	}

+ 30 - 28
drivers/gles3/rasterizer_storage_gles3.h

@@ -408,6 +408,7 @@ public:
 			bool uses_vertex;
 			bool uses_discard;
 			bool uses_sss;
+			bool writes_modelview_or_projection;
 
 		} spatial;
 
@@ -433,10 +434,7 @@ public:
 
 	mutable RID_Owner<Shader> shader_owner;
 
-	virtual RID shader_create(VS::ShaderMode p_mode = VS::SHADER_SPATIAL);
-
-	virtual void shader_set_mode(RID p_shader, VS::ShaderMode p_mode);
-	virtual VS::ShaderMode shader_get_mode(RID p_shader) const;
+	virtual RID shader_create();
 
 	virtual void shader_set_code(RID p_shader, const String &p_code);
 	virtual String shader_get_code(RID p_shader) const;
@@ -778,7 +776,7 @@ public:
 
 		Skeleton()
 			: update_list(this) {
-			size=0;
+			size = 0;
 
 			use_2d = false;
 			texture = 0;
@@ -987,7 +985,7 @@ public:
 
 	/* PARTICLES */
 
-	struct Particles : public Instantiable {
+	struct Particles : public GeometryOwner {
 
 		bool emitting;
 		int amount;
@@ -1000,23 +998,14 @@ public:
 		bool use_local_coords;
 		RID process_material;
 
-		VS::ParticlesEmissionShape emission_shape;
-		float emission_sphere_radius;
-		Vector3 emission_box_extents;
-		PoolVector<Vector3> emission_points;
-		GLuint emission_point_texture;
-
 		VS::ParticlesDrawOrder draw_order;
-		struct DrawPass {
-			RID mesh;
-			RID material;
-		};
 
-		Vector<DrawPass> draw_passes;
+		Vector<RID> draw_passes;
 
 		Rect3 computed_aabb;
 
 		GLuint particle_buffers[2];
+		GLuint particle_vaos[2];
 
 		SelfList<Particles> particle_element;
 
@@ -1024,10 +1013,19 @@ public:
 		float prev_phase;
 		uint64_t prev_ticks;
 
-		Transform origin;
+		uint32_t cycle_number;
+
+		int fixed_fps = 0;
+		bool fractional_delta;
+		float frame_remainder;
+
+		bool clear;
+
+		Transform emission_transform;
 
 		Particles()
 			: particle_element(this) {
+			cycle_number = 0;
 			emitting = false;
 			amount = 0;
 			lifetime = 1.0;
@@ -1035,23 +1033,26 @@ public:
 			explosiveness = 0.0;
 			randomness = 0.0;
 			use_local_coords = true;
+			fixed_fps = 0;
+			fractional_delta = false;
+			frame_remainder = 0;
 
 			draw_order = VS::PARTICLES_DRAW_ORDER_INDEX;
-			emission_shape = VS::PARTICLES_EMSSION_POINT;
-			emission_sphere_radius = 1.0;
-			emission_box_extents = Vector3(1, 1, 1);
-			emission_point_texture = 0;
 			particle_buffers[0] = 0;
 			particle_buffers[1] = 0;
 
 			prev_ticks = 0;
 
+			clear = true;
+
 			glGenBuffers(2, particle_buffers);
+			glGenVertexArrays(2, particle_vaos);
 		}
 
 		~Particles() {
 
 			glDeleteBuffers(2, particle_buffers);
+			glDeleteVertexArrays(2, particle_vaos);
 		}
 	};
 
@@ -1073,19 +1074,20 @@ public:
 	virtual void particles_set_gravity(RID p_particles, const Vector3 &p_gravity);
 	virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
 	virtual void particles_set_process_material(RID p_particles, RID p_material);
-
-	virtual void particles_set_emission_shape(RID p_particles, VS::ParticlesEmissionShape p_shape);
-	virtual void particles_set_emission_sphere_radius(RID p_particles, float p_radius);
-	virtual void particles_set_emission_box_extents(RID p_particles, const Vector3 &p_extents);
-	virtual void particles_set_emission_points(RID p_particles, const PoolVector<Vector3> &p_points);
+	virtual void particles_set_fixed_fps(RID p_particles, int p_fps);
+	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable);
 
 	virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order);
 
 	virtual void particles_set_draw_passes(RID p_particles, int p_count);
-	virtual void particles_set_draw_pass_material(RID p_particles, int p_pass, RID p_material);
 	virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh);
 
+	virtual void particles_request_process(RID p_particles);
 	virtual Rect3 particles_get_current_aabb(RID p_particles);
+	virtual Rect3 particles_get_aabb(RID p_particles) const;
+
+	virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform);
+	void _particles_process(Particles *p_particles, float p_delta);
 
 	/* INSTANCE */
 

+ 66 - 10
drivers/gles3/shader_compiler_gles3.cpp

@@ -91,6 +91,16 @@ static String _prestr(SL::DataPrecision p_pres) {
 	return "";
 }
 
+static String _qualstr(SL::ArgumentQualifier p_qual) {
+
+	switch (p_qual) {
+		case SL::ARGUMENT_QUALIFIER_IN: return "";
+		case SL::ARGUMENT_QUALIFIER_OUT: return "out ";
+		case SL::ARGUMENT_QUALIFIER_INOUT: return "inout ";
+	}
+	return "";
+}
+
 static String _opstr(SL::Operator p_op) {
 
 	return SL::get_operator_text(p_op);
@@ -174,6 +184,21 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNo
 			text += ")";
 			return text;
 
+		} break;
+		case SL::TYPE_MAT2:
+		case SL::TYPE_MAT3:
+		case SL::TYPE_MAT4: {
+
+			String text = "mat" + itos(p_type - SL::TYPE_MAT2 + 2) + "(";
+			for (int i = 0; i < p_values.size(); i++) {
+				if (i > 0)
+					text += ",";
+
+				text += f2sp0(p_values[i].real);
+			}
+			text += ")";
+			return text;
+
 		} break;
 		default: ERR_FAIL_V(String());
 	}
@@ -194,6 +219,7 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri
 
 	for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
 
+		print_line(String(p_node->functions[fidx].name) + " uses function: " + String(E->get()));
 		if (added.has(E->get())) {
 			continue; //was added already
 		}
@@ -219,7 +245,7 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri
 
 			if (i > 0)
 				header += ", ";
-			header += _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
+			header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
 		}
 
 		header += ")\n";
@@ -383,6 +409,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 
 				if (fnode->name == "vertex") {
 
+					print_line("vertex uses functions: " + itos(pnode->functions[i].uses_function.size()));
 					_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx);
 					r_gen_code.vertex = function_code["vertex"];
 				}
@@ -482,6 +509,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 				case SL::OP_ASSIGN_BIT_AND:
 				case SL::OP_ASSIGN_BIT_OR:
 				case SL::OP_ASSIGN_BIT_XOR:
+					if (onode->arguments[0]->type == SL::Node::TYPE_VARIABLE) {
+						SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0];
+						if (p_actions.write_flag_pointers.has(vnode->name)) {
+							*p_actions.write_flag_pointers[vnode->name] = true;
+						}
+					}
 					code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions);
 					break;
 				case SL::OP_BIT_INVERT:
@@ -524,6 +557,23 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 					}
 					code += ")";
 				} break;
+				case SL::OP_INDEX: {
+
+					code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions);
+					code += "[";
+					code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions);
+					code += "]";
+
+				} break;
+				case SL::OP_SELECT_IF: {
+
+					code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions);
+					code += "?";
+					code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions);
+					code += ":";
+					code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions);
+
+				} break;
 				default: {
 
 					code = "(" + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions) + ")";
@@ -546,10 +596,10 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 
 			} else if (cfnode->flow_op == SL::FLOW_OP_RETURN) {
 
-				if (cfnode->blocks.size()) {
-					code = "return " + _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions);
+				if (cfnode->expressions.size()) {
+					code = "return " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions) + ";";
 				} else {
-					code = "return";
+					code = "return;";
 				}
 			}
 
@@ -566,7 +616,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 
 Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
 
-	Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode));
+	Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types());
 
 	if (err != OK) {
 #if 1
@@ -648,7 +698,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
 
 	actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
 	actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix";
+	actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix";
 	actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
+	actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
 
 	actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
 	actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal";
@@ -686,6 +738,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
 	actions[VS::SHADER_SPATIAL].renames["DISCARD"] = "_discard";
 	//actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2;
 	actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
+	actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
 
 	actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n";
 	actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT";
@@ -701,16 +754,17 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
 	actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n";
 	actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
 	actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n";
+	actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
 
 	actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS_MOTION\n";
 
 	actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
 
-	actions[VS::SHADER_SPATIAL].render_mode_defines["skip_transform"] = "#define SKIP_TRANSFORM_USED\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["skip_default_transform"] = "#define SKIP_TRANSFORM_USED\n";
 
 	/* PARTICLES SHADER */
 
-	actions[VS::SHADER_PARTICLES].renames["COLOR"] = "color";
+	actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color";
 	actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz";
 	actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass";
 	actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "active";
@@ -719,13 +773,15 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
 	actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform";
 	actions[VS::SHADER_PARTICLES].renames["TIME"] = "time";
 	actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime";
-	actions[VS::SHADER_PARTICLES].renames["DELTA"] = "delta";
-	actions[VS::SHADER_PARTICLES].renames["SEED"] = "seed";
-	actions[VS::SHADER_PARTICLES].renames["ORIGIN"] = "origin";
+	actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta";
+	actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number";
 	actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index";
+	actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity";
+	actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform";
 
 	actions[VS::SHADER_SPATIAL].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
 	actions[VS::SHADER_SPATIAL].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
+	actions[VS::SHADER_SPATIAL].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
 
 	vertex_name = "vertex";
 	fragment_name = "fragment";

+ 1 - 0
drivers/gles3/shader_compiler_gles3.h

@@ -41,6 +41,7 @@ public:
 		Map<StringName, Pair<int *, int> > render_mode_values;
 		Map<StringName, bool *> render_mode_flags;
 		Map<StringName, bool *> usage_flag_pointers;
+		Map<StringName, bool *> write_flag_pointers;
 
 		Map<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms;
 	};

+ 93 - 22
drivers/gles3/shaders/particles.glsl

@@ -22,16 +22,21 @@ struct Attractor {
 
 #define MAX_ATTRACTORS 64
 
-uniform mat4 origin;
+uniform bool emitting;
 uniform float system_phase;
 uniform float prev_system_phase;
-uniform float total_particles;
+uniform int total_particles;
 uniform float explosiveness;
+uniform float randomness;
 uniform vec4 time;
 uniform float delta;
 uniform vec3 gravity;
 uniform int attractor_count;
 uniform Attractor attractors[MAX_ATTRACTORS];
+uniform bool clear;
+uniform uint cycle;
+uniform float lifetime;
+uniform mat4 emission_transform;
 
 
 out highp vec4 out_color; //tfb:
@@ -53,52 +58,116 @@ MATERIAL_UNIFORMS
 
 #endif
 
+uint hash(uint x) {
+
+	x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+	x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+	x = (x >> uint(16)) ^ x;
+	return x;
+}
+
+
 void main() {
 
 	bool apply_forces=true;
 	bool apply_velocity=true;
+	vec3 current_gravity = gravity;
+	float local_delta=delta;
 
 	float mass = 1.0;
 
-	float restart_phase = float(gl_InstanceID)/total_particles;
-	restart_phase*= explosiveness;
+	float restart_phase = float(gl_VertexID)/float(total_particles);
+
+	if (randomness>0.0) {
+		uint seed = cycle;
+		if (restart_phase >= system_phase) {
+			seed-=uint(1);
+		}
+		seed*=uint(total_particles);
+		seed+=uint(gl_VertexID);
+		float random = float(hash(seed) % uint(65536)) / 65536.0;
+		restart_phase+=randomness * random * 1.0 / float(total_particles);
+	}
+
+	restart_phase*= (1.0-explosiveness);
 	bool restart=false;
-	bool active = out_velocity_active.a > 0.5;
+	bool active = velocity_active.a > 0.5;
 
 	if (system_phase > prev_system_phase) {
-		restart = prev_system_phase < restart_phase && system_phase >= restart_phase;
+		if (prev_system_phase < restart_phase && system_phase >= restart_phase) {
+			restart=true;
+#ifdef USE_FRACTIONAL_DELTA
+			local_delta = (system_phase - restart_phase) * lifetime;
+#endif
+		}
+
 	} else {
-		restart = prev_system_phase < restart_phase || system_phase >= restart_phase;
+		if (prev_system_phase < restart_phase) {
+			restart=true;
+#ifdef USE_FRACTIONAL_DELTA
+			local_delta = (1.0 - restart_phase + system_phase) * lifetime;
+#endif
+		} else if (system_phase >= restart_phase) {
+			restart=true;
+#ifdef USE_FRACTIONAL_DELTA
+			local_delta = (system_phase - restart_phase) * lifetime;
+#endif
+		}
 	}
 
-	if (restart) {
-		active=true;
+	uint current_cycle = cycle;
+
+	if (system_phase < restart_phase) {
+		current_cycle-=uint(1);
 	}
 
-	out_color=color;
-	out_velocity_active=velocity_active;
-	out_custom=custom;
+	uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID);
 
-	mat4 xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0)));
+	if (restart) {
+		active=emitting;
+	}
 
+	mat4 xform;
 
-	out_rot_active=rot_active;
+#if defined(ENABLE_KEEP_DATA)
+	if (clear) {
+#else
+	if (clear || restart) {
+#endif
+		out_color=vec4(1.0);
+		out_velocity_active=vec4(0.0);
+		out_custom=vec4(0.0);
+		if (!restart)
+			active=false;
+
+		xform = mat4(
+				vec4(1.0,0.0,0.0,0.0),
+				vec4(0.0,1.0,0.0,0.0),
+				vec4(0.0,0.0,1.0,0.0),
+				vec4(0.0,0.0,0.0,1.0)
+			);
+	} else {
+		out_color=color;
+		out_velocity_active=velocity_active;
+		out_custom=custom;
+		xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0)));
+	}
 
 	if (active) {
 		//execute shader
 
 		{
-			VERTEX_SHADER_CODE
+VERTEX_SHADER_CODE
 		}
 
 #if !defined(DISABLE_FORCE)
 
-		{
+		if (true) {
 
-			vec3 force = gravity;
+			vec3 force = current_gravity;
 			for(int i=0;i<attractor_count;i++) {
 
-				vec3 rel_vec = out_pos_lifetime.xyz - attractors[i].pos;
+				vec3 rel_vec = xform[3].xyz - attractors[i].pos;
 				float dist = rel_vec.length();
 				if (attractors[i].radius < dist)
 					continue;
@@ -119,17 +188,19 @@ void main() {
 				}
 			}
 
-			out_velocity_seed.xyz += force * delta;
+			out_velocity_active.xyz += force * local_delta;
 		}
 #endif
 
 #if !defined(DISABLE_VELOCITY)
 
-		{
+		if (true) {
 
-			out_pos_lifetime.xyz += out_velocity_seed.xyz * delta;
+			xform[3].xyz += out_velocity_active.xyz * local_delta;
 		}
 #endif
+	} else {
+		xform=mat4(0.0);
 	}
 
 	xform = transpose(xform);
@@ -162,6 +233,6 @@ MATERIAL_UNIFORMS
 void main() {
 
 	{
-		FRAGMENT_SHADER_CODE
+FRAGMENT_SHADER_CODE
 	}
 }

+ 50 - 29
drivers/gles3/shaders/scene.glsl

@@ -52,6 +52,10 @@ layout(location=9) in highp vec4 instance_xform1;
 layout(location=10) in highp vec4 instance_xform2;
 layout(location=11) in lowp vec4 instance_color;
 
+#if defined(ENABLE_INSTANCE_CUSTOM)
+layout(location=12) in highp vec4 instance_custom_data;
+#endif
+
 #endif
 
 layout(std140) uniform SceneData { //ubo:0
@@ -157,9 +161,21 @@ out highp vec4 position_interp;
 void main() {
 
 	highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0);
-	highp mat4 modelview = camera_inverse_matrix * world_transform;
+
+	mat4 world_matrix = world_transform;
+
+
+#ifdef USE_INSTANCING
+
+	{
+		highp mat4 m=mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0));
+		world_matrix = world_matrix * transpose(m);
+	}
+#endif
+
 	vec3 normal = normal_attrib * normal_mult;
 
+
 #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
 	vec3 tangent = tangent_attrib.xyz;
 	tangent*=normal_mult;
@@ -168,6 +184,10 @@ void main() {
 
 #if defined(ENABLE_COLOR_INTERP)
 	color_interp = color_attrib;
+#if defined(USE_INSTANCING)
+	color_interp *= instance_color;
+#endif
+
 #endif
 
 #ifdef USE_SKELETON
@@ -215,40 +235,12 @@ void main() {
 	}
 #endif
 
-#ifdef USE_INSTANCING
-
-	{
-		highp mat3x4 m=mat3x4(instance_xform0,instance_xform1,instance_xform2);
 
-		vertex.xyz = vertex * m;
-		normal = vec4(normal,0.0) * m;
 #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-		tangent.xyz = vec4(tangent.xyz,0.0) * mn;
-#endif
 
-#if defined(ENABLE_COLOR_INTERP)
-		color_interp*=instance_color;
-#endif
-	}
-#endif //USE_INSTANCING
-
-#if !defined(SKIP_TRANSFORM_USED)
-
-	vertex = modelview * vertex;
-	normal = normalize((modelview * vec4(normal,0.0)).xyz);
-#endif
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-# if !defined(SKIP_TRANSFORM_USED)
-
-	tangent=normalize((modelview * vec4(tangent,0.0)).xyz);
-# endif
 	vec3 binormal = normalize( cross(normal,tangent) * binormalf );
 #endif
 
-
-
-
 #if defined(ENABLE_UV_INTERP)
 	uv_interp = uv_attrib;
 #endif
@@ -257,16 +249,45 @@ void main() {
 	uv2_interp = uv2_attrib;
 #endif
 
+#if defined(USE_INSTANCING) && defined(ENABLE_INSTANCE_CUSTOM)
+	vec4 instance_custom = instance_custom_data;
+#else
+	vec4 instance_custom = vec4(0.0);
+#endif
+
+	highp mat4 modelview = camera_inverse_matrix * world_matrix;
+	highp mat4 local_projection = projection_matrix;
+
+//defines that make writing custom shaders easier
+#define projection_matrix local_projection
+#define world_transform world_matrix
 {
 
 VERTEX_SHADER_CODE
 
 }
 
+
+
+
+#if !defined(SKIP_TRANSFORM_USED)
+
+	vertex = modelview * vertex;
+	normal = normalize((modelview * vec4(normal,0.0)).xyz);
+#endif
+
+
 	vertex_interp = vertex.xyz;
 	normal_interp = normal;
 
 #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+
+#if !defined(SKIP_TRANSFORM_USED)
+
+	tangent = normalize((modelview * vec4(tangent,0.0)).xyz);
+	binormal = normalize((modelview * vec4(binormal,0.0)).xyz);
+
+#endif
 	tangent_interp = tangent;
 	binormal_interp = binormal;
 #endif

+ 1 - 1
editor/editor_file_system.cpp

@@ -789,7 +789,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
 			} else {
 
 				uint64_t import_mt = FileAccess::get_modified_time(path + ".import");
-				print_line(itos(import_mt) + " vs " + itos(p_dir->files[i]->import_modified_time));
+				//print_line(itos(import_mt) + " vs " + itos(p_dir->files[i]->import_modified_time));
 				if (import_mt != p_dir->files[i]->import_modified_time) {
 					print_line("REIMPORT: import modified changed, reimport");
 					reimport = true;

+ 5 - 1
editor/editor_node.cpp

@@ -73,7 +73,9 @@
 #include "plugins/collision_shape_2d_editor_plugin.h"
 #include "plugins/color_ramp_editor_plugin.h"
 #include "plugins/cube_grid_theme_editor_plugin.h"
+#include "plugins/curve_editor_plugin.h"
 #include "plugins/gi_probe_editor_plugin.h"
+#include "plugins/gradient_texture_editor_plugin.h"
 #include "plugins/item_list_editor_plugin.h"
 #include "plugins/light_occluder_2d_editor_plugin.h"
 #include "plugins/line_2d_editor_plugin.h"
@@ -5909,7 +5911,7 @@ EditorNode::EditorNode() {
 	//add_editor_plugin( memnew( MeshLibraryEditorPlugin(this) ) );
 	//add_editor_plugin( memnew( StreamEditorPlugin(this) ) );
 	add_editor_plugin(memnew(StyleBoxEditorPlugin(this)));
-	//add_editor_plugin( memnew( ParticlesEditorPlugin(this) ) );
+	add_editor_plugin(memnew(ParticlesEditorPlugin(this)));
 	add_editor_plugin(memnew(ResourcePreloaderEditorPlugin(this)));
 	add_editor_plugin(memnew(ItemListEditorPlugin(this)));
 	//add_editor_plugin( memnew( RichTextEditorPlugin(this) ) );
@@ -5929,7 +5931,9 @@ EditorNode::EditorNode() {
 	add_editor_plugin(memnew(LightOccluder2DEditorPlugin(this)));
 	add_editor_plugin(memnew(NavigationPolygonEditorPlugin(this)));
 	add_editor_plugin(memnew(ColorRampEditorPlugin(this)));
+	add_editor_plugin(memnew(GradientTextureEditorPlugin(this)));
 	add_editor_plugin(memnew(CollisionShape2DEditorPlugin(this)));
+	add_editor_plugin(memnew(CurveTextureEditorPlugin(this)));
 	add_editor_plugin(memnew(TextureEditorPlugin(this)));
 	add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));
 	//add_editor_plugin( memnew( MaterialEditorPlugin(this) ) );

+ 17 - 17
editor/import/editor_import_collada.cpp

@@ -364,7 +364,7 @@ Error ColladaImport::_create_material(const String &p_target) {
 	ERR_FAIL_COND_V(!collada.state.effect_map.has(src_mat.instance_effect), ERR_INVALID_PARAMETER);
 	Collada::Effect &effect = collada.state.effect_map[src_mat.instance_effect];
 
-	Ref<FixedSpatialMaterial> material = memnew(FixedSpatialMaterial);
+	Ref<SpatialMaterial> material = memnew(SpatialMaterial);
 
 	if (src_mat.name != "")
 		material->set_name(src_mat.name);
@@ -381,15 +381,15 @@ Error ColladaImport::_create_material(const String &p_target) {
 			Ref<Texture> texture = ResourceLoader::load(texfile, "Texture");
 			if (texture.is_valid()) {
 
-				material->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, texture);
+				material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture);
 				material->set_albedo(Color(1, 1, 1, 1));
-				//material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,1));
+				//material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,1));
 			} else {
 				missing_textures.push_back(texfile.get_file());
 			}
 		}
 	} else {
-		//material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,effect.diffuse.color);
+		//material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,effect.diffuse.color);
 	}
 
 	// SPECULAR
@@ -401,11 +401,11 @@ Error ColladaImport::_create_material(const String &p_target) {
 
 			Ref<Texture> texture = ResourceLoader::load(texfile, "Texture");
 			if (texture.is_valid()) {
-				material->set_texture(FixedSpatialMaterial::TEXTURE_SPECULAR, texture);
+				material->set_texture(SpatialMaterial::TEXTURE_SPECULAR, texture);
 				material->set_specular(Color(1, 1, 1, 1));
 
-				//material->set_texture(FixedSpatialMaterial::PARAM_SPECULAR,texture);
-				//material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR,Color(1,1,1,1));
+				//material->set_texture(SpatialMaterial::PARAM_SPECULAR,texture);
+				//material->set_parameter(SpatialMaterial::PARAM_SPECULAR,Color(1,1,1,1));
 			} else {
 				missing_textures.push_back(texfile.get_file());
 			}
@@ -424,18 +424,18 @@ Error ColladaImport::_create_material(const String &p_target) {
 			Ref<Texture> texture = ResourceLoader::load(texfile, "Texture");
 			if (texture.is_valid()) {
 
-				material->set_feature(FixedSpatialMaterial::FEATURE_EMISSION, true);
-				material->set_texture(FixedSpatialMaterial::TEXTURE_EMISSION, texture);
+				material->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
+				material->set_texture(SpatialMaterial::TEXTURE_EMISSION, texture);
 				material->set_emission(Color(1, 1, 1, 1));
 
-				//material->set_parameter(FixedSpatialMaterial::PARAM_EMISSION,Color(1,1,1,1));
+				//material->set_parameter(SpatialMaterial::PARAM_EMISSION,Color(1,1,1,1));
 			} else {
 				missing_textures.push_back(texfile.get_file());
 			}
 		}
 	} else {
 		if (effect.emission.color != Color()) {
-			material->set_feature(FixedSpatialMaterial::FEATURE_EMISSION, true);
+			material->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
 			material->set_emission(effect.emission.color);
 		}
 	}
@@ -449,11 +449,11 @@ Error ColladaImport::_create_material(const String &p_target) {
 
 			Ref<Texture> texture = ResourceLoader::load(texfile, "Texture");
 			if (texture.is_valid()) {
-				material->set_feature(FixedSpatialMaterial::FEATURE_NORMAL_MAPPING, true);
-				material->set_texture(FixedSpatialMaterial::TEXTURE_NORMAL, texture);
+				material->set_feature(SpatialMaterial::FEATURE_NORMAL_MAPPING, true);
+				material->set_texture(SpatialMaterial::TEXTURE_NORMAL, texture);
 				//material->set_emission(Color(1,1,1,1));
 
-				//material->set_texture(FixedSpatialMaterial::PARAM_NORMAL,texture);
+				//material->set_texture(SpatialMaterial::PARAM_NORMAL,texture);
 			} else {
 				//missing_textures.push_back(texfile.get_file());
 			}
@@ -464,9 +464,9 @@ Error ColladaImport::_create_material(const String &p_target) {
 	material->set_roughness(roughness);
 
 	if (effect.double_sided) {
-		material->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
+		material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
 	}
-	material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, effect.unshaded);
+	material->set_flag(SpatialMaterial::FLAG_UNSHADED, effect.unshaded);
 
 	material_cache[p_target] = material;
 	return OK;
@@ -1000,7 +1000,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<Mesh> &p_mesh, c
 
 		{
 
-			Ref<FixedSpatialMaterial> material;
+			Ref<SpatialMaterial> material;
 
 			//find material
 			Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES;

+ 18 - 16
editor/import/resource_importer_scene.cpp

@@ -157,7 +157,7 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
 		memdelete(p_node);
 		return NULL;
 	}
-
+#if 0
 	if (p_node->cast_to<MeshInstance>()) {
 
 		MeshInstance *mi = p_node->cast_to<MeshInstance>();
@@ -177,18 +177,18 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
 				Ref<Mesh> m = mi->get_mesh();
 				for (int i = 0; i < m->get_surface_count(); i++) {
 
-					Ref<FixedSpatialMaterial> fm = m->surface_get_material(i);
+					Ref<SpatialMaterial> fm = m->surface_get_material(i);
 					if (fm.is_valid()) {
 						//fm->set_flag(Material::FLAG_UNSHADED,true);
 						//fm->set_flag(Material::FLAG_DOUBLE_SIDED,true);
 						//fm->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
-						//fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+						//fm->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 					}
 				}
 			}
 		}
 	}
-
+#endif
 	if (p_node->cast_to<MeshInstance>()) {
 
 		MeshInstance *mi = p_node->cast_to<MeshInstance>();
@@ -199,19 +199,19 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
 
 			for (int i = 0; i < m->get_surface_count(); i++) {
 
-				Ref<FixedSpatialMaterial> mat = m->surface_get_material(i);
+				Ref<SpatialMaterial> mat = m->surface_get_material(i);
 				if (!mat.is_valid())
 					continue;
 
 				if (_teststr(mat->get_name(), "alpha")) {
 
-					mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+					mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 					mat->set_name(_fixstr(mat->get_name(), "alpha"));
 				}
 				if (_teststr(mat->get_name(), "vcol")) {
 
-					mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-					mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+					mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+					mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
 					mat->set_name(_fixstr(mat->get_name(), "vcol"));
 				}
 			}
@@ -242,7 +242,7 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
 			}
 		}
 	}
-
+#if 0
 	if (p_node->cast_to<MeshInstance>()) {
 
 		MeshInstance *mi = p_node->cast_to<MeshInstance>();
@@ -277,12 +277,12 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
 						Ref<Mesh> m = mi->get_mesh();
 						for (int i = 0; i < m->get_surface_count(); i++) {
 
-							Ref<FixedSpatialMaterial> fm = m->surface_get_material(i);
+							Ref<SpatialMaterial> fm = m->surface_get_material(i);
 							if (fm.is_valid()) {
 								//fm->set_flag(Material::FLAG_UNSHADED,true);
 								//fm->set_flag(Material::FLAG_DOUBLE_SIDED,true);
 								//fm->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
-								//fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+								//fm->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 							}
 						}
 					}
@@ -290,6 +290,8 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
 			}
 		}
 	}
+
+#endif
 #if 0
     if (p_flags&SCENE_FLAG_CREATE_LODS && p_node->cast_to<MeshInstance>()) {
 
@@ -325,12 +327,12 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
 			Ref<Mesh> m = mi->get_mesh();
 			for(int i=0;i<m->get_surface_count();i++) {
 
-			    Ref<FixedSpatialMaterial> fm = m->surface_get_material(i);
+			    Ref<SpatialMaterial> fm = m->surface_get_material(i);
 			    if (fm.is_valid()) {
 				fm->set_flag(Material::FLAG_UNSHADED,true);
 				fm->set_flag(Material::FLAG_DOUBLE_SIDED,true);
 				fm->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
-				fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+				fm->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 			    }
 			}
 		    }*/
@@ -687,16 +689,16 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
 
 			for (int i = 0; i < mesh->get_surface_count(); i++) {
 
-				Ref<FixedSpatialMaterial> fm = mesh->surface_get_material(i);
+				Ref<SpatialMaterial> fm = mesh->surface_get_material(i);
 				if (fm.is_valid()) {
 					String name = fm->get_name();
 					/*	if (_teststr(name,"alpha")) {
-						fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+						fm->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 						name=_fixstr(name,"alpha");
 					}
 
 					if (_teststr(name,"vcol")) {
-						fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY,true);
+						fm->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY,true);
 						name=_fixstr(name,"vcol");
 					}*/
 					fm->set_name(name);

+ 15 - 15
editor/io_plugins/editor_scene_import_plugin.cpp

@@ -1408,7 +1408,7 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<Imag
 					for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
 
 						if (E->get().type==Variant::OBJECT || E->get().type==Variant::ARRAY || E->get().type==Variant::DICTIONARY) {
-							if (E->get().type==Variant::OBJECT && res->cast_to<FixedSpatialMaterial>() && (E->get().name=="textures/diffuse" || E->get().name=="textures/detail" || E->get().name=="textures/emission")) {
+							if (E->get().type==Variant::OBJECT && res->cast_to<SpatialMaterial>() && (E->get().name=="textures/diffuse" || E->get().name=="textures/detail" || E->get().name=="textures/emission")) {
 
 								Ref<ImageTexture> tex =res->get(E->get().name);
 								if (tex.is_valid()) {
@@ -1416,7 +1416,7 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<Imag
 									image_map.insert(tex,TEXTURE_ROLE_DIFFUSE);
 								}
 
-							} else if (E->get().type==Variant::OBJECT && res->cast_to<FixedSpatialMaterial>() && (E->get().name=="textures/normal")) {
+							} else if (E->get().type==Variant::OBJECT && res->cast_to<SpatialMaterial>() && (E->get().name=="textures/normal")) {
 
 								Ref<ImageTexture> tex =res->get(E->get().name);
 								if (tex.is_valid()) {
@@ -1424,7 +1424,7 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map<Ref<Imag
 									image_map.insert(tex,TEXTURE_ROLE_NORMALMAP);
 									/*
 									if (p_flags&SCENE_FLAG_CONVERT_NORMALMAPS_TO_XY)
-										res->cast_to<FixedSpatialMaterial>()->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_XY_NORMALMAP,true);
+										res->cast_to<SpatialMaterial>()->set_fixed_flag(SpatialMaterial::FLAG_USE_XY_NORMALMAP,true);
 									*/
 								}
 
@@ -1532,12 +1532,12 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 				Ref<Mesh> m = mi->get_mesh();
 				for(int i=0;i<m->get_surface_count();i++) {
 
-					Ref<FixedSpatialMaterial> fm = m->surface_get_material(i);
+					Ref<SpatialMaterial> fm = m->surface_get_material(i);
 					if (fm.is_valid()) {
 						//fm->set_flag(Material::FLAG_UNSHADED,true);
 						//fm->set_flag(Material::FLAG_DOUBLE_SIDED,true);
 						//fm->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
-						//fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+						//fm->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 					}
 				}
 			}
@@ -1555,18 +1555,18 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 
 			for(int i=0;i<m->get_surface_count();i++) {
 
-				Ref<FixedSpatialMaterial> mat = m->surface_get_material(i);
+				Ref<SpatialMaterial> mat = m->surface_get_material(i);
 				if (!mat.is_valid())
 					continue;
 
 				if (p_flags&SCENE_FLAG_DETECT_ALPHA && _teststr(mat->get_name(),"alpha")) {
 
-					//mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+					//mat->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 					//mat->set_name(_fixstr(mat->get_name(),"alpha"));
 				}
 				if (p_flags&SCENE_FLAG_DETECT_VCOLOR && _teststr(mat->get_name(),"vcol")) {
 
-					//mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY,true);
+					//mat->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY,true);
 					//mat->set_name(_fixstr(mat->get_name(),"vcol"));
 				}
 
@@ -1641,12 +1641,12 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 						Ref<Mesh> m = mi->get_mesh();
 						for(int i=0;i<m->get_surface_count();i++) {
 
-							Ref<FixedSpatialMaterial> fm = m->surface_get_material(i);
+							Ref<SpatialMaterial> fm = m->surface_get_material(i);
 							if (fm.is_valid()) {
 								//fm->set_flag(Material::FLAG_UNSHADED,true);
 								//fm->set_flag(Material::FLAG_DOUBLE_SIDED,true);
 								//fm->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
-								//fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+								//fm->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 							}
 						}
 					}
@@ -1689,12 +1689,12 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 			Ref<Mesh> m = mi->get_mesh();
 			for(int i=0;i<m->get_surface_count();i++) {
 
-			    Ref<FixedSpatialMaterial> fm = m->surface_get_material(i);
+			    Ref<SpatialMaterial> fm = m->surface_get_material(i);
 			    if (fm.is_valid()) {
 				fm->set_flag(Material::FLAG_UNSHADED,true);
 				fm->set_flag(Material::FLAG_DOUBLE_SIDED,true);
 				fm->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
-				fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+				fm->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 			    }
 			}
 		    }*/
@@ -2062,16 +2062,16 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 
 			for(int i=0;i<mesh->get_surface_count();i++) {
 
-				Ref<FixedSpatialMaterial> fm = mesh->surface_get_material(i);
+				Ref<SpatialMaterial> fm = mesh->surface_get_material(i);
 				if (fm.is_valid()) {
 					String name = fm->get_name();
 				/*	if (_teststr(name,"alpha")) {
-						fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
+						fm->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
 						name=_fixstr(name,"alpha");
 					}
 
 					if (_teststr(name,"vcol")) {
-						fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY,true);
+						fm->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY,true);
 						name=_fixstr(name,"vcol");
 					}*/
 					fm->set_name(name);

+ 12 - 12
editor/io_plugins/editor_scene_importer_fbxconv.cpp

@@ -483,29 +483,29 @@ void EditorSceneImporterFBXConv::_parse_materials(State& state) {
 		ERR_CONTINUE(!material.has("id"));
 		String id = _id(material["id"]);
 
-		Ref<FixedSpatialMaterial> mat = memnew( FixedSpatialMaterial );
+		Ref<SpatialMaterial> mat = memnew( SpatialMaterial );
 
 		if (material.has("diffuse")) {
-			mat->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,_get_color(material["diffuse"]));
+			mat->set_parameter(SpatialMaterial::PARAM_DIFFUSE,_get_color(material["diffuse"]));
 		}
 
 		if (material.has("specular")) {
-			mat->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR,_get_color(material["specular"]));
+			mat->set_parameter(SpatialMaterial::PARAM_SPECULAR,_get_color(material["specular"]));
 		}
 
 		if (material.has("emissive")) {
-			mat->set_parameter(FixedSpatialMaterial::PARAM_EMISSION,_get_color(material["emissive"]));
+			mat->set_parameter(SpatialMaterial::PARAM_EMISSION,_get_color(material["emissive"]));
 		}
 
 		if (material.has("shininess")) {
 			float exp = material["shininess"];
-			mat->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR_EXP,exp);
+			mat->set_parameter(SpatialMaterial::PARAM_SPECULAR_EXP,exp);
 		}
 
 		if (material.has("opacity")) {
-			Color c = mat->get_parameter(FixedSpatialMaterial::PARAM_DIFFUSE);
+			Color c = mat->get_parameter(SpatialMaterial::PARAM_DIFFUSE);
 			c.a=material["opacity"];
-			mat->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,c);
+			mat->set_parameter(SpatialMaterial::PARAM_DIFFUSE,c);
 		}
 
 
@@ -537,15 +537,15 @@ void EditorSceneImporterFBXConv::_parse_materials(State& state) {
 
 					String type=texture["type"];
 					if (type=="DIFFUSE")
-						mat->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,tex);
+						mat->set_texture(SpatialMaterial::PARAM_DIFFUSE,tex);
 					else if (type=="SPECULAR")
-						mat->set_texture(FixedSpatialMaterial::PARAM_SPECULAR,tex);
+						mat->set_texture(SpatialMaterial::PARAM_SPECULAR,tex);
 					else if (type=="SHININESS")
-						mat->set_texture(FixedSpatialMaterial::PARAM_SPECULAR_EXP,tex);
+						mat->set_texture(SpatialMaterial::PARAM_SPECULAR_EXP,tex);
 					else if (type=="NORMAL")
-						mat->set_texture(FixedSpatialMaterial::PARAM_NORMAL,tex);
+						mat->set_texture(SpatialMaterial::PARAM_NORMAL,tex);
 					else if (type=="EMISSIVE")
-						mat->set_texture(FixedSpatialMaterial::PARAM_EMISSION,tex);
+						mat->set_texture(SpatialMaterial::PARAM_EMISSION,tex);
 				}
 
 			}

+ 5 - 5
editor/plugins/baked_light_baker.cpp

@@ -144,18 +144,18 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
 
 				MeshMaterial mm;
 
-				Ref<FixedSpatialMaterial> fm = mat;
+				Ref<SpatialMaterial> fm = mat;
 				if (fm.is_valid()) {
 					//fixed route
-					mm.diffuse.color=fm->get_parameter(FixedSpatialMaterial::PARAM_DIFFUSE);
+					mm.diffuse.color=fm->get_parameter(SpatialMaterial::PARAM_DIFFUSE);
 					if (linear_color)
 						mm.diffuse.color=mm.diffuse.color.to_linear();
-					mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedSpatialMaterial::PARAM_DIFFUSE));
-					mm.specular.color=fm->get_parameter(FixedSpatialMaterial::PARAM_SPECULAR);
+					mm.diffuse.tex=_get_mat_tex(fm->get_texture(SpatialMaterial::PARAM_DIFFUSE));
+					mm.specular.color=fm->get_parameter(SpatialMaterial::PARAM_SPECULAR);
 					if (linear_color)
 						mm.specular.color=mm.specular.color.to_linear();
 
-					mm.specular.tex=_get_mat_tex(fm->get_texture(FixedSpatialMaterial::PARAM_SPECULAR));
+					mm.specular.tex=_get_mat_tex(fm->get_texture(SpatialMaterial::PARAM_SPECULAR));
 				} else {
 
 					mm.diffuse.color=Color(1,1,1,1);

+ 10 - 10
editor/plugins/collision_polygon_editor_plugin.cpp

@@ -571,25 +571,25 @@ CollisionPolygonEditor::CollisionPolygonEditor(EditorNode *p_editor) {
 	imgeom->set_transform(Transform(Matrix3(),Vector3(0,0,0.00001)));
 
 
-	line_material = Ref<FixedSpatialMaterial>( memnew( FixedSpatialMaterial ));
+	line_material = Ref<SpatialMaterial>( memnew( SpatialMaterial ));
 	line_material->set_flag(Material::FLAG_UNSHADED, true);
 	line_material->set_line_width(3.0);
-	line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true);
-	line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true);
-	line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1));
+	line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true);
+	line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true);
+	line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,Color(1,1,1));
 
 
 
 
-	handle_material = Ref<FixedSpatialMaterial>( memnew( FixedSpatialMaterial ));
+	handle_material = Ref<SpatialMaterial>( memnew( SpatialMaterial ));
 	handle_material->set_flag(Material::FLAG_UNSHADED, true);
-	handle_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_POINT_SIZE, true);
-	handle_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1));
-	handle_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true);
-	handle_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, false);
+	handle_material->set_fixed_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true);
+	handle_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,Color(1,1,1));
+	handle_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true);
+	handle_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, false);
 	Ref<Texture> handle=editor->get_gui_base()->get_icon("Editor3DHandle","EditorIcons");
 	handle_material->set_point_size(handle->get_width());
-	handle_material->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,handle);
+	handle_material->set_texture(SpatialMaterial::PARAM_DIFFUSE,handle);
 
 	pointsm = memnew( MeshInstance );
 	imgeom->add_child(pointsm);

+ 2 - 2
editor/plugins/collision_polygon_editor_plugin.h

@@ -62,8 +62,8 @@ class CollisionPolygonEditor : public HBoxContainer {
 	ToolButton *button_edit;
 
 
-	Ref<FixedSpatialMaterial> line_material;
-	Ref<FixedSpatialMaterial> handle_material;
+	Ref<SpatialMaterial> line_material;
+	Ref<SpatialMaterial> handle_material;
 
 	EditorNode *editor;
 	Panel *panel;

+ 519 - 0
editor/plugins/curve_editor_plugin.cpp

@@ -0,0 +1,519 @@
+#include "curve_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "os/keyboard.h"
+#include "spatial_editor_plugin.h"
+void CurveTextureEdit::_gui_input(const InputEvent &p_event) {
+
+	if (p_event.type == InputEvent::KEY && p_event.key.pressed && p_event.key.scancode == KEY_DELETE && grabbed != -1) {
+
+		points.remove(grabbed);
+		grabbed = -1;
+		update();
+		emit_signal("curve_changed");
+		accept_event();
+	}
+
+	if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == 1 && p_event.mouse_button.pressed) {
+
+		update();
+		Ref<Font> font = get_font("font", "Label");
+
+		int font_h = font->get_height();
+
+		Vector2 size = get_size();
+		size.y -= font_h;
+
+		Point2 p = Vector2(p_event.mouse_button.x, p_event.mouse_button.y) / size;
+		p.y = CLAMP(1.0 - p.y, 0, 1) * (max - min) + min;
+		grabbed = -1;
+		grabbing = true;
+
+		for (int i = 0; i < points.size(); i++) {
+
+			Vector2 ps = p * get_size();
+			Vector2 pt = Vector2(points[i].offset, points[i].height) * get_size();
+			if (ps.distance_to(pt) < 4) {
+				grabbed = i;
+			}
+		}
+
+		//grab or select
+		if (grabbed != -1) {
+			return;
+		}
+		//insert
+
+		Point np;
+		np.offset = p.x;
+		np.height = p.y;
+
+		points.push_back(np);
+		points.sort();
+		for (int i = 0; i < points.size(); i++) {
+			if (points[i].offset == p.x && points[i].height == p.y) {
+				grabbed = i;
+				break;
+			}
+		}
+
+		emit_signal("curve_changed");
+	}
+
+	if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == 1 && !p_event.mouse_button.pressed) {
+
+		if (grabbing) {
+			grabbing = false;
+			emit_signal("curve_changed");
+		}
+		update();
+	}
+
+	if (p_event.type == InputEvent::MOUSE_MOTION && grabbing && grabbed != -1) {
+
+		Ref<Font> font = get_font("font", "Label");
+		int font_h = font->get_height();
+		Vector2 size = get_size();
+		size.y -= font_h;
+
+		Point2 p = Vector2(p_event.mouse_motion.x, p_event.mouse_motion.y) / size;
+		p.y = CLAMP(1.0 - p.y, 0, 1) * (max - min) + min;
+		p.x = CLAMP(p.x, 0.0, 1.0);
+
+		bool valid = true;
+
+		for (int i = 0; i < points.size(); i++) {
+
+			if (points[i].offset == p.x && points[i].height == p.y && i != grabbed) {
+				valid = false;
+			}
+		}
+
+		if (!valid)
+			return;
+
+		points[grabbed].offset = p.x;
+		points[grabbed].height = p.y;
+
+		points.sort();
+		for (int i = 0; i < points.size(); i++) {
+			if (points[i].offset == p.x && points[i].height == p.y) {
+				grabbed = i;
+				break;
+			}
+		}
+
+		emit_signal("curve_changed");
+
+		update();
+	}
+}
+
+void CurveTextureEdit::_plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d) {
+
+	Ref<Font> font = get_font("font", "Label");
+
+	int font_h = font->get_height();
+
+	float geometry[4][4];
+	float tmp1[4][4];
+	float tmp2[4][4];
+	float deltas[4][4];
+	double x, dx, dx2, dx3;
+	double y, dy, dy2, dy3;
+	double d, d2, d3;
+	int lastx, lasty;
+	int newx, newy;
+	int ntimes;
+	int i, j;
+
+	int xmax = get_size().x;
+	int ymax = get_size().y - font_h;
+
+	int vsplits = 4;
+
+	int zero_ofs = (1.0 - (0.0 - min) / (max - min)) * ymax;
+
+	draw_line(Vector2(0, zero_ofs), Vector2(xmax, zero_ofs), Color(0.8, 0.8, 0.8, 0.15), 2.0);
+
+	for (int i = 0; i <= vsplits; i++) {
+		float fofs = float(i) / vsplits;
+		int yofs = fofs * ymax;
+		draw_line(Vector2(xmax, yofs), Vector2(xmax - 4, yofs), Color(0.8, 0.8, 0.8, 0.8), 2.0);
+
+		String text = rtos((1.0 - fofs) * (max - min) + min);
+		int ppos = text.find(".");
+		if (ppos != -1) {
+			if (text.length() > ppos + 2)
+				text = text.substr(0, ppos + 2);
+		}
+
+		int size = font->get_string_size(text).x;
+		int xofs = xmax - size - 4;
+		yofs -= font_h / 2;
+
+		if (yofs < 2) {
+			yofs = 2;
+		} else if (yofs + font_h > ymax - 2) {
+			yofs = ymax - font_h - 2;
+		}
+
+		draw_string(font, Vector2(xofs, yofs + font->get_ascent()), text, Color(0.8, 0.8, 0.8, 1));
+	}
+
+	/* construct the geometry matrix from the segment */
+	for (i = 0; i < 4; i++) {
+		geometry[i][2] = 0;
+		geometry[i][3] = 0;
+	}
+
+	geometry[0][0] = (p_a[0] * xmax);
+	geometry[1][0] = (p_b[0] * xmax);
+	geometry[2][0] = (p_c[0] * xmax);
+	geometry[3][0] = (p_d[0] * xmax);
+
+	geometry[0][1] = ((p_a[1] - min) / (max - min) * ymax);
+	geometry[1][1] = ((p_b[1] - min) / (max - min) * ymax);
+	geometry[2][1] = ((p_c[1] - min) / (max - min) * ymax);
+	geometry[3][1] = ((p_d[1] - min) / (max - min) * ymax);
+
+	/* subdivide the curve ntimes (1000) times */
+	ntimes = 4 * xmax;
+	/* ntimes can be adjusted to give a finer or coarser curve */
+	d = 1.0 / ntimes;
+	d2 = d * d;
+	d3 = d * d * d;
+
+	/* construct a temporary matrix for determining the forward differencing deltas */
+	tmp2[0][0] = 0;
+	tmp2[0][1] = 0;
+	tmp2[0][2] = 0;
+	tmp2[0][3] = 1;
+	tmp2[1][0] = d3;
+	tmp2[1][1] = d2;
+	tmp2[1][2] = d;
+	tmp2[1][3] = 0;
+	tmp2[2][0] = 6 * d3;
+	tmp2[2][1] = 2 * d2;
+	tmp2[2][2] = 0;
+	tmp2[2][3] = 0;
+	tmp2[3][0] = 6 * d3;
+	tmp2[3][1] = 0;
+	tmp2[3][2] = 0;
+	tmp2[3][3] = 0;
+
+	/* compose the basis and geometry matrices */
+
+	static const float CR_basis[4][4] = {
+		{ -0.5, 1.5, -1.5, 0.5 },
+		{ 1.0, -2.5, 2.0, -0.5 },
+		{ -0.5, 0.0, 0.5, 0.0 },
+		{ 0.0, 1.0, 0.0, 0.0 },
+	};
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
+						  CR_basis[i][1] * geometry[1][j] +
+						  CR_basis[i][2] * geometry[2][j] +
+						  CR_basis[i][3] * geometry[3][j]);
+		}
+	}
+	/* compose the above results to get the deltas matrix */
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
+							tmp2[i][1] * tmp1[1][j] +
+							tmp2[i][2] * tmp1[2][j] +
+							tmp2[i][3] * tmp1[3][j]);
+		}
+	}
+
+	/* extract the x deltas */
+	x = deltas[0][0];
+	dx = deltas[1][0];
+	dx2 = deltas[2][0];
+	dx3 = deltas[3][0];
+
+	/* extract the y deltas */
+	y = deltas[0][1];
+	dy = deltas[1][1];
+	dy2 = deltas[2][1];
+	dy3 = deltas[3][1];
+
+	lastx = CLAMP(x, 0, xmax);
+	lasty = CLAMP(y, 0, ymax);
+
+	/*	if (fix255)
+		{
+				cd->curve[cd->outline][lastx] = lasty;
+		}
+		else
+		{
+				cd->curve_ptr[cd->outline][lastx] = lasty;
+				if(gb_debug) printf("bender_plot_curve xmax:%d ymax:%d\n", (int)xmax, (int)ymax);
+		}
+*/
+	/* loop over the curve */
+	for (i = 0; i < ntimes; i++) {
+		/* increment the x values */
+		x += dx;
+		dx += dx2;
+		dx2 += dx3;
+
+		/* increment the y values */
+		y += dy;
+		dy += dy2;
+		dy2 += dy3;
+
+		newx = CLAMP((Math::round(x)), 0, xmax);
+		newy = CLAMP((Math::round(y)), 0, ymax);
+
+		/* if this point is different than the last one...then draw it */
+		if ((lastx != newx) || (lasty != newy)) {
+#if 0
+			if(fix255)
+			{
+				/* use fixed array size (for the curve graph) */
+				cd->curve[cd->outline][newx] = newy;
+			}
+			else
+			{
+				/* use dynamic allocated curve_ptr (for the real curve) */
+				cd->curve_ptr[cd->outline][newx] = newy;
+
+				if(gb_debug) printf("outline: %d  cX: %d cY: %d\n", (int)cd->outline, (int)newx, (int)newy);
+			}
+#endif
+			draw_line(Vector2(lastx, ymax - lasty), Vector2(newx, ymax - newy), Color(0.8, 0.8, 0.8, 0.8), 2.0);
+		}
+
+		lastx = newx;
+		lasty = newy;
+	}
+
+	int splits = 8;
+
+	draw_line(Vector2(0, ymax - 1), Vector2(xmax, ymax - 1), Color(0.8, 0.8, 0.8, 0.3), 2.0);
+
+	for (int i = 0; i <= splits; i++) {
+		float fofs = float(i) / splits;
+		draw_line(Vector2(fofs * xmax, ymax), Vector2(fofs * xmax, ymax - 2), Color(0.8, 0.8, 0.8, 0.8), 2.0);
+
+		String text = rtos(fofs);
+		int size = font->get_string_size(text).x;
+		int ofs = fofs * xmax - size * 0.5;
+		if (ofs < 2) {
+			ofs = 2;
+		} else if (ofs + size > xmax - 2) {
+			ofs = xmax - size - 2;
+		}
+
+		draw_string(font, Vector2(ofs, ymax + font->get_ascent()), text, Color(0.8, 0.8, 0.8, 1));
+	}
+}
+
+void CurveTextureEdit::_notification(int p_what) {
+
+	if (p_what == NOTIFICATION_DRAW) {
+
+		Ref<Font> font = get_font("font", "Label");
+
+		int font_h = font->get_height();
+
+		draw_style_box(get_stylebox("bg", "Tree"), Rect2(Point2(), get_size()));
+
+		int w = get_size().x;
+		int h = get_size().y;
+
+		Vector2 prev = Vector2(0, 0);
+		Vector2 prev2 = Vector2(0, 0);
+
+		for (int i = -1; i < points.size(); i++) {
+
+			Vector2 next;
+			Vector2 next2;
+			if (i + 1 >= points.size()) {
+				next = Vector2(1, 0);
+			} else {
+				next = Vector2(points[i + 1].offset, points[i + 1].height);
+			}
+
+			if (i + 2 >= points.size()) {
+				next2 = Vector2(1, 0);
+			} else {
+				next2 = Vector2(points[i + 2].offset, points[i + 2].height);
+			}
+
+			/*if (i==-1 && prev.offset==next.offset) {
+								prev=next;
+								continue;
+						}*/
+
+			_plot_curve(prev2, prev, next, next2);
+
+			prev2 = prev;
+			prev = next;
+		}
+
+		Vector2 size = get_size();
+		size.y -= font_h;
+		for (int i = 0; i < points.size(); i++) {
+
+			Color col = i == grabbed ? Color(1, 0.0, 0.0, 0.9) : Color(1, 1, 1, 0.8);
+
+			float h = (points[i].height - min) / (max - min);
+			draw_rect(Rect2(Vector2(points[i].offset, 1.0 - h) * size - Vector2(2, 2), Vector2(5, 5)), col);
+		}
+
+		/*		if (grabbed!=-1) {
+
+						draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color);
+				}
+*/
+		if (has_focus()) {
+
+			draw_line(Vector2(-1, -1), Vector2(w + 1, -1), Color(1, 1, 1, 0.6));
+			draw_line(Vector2(w + 1, -1), Vector2(w + 1, h + 1), Color(1, 1, 1, 0.6));
+			draw_line(Vector2(w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6));
+			draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6));
+		}
+	}
+}
+
+Size2 CurveTextureEdit::get_minimum_size() const {
+
+	return Vector2(64, 64);
+}
+
+void CurveTextureEdit::set_range(float p_min, float p_max) {
+	max = p_max;
+	min = p_min;
+	update();
+}
+
+void CurveTextureEdit::set_points(const Vector<Vector2> &p_points) {
+
+	points.clear();
+	for (int i = 0; i < p_points.size(); i++) {
+		Point p;
+		p.offset = p_points[i].x;
+		p.height = p_points[i].y;
+		points.push_back(p);
+	}
+
+	points.sort();
+	update();
+}
+
+Vector<Vector2> CurveTextureEdit::get_points() const {
+	Vector<Vector2> ret;
+	for (int i = 0; i < points.size(); i++)
+		ret.push_back(Vector2(points[i].offset, points[i].height));
+	return ret;
+}
+
+void CurveTextureEdit::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("_gui_input"), &CurveTextureEdit::_gui_input);
+
+	ADD_SIGNAL(MethodInfo("curve_changed"));
+}
+
+CurveTextureEdit::CurveTextureEdit() {
+
+	grabbed = -1;
+	grabbing = false;
+	max = 1;
+	min = 0;
+	set_focus_mode(FOCUS_ALL);
+}
+
+void CurveTextureEditorPlugin::_curve_settings_changed() {
+
+	if (!curve_texture_ref.is_valid())
+		return;
+	curve_editor->set_points(Variant(curve_texture_ref->get_points()));
+	curve_editor->set_range(curve_texture_ref->get_min(), curve_texture_ref->get_max());
+}
+
+CurveTextureEditorPlugin::CurveTextureEditorPlugin(EditorNode *p_node) {
+
+	editor = p_node;
+	curve_editor = memnew(CurveTextureEdit);
+
+	curve_button = editor->add_bottom_panel_item("CurveTexture", curve_editor);
+
+	curve_button->hide();
+	curve_editor->set_custom_minimum_size(Size2(100, 128 * EDSCALE));
+	curve_editor->hide();
+	curve_editor->connect("curve_changed", this, "curve_changed");
+}
+
+void CurveTextureEditorPlugin::edit(Object *p_object) {
+
+	if (curve_texture_ref.is_valid()) {
+		curve_texture_ref->disconnect("changed", this, "_curve_settings_changed");
+	}
+	CurveTexture *curve_texture = p_object->cast_to<CurveTexture>();
+	if (!curve_texture)
+		return;
+	curve_texture_ref = Ref<CurveTexture>(curve_texture);
+	curve_editor->set_points(Variant(curve_texture_ref->get_points()));
+	curve_editor->set_range(curve_texture_ref->get_min(), curve_texture_ref->get_max());
+	if (!curve_texture_ref->is_connected("changed", this, "_curve_settings_changed")) {
+		curve_texture_ref->connect("changed", this, "_curve_settings_changed");
+	}
+}
+
+bool CurveTextureEditorPlugin::handles(Object *p_object) const {
+
+	return p_object->is_class("CurveTexture");
+}
+
+void CurveTextureEditorPlugin::make_visible(bool p_visible) {
+
+	if (p_visible) {
+		curve_button->show();
+		editor->make_bottom_panel_item_visible(curve_editor);
+
+	} else {
+
+		curve_button->hide();
+		if (curve_editor->is_visible_in_tree())
+			editor->hide_bottom_panel();
+	}
+}
+
+void CurveTextureEditorPlugin::_curve_changed() {
+
+	if (curve_texture_ref.is_valid()) {
+
+		UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+		Vector<Vector2> points = curve_editor->get_points();
+		PoolVector<Vector2> ppoints = Variant(points);
+
+		ur->create_action(TTR("Modify Curve"), UndoRedo::MERGE_ENDS);
+		ur->add_do_method(this, "undo_redo_curve_texture", ppoints);
+		ur->add_undo_method(this, "undo_redo_curve_texture", curve_texture_ref->get_points());
+		ur->commit_action();
+	}
+}
+
+void CurveTextureEditorPlugin::_undo_redo_curve_texture(const PoolVector<Vector2> &points) {
+
+	curve_texture_ref->set_points(points);
+	curve_editor->set_points(Variant(curve_texture_ref->get_points()));
+	curve_editor->update();
+}
+
+CurveTextureEditorPlugin::~CurveTextureEditorPlugin() {
+}
+
+void CurveTextureEditorPlugin::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("curve_changed"), &CurveTextureEditorPlugin::_curve_changed);
+	ClassDB::bind_method(D_METHOD("_curve_settings_changed"), &CurveTextureEditorPlugin::_curve_settings_changed);
+	ClassDB::bind_method(D_METHOD("undo_redo_curve_texture", "points"), &CurveTextureEditorPlugin::_undo_redo_curve_texture);
+}

+ 66 - 0
editor/plugins/curve_editor_plugin.h

@@ -0,0 +1,66 @@
+#ifndef CURVE_EDITOR_PLUGIN_H
+#define CURVE_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+
+class CurveTextureEdit : public Control {
+
+	GDCLASS(CurveTextureEdit, Control);
+
+	struct Point {
+
+		float offset;
+		float height;
+		bool operator<(const Point &p_ponit) const {
+			return offset < p_ponit.offset;
+		}
+	};
+
+	bool grabbing;
+	int grabbed;
+	Vector<Point> points;
+	float max, min;
+
+	void _plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d);
+
+protected:
+	void _gui_input(const InputEvent &p_event);
+	void _notification(int p_what);
+	static void _bind_methods();
+
+public:
+	void set_range(float p_min, float p_max);
+	void set_points(const Vector<Vector2> &p_points);
+	Vector<Vector2> get_points() const;
+	virtual Size2 get_minimum_size() const;
+	CurveTextureEdit();
+};
+
+class CurveTextureEditorPlugin : public EditorPlugin {
+
+	GDCLASS(CurveTextureEditorPlugin, EditorPlugin);
+
+	CurveTextureEdit *curve_editor;
+	Ref<CurveTexture> curve_texture_ref;
+	EditorNode *editor;
+	ToolButton *curve_button;
+
+protected:
+	static void _bind_methods();
+	void _curve_changed();
+	void _undo_redo_curve_texture(const PoolVector<Vector2> &points);
+	void _curve_settings_changed();
+
+public:
+	virtual String get_name() const { return "CurveTexture"; }
+	bool has_main_screen() const { return false; }
+	virtual void edit(Object *p_node);
+	virtual bool handles(Object *p_node) const;
+	virtual void make_visible(bool p_visible);
+
+	CurveTextureEditorPlugin(EditorNode *p_node);
+	~CurveTextureEditorPlugin();
+};
+
+#endif // CURVE_EDITOR_PLUGIN_H

+ 504 - 0
editor/plugins/gradient_texture_editor_plugin.cpp

@@ -0,0 +1,504 @@
+#include "gradient_texture_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "spatial_editor_plugin.h"
+
+#include "os/keyboard.h"
+#include "scene/resources/default_theme/theme_data.h"
+#define POINT_WIDTH 8
+
+GradientTextureEdit::GradientTextureEdit() {
+	grabbed = -1;
+	grabbing = false;
+	set_focus_mode(FOCUS_ALL);
+
+	popup = memnew(PopupPanel);
+	picker = memnew(ColorPicker);
+	popup->add_child(picker);
+
+	add_child(popup);
+
+	checker = Ref<ImageTexture>(memnew(ImageTexture));
+	checker->create_from_image(Image(checker_bg_png), ImageTexture::FLAG_REPEAT);
+}
+
+int GradientTextureEdit::_get_point_from_pos(int x) {
+	int result = -1;
+	int total_w = get_size().width - get_size().height - 3;
+	for (int i = 0; i < points.size(); i++) {
+		//Check if we clicked at point
+		if (ABS(x - points[i].offset * total_w + 1) < (POINT_WIDTH / 2 + 1)) {
+			result = i;
+		}
+	}
+	return result;
+}
+
+void GradientTextureEdit::_show_color_picker() {
+	if (grabbed == -1)
+		return;
+	Size2 ms = Size2(350, picker->get_combined_minimum_size().height + 10);
+	picker->set_pick_color(points[grabbed].color);
+	popup->set_pos(get_global_pos() - Vector2(ms.width - get_size().width, ms.height));
+	popup->set_size(ms);
+	popup->popup();
+}
+
+GradientTextureEdit::~GradientTextureEdit() {
+}
+
+void GradientTextureEdit::_gui_input(const InputEvent &p_event) {
+
+	if (p_event.type == InputEvent::KEY && p_event.key.pressed && p_event.key.scancode == KEY_DELETE && grabbed != -1) {
+
+		points.remove(grabbed);
+		grabbed = -1;
+		grabbing = false;
+		update();
+		emit_signal("ramp_changed");
+		accept_event();
+	}
+
+	//Show color picker on double click.
+	if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == 1 && p_event.mouse_button.doubleclick && p_event.mouse_button.pressed) {
+		grabbed = _get_point_from_pos(p_event.mouse_button.x);
+		_show_color_picker();
+		accept_event();
+	}
+
+	//Delete point on right click
+	if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == 2 && p_event.mouse_button.pressed) {
+		grabbed = _get_point_from_pos(p_event.mouse_button.x);
+		if (grabbed != -1) {
+			points.remove(grabbed);
+			grabbed = -1;
+			grabbing = false;
+			update();
+			emit_signal("ramp_changed");
+			accept_event();
+		}
+	}
+
+	//Hold alt key to duplicate selected color
+	if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == 1 && p_event.mouse_button.pressed && p_event.key.mod.alt) {
+
+		int x = p_event.mouse_button.x;
+		grabbed = _get_point_from_pos(x);
+
+		if (grabbed != -1) {
+			int total_w = get_size().width - get_size().height - 3;
+			GradientTexture::Point newPoint = points[grabbed];
+			newPoint.offset = CLAMP(x / float(total_w), 0, 1);
+
+			points.push_back(newPoint);
+			points.sort();
+			for (int i = 0; i < points.size(); ++i) {
+				if (points[i].offset == newPoint.offset) {
+					grabbed = i;
+					break;
+				}
+			}
+
+			emit_signal("ramp_changed");
+			update();
+		}
+	}
+
+	if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == 1 && p_event.mouse_button.pressed) {
+
+		update();
+		int x = p_event.mouse_button.x;
+		int total_w = get_size().width - get_size().height - 3;
+
+		//Check if color selector was clicked.
+		if (x > total_w + 3) {
+			_show_color_picker();
+			return;
+		}
+
+		grabbing = true;
+
+		grabbed = _get_point_from_pos(x);
+		//grab or select
+		if (grabbed != -1) {
+			return;
+		}
+
+		//insert
+		GradientTexture::Point newPoint;
+		newPoint.offset = CLAMP(x / float(total_w), 0, 1);
+
+		GradientTexture::Point prev;
+		GradientTexture::Point next;
+
+		int pos = -1;
+		for (int i = 0; i < points.size(); i++) {
+			if (points[i].offset < newPoint.offset)
+				pos = i;
+		}
+
+		if (pos == -1) {
+
+			prev.color = Color(0, 0, 0);
+			prev.offset = 0;
+			if (points.size()) {
+				next = points[0];
+			} else {
+				next.color = Color(1, 1, 1);
+				next.offset = 1.0;
+			}
+		} else {
+
+			if (pos == points.size() - 1) {
+				next.color = Color(1, 1, 1);
+				next.offset = 1.0;
+			} else {
+				next = points[pos + 1];
+			}
+			prev = points[pos];
+		}
+
+		newPoint.color = prev.color.linear_interpolate(next.color, (newPoint.offset - prev.offset) / (next.offset - prev.offset));
+
+		points.push_back(newPoint);
+		points.sort();
+		for (int i = 0; i < points.size(); i++) {
+			if (points[i].offset == newPoint.offset) {
+				grabbed = i;
+				break;
+			}
+		}
+
+		emit_signal("ramp_changed");
+	}
+
+	if (p_event.type == InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index == 1 && !p_event.mouse_button.pressed) {
+
+		if (grabbing) {
+			grabbing = false;
+			emit_signal("ramp_changed");
+		}
+		update();
+	}
+
+	if (p_event.type == InputEvent::MOUSE_MOTION && grabbing) {
+
+		int total_w = get_size().width - get_size().height - 3;
+
+		int x = p_event.mouse_motion.x;
+		float newofs = CLAMP(x / float(total_w), 0, 1);
+
+		//Snap to nearest point if holding shift
+		if (p_event.key.mod.shift) {
+			float snap_treshhold = 0.03;
+			float smallest_ofs = snap_treshhold;
+			bool founded = false;
+			int nearest_point;
+			for (int i = 0; i < points.size(); ++i) {
+				if (i != grabbed) {
+					float temp_ofs = ABS(points[i].offset - newofs);
+					if (temp_ofs < smallest_ofs) {
+						smallest_ofs = temp_ofs;
+						nearest_point = i;
+						if (founded)
+							break;
+						founded = true;
+					}
+				}
+			}
+			if (founded) {
+				if (points[nearest_point].offset < newofs)
+					newofs = points[nearest_point].offset + 0.00001;
+				else
+					newofs = points[nearest_point].offset - 0.00001;
+				newofs = CLAMP(newofs, 0, 1);
+			}
+		}
+
+		bool valid = true;
+		for (int i = 0; i < points.size(); i++) {
+
+			if (points[i].offset == newofs && i != grabbed) {
+				valid = false;
+			}
+		}
+
+		if (!valid)
+			return;
+
+		points[grabbed].offset = newofs;
+
+		points.sort();
+		for (int i = 0; i < points.size(); i++) {
+			if (points[i].offset == newofs) {
+				grabbed = i;
+				break;
+			}
+		}
+
+		emit_signal("ramp_changed");
+
+		update();
+	}
+}
+
+void GradientTextureEdit::_notification(int p_what) {
+
+	if (p_what == NOTIFICATION_ENTER_TREE) {
+		if (!picker->is_connected("color_changed", this, "_color_changed")) {
+			picker->connect("color_changed", this, "_color_changed");
+		}
+	}
+	if (p_what == NOTIFICATION_DRAW) {
+
+		int w = get_size().x;
+		int h = get_size().y;
+
+		if (w == 0 || h == 0)
+			return; //Safety check. We have division by 'h'. And in any case there is nothing to draw with such size
+
+		int total_w = get_size().width - get_size().height - 3;
+
+		//Draw checker pattern for ramp
+		_draw_checker(0, 0, total_w, h);
+
+		//Draw color ramp
+		GradientTexture::Point prev;
+		prev.offset = 0;
+		if (points.size() == 0)
+			prev.color = Color(0, 0, 0); //Draw black rectangle if we have no points
+		else
+			prev.color = points[0].color; //Extend color of first point to the beginning.
+
+		for (int i = -1; i < points.size(); i++) {
+
+			GradientTexture::Point next;
+			//If there is no next point
+			if (i + 1 == points.size()) {
+				if (points.size() == 0)
+					next.color = Color(0, 0, 0); //Draw black rectangle if we have no points
+				else
+					next.color = points[i].color; //Extend color of last point to the end.
+				next.offset = 1;
+			} else {
+				next = points[i + 1];
+			}
+
+			if (prev.offset == next.offset) {
+				prev = next;
+				continue;
+			}
+
+			Vector<Vector2> points;
+			Vector<Color> colors;
+			points.push_back(Vector2(prev.offset * total_w, h));
+			points.push_back(Vector2(prev.offset * total_w, 0));
+			points.push_back(Vector2(next.offset * total_w, 0));
+			points.push_back(Vector2(next.offset * total_w, h));
+			colors.push_back(prev.color);
+			colors.push_back(prev.color);
+			colors.push_back(next.color);
+			colors.push_back(next.color);
+			draw_primitive(points, colors, Vector<Point2>());
+			prev = next;
+		}
+
+		//Draw point markers
+		for (int i = 0; i < points.size(); i++) {
+
+			Color col = i == grabbed ? Color(1, 0.0, 0.0, 0.9) : points[i].color.contrasted();
+			col.a = 0.9;
+
+			draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col);
+			draw_rect(Rect2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2, POINT_WIDTH, h / 2), Color(0.6, 0.6, 0.6, i == grabbed ? 0.9 : 0.4));
+			draw_line(Vector2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2), Vector2(points[i].offset * total_w - POINT_WIDTH / 2, h - 1), col);
+			draw_line(Vector2(points[i].offset * total_w + POINT_WIDTH / 2, h / 2), Vector2(points[i].offset * total_w + POINT_WIDTH / 2, h - 1), col);
+			draw_line(Vector2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2), Vector2(points[i].offset * total_w + POINT_WIDTH / 2, h / 2), col);
+			draw_line(Vector2(points[i].offset * total_w - POINT_WIDTH / 2, h - 1), Vector2(points[i].offset * total_w + POINT_WIDTH / 2, h - 1), col);
+		}
+
+		//Draw "button" for color selector
+		_draw_checker(total_w + 3, 0, h, h);
+		if (grabbed != -1) {
+			//Draw with selection color
+			draw_rect(Rect2(total_w + 3, 0, h, h), points[grabbed].color);
+		} else {
+			//if no color selected draw grey color with 'X' on top.
+			draw_rect(Rect2(total_w + 3, 0, h, h), Color(0.5, 0.5, 0.5, 1));
+			draw_line(Vector2(total_w + 3, 0), Vector2(total_w + 3 + h, h), Color(1, 1, 1, 0.6));
+			draw_line(Vector2(total_w + 3, h), Vector2(total_w + 3 + h, 0), Color(1, 1, 1, 0.6));
+		}
+
+		//Draw borders around color ramp if in focus
+		if (has_focus()) {
+
+			draw_line(Vector2(-1, -1), Vector2(total_w + 1, -1), Color(1, 1, 1, 0.6));
+			draw_line(Vector2(total_w + 1, -1), Vector2(total_w + 1, h + 1), Color(1, 1, 1, 0.6));
+			draw_line(Vector2(total_w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6));
+			draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6));
+		}
+	}
+}
+
+void GradientTextureEdit::_draw_checker(int x, int y, int w, int h) {
+	//Draw it with polygon to insert UVs for scale
+	Vector<Vector2> backPoints;
+	backPoints.push_back(Vector2(x, y));
+	backPoints.push_back(Vector2(x, y + h));
+	backPoints.push_back(Vector2(x + w, y + h));
+	backPoints.push_back(Vector2(x + w, y));
+	Vector<Color> colorPoints;
+	colorPoints.push_back(Color(1, 1, 1, 1));
+	colorPoints.push_back(Color(1, 1, 1, 1));
+	colorPoints.push_back(Color(1, 1, 1, 1));
+	colorPoints.push_back(Color(1, 1, 1, 1));
+	Vector<Vector2> uvPoints;
+	//Draw checker pattern pixel-perfect and scale it by 2.
+	uvPoints.push_back(Vector2(x, y));
+	uvPoints.push_back(Vector2(x, y + h * .5f / checker->get_height()));
+	uvPoints.push_back(Vector2(x + w * .5f / checker->get_width(), y + h * .5f / checker->get_height()));
+	uvPoints.push_back(Vector2(x + w * .5f / checker->get_width(), y));
+	draw_polygon(backPoints, colorPoints, uvPoints, checker);
+}
+
+Size2 GradientTextureEdit::get_minimum_size() const {
+
+	return Vector2(0, 16);
+}
+
+void GradientTextureEdit::_color_changed(const Color &p_color) {
+
+	if (grabbed == -1)
+		return;
+	points[grabbed].color = p_color;
+	update();
+	emit_signal("ramp_changed");
+}
+
+void GradientTextureEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) {
+
+	ERR_FAIL_COND(p_offsets.size() != p_colors.size());
+	points.clear();
+	for (int i = 0; i < p_offsets.size(); i++) {
+		GradientTexture::Point p;
+		p.offset = p_offsets[i];
+		p.color = p_colors[i];
+		points.push_back(p);
+	}
+
+	points.sort();
+	update();
+}
+
+Vector<float> GradientTextureEdit::get_offsets() const {
+	Vector<float> ret;
+	for (int i = 0; i < points.size(); i++)
+		ret.push_back(points[i].offset);
+	return ret;
+}
+
+Vector<Color> GradientTextureEdit::get_colors() const {
+	Vector<Color> ret;
+	for (int i = 0; i < points.size(); i++)
+		ret.push_back(points[i].color);
+	return ret;
+}
+
+void GradientTextureEdit::set_points(Vector<GradientTexture::Point> &p_points) {
+	if (points.size() != p_points.size())
+		grabbed = -1;
+	points.clear();
+	points = p_points;
+}
+
+Vector<GradientTexture::Point> &GradientTextureEdit::get_points() {
+	return points;
+}
+
+void GradientTextureEdit::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("_gui_input"), &GradientTextureEdit::_gui_input);
+	ClassDB::bind_method(D_METHOD("_color_changed"), &GradientTextureEdit::_color_changed);
+	ADD_SIGNAL(MethodInfo("ramp_changed"));
+}
+
+GradientTextureEditorPlugin::GradientTextureEditorPlugin(EditorNode *p_node) {
+
+	editor = p_node;
+	ramp_editor = memnew(GradientTextureEdit);
+
+	gradient_button = editor->add_bottom_panel_item("GradientTexture", ramp_editor);
+
+	gradient_button->hide();
+	ramp_editor->set_custom_minimum_size(Size2(100, 100 * EDSCALE));
+	ramp_editor->hide();
+	ramp_editor->connect("ramp_changed", this, "ramp_changed");
+}
+
+void GradientTextureEditorPlugin::edit(Object *p_object) {
+
+	GradientTexture *gradient_texture = p_object->cast_to<GradientTexture>();
+	if (!gradient_texture)
+		return;
+	gradient_texture_ref = Ref<GradientTexture>(gradient_texture);
+	ramp_editor->set_points(gradient_texture_ref->get_points());
+}
+
+bool GradientTextureEditorPlugin::handles(Object *p_object) const {
+
+	return p_object->is_class("GradientTexture");
+}
+
+void GradientTextureEditorPlugin::make_visible(bool p_visible) {
+
+	if (p_visible) {
+		gradient_button->show();
+		editor->make_bottom_panel_item_visible(ramp_editor);
+
+	} else {
+
+		gradient_button->hide();
+		if (ramp_editor->is_visible_in_tree())
+			editor->hide_bottom_panel();
+	}
+}
+
+void GradientTextureEditorPlugin::_ramp_changed() {
+
+	if (gradient_texture_ref.is_valid()) {
+
+		UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+		//Not sure if I should convert this data to PoolVector
+		Vector<float> new_offsets = ramp_editor->get_offsets();
+		Vector<Color> new_colors = ramp_editor->get_colors();
+		Vector<float> old_offsets = gradient_texture_ref->get_offsets();
+		Vector<Color> old_colors = gradient_texture_ref->get_colors();
+
+		if (old_offsets.size() != new_offsets.size())
+			ur->create_action(TTR("Add/Remove Color Ramp Point"));
+		else
+			ur->create_action(TTR("Modify Color Ramp"), UndoRedo::MERGE_ENDS);
+		ur->add_do_method(this, "undo_redo_gradient_texture", new_offsets, new_colors);
+		ur->add_undo_method(this, "undo_redo_gradient_texture", old_offsets, old_colors);
+		ur->commit_action();
+
+		//gradient_texture_ref->set_points(ramp_editor->get_points());
+	}
+}
+
+void GradientTextureEditorPlugin::_undo_redo_gradient_texture(const Vector<float> &offsets,
+		const Vector<Color> &colors) {
+
+	gradient_texture_ref->set_offsets(offsets);
+	gradient_texture_ref->set_colors(colors);
+	ramp_editor->set_points(gradient_texture_ref->get_points());
+	ramp_editor->update();
+}
+
+GradientTextureEditorPlugin::~GradientTextureEditorPlugin() {
+}
+
+void GradientTextureEditorPlugin::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("ramp_changed"), &GradientTextureEditorPlugin::_ramp_changed);
+	ClassDB::bind_method(D_METHOD("undo_redo_gradient_texture", "offsets", "colors"), &GradientTextureEditorPlugin::_undo_redo_gradient_texture);
+}

+ 69 - 0
editor/plugins/gradient_texture_editor_plugin.h

@@ -0,0 +1,69 @@
+#ifndef GRADIENT_TEXTURE_EDITOR_PLUGIN_H
+#define GRADIENT_TEXTURE_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/resources/texture.h"
+
+class GradientTextureEdit : public Control {
+
+	GDCLASS(GradientTextureEdit, Control);
+
+	PopupPanel *popup;
+	ColorPicker *picker;
+
+	Ref<ImageTexture> checker;
+
+	bool grabbing;
+	int grabbed;
+	Vector<GradientTexture::Point> points;
+
+	void _draw_checker(int x, int y, int w, int h);
+	void _color_changed(const Color &p_color);
+	int _get_point_from_pos(int x);
+	void _show_color_picker();
+
+protected:
+	void _gui_input(const InputEvent &p_event);
+	void _notification(int p_what);
+	static void _bind_methods();
+
+public:
+	void set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors);
+	Vector<float> get_offsets() const;
+	Vector<Color> get_colors() const;
+	void set_points(Vector<GradientTexture::Point> &p_points);
+	Vector<GradientTexture::Point> &get_points();
+	virtual Size2 get_minimum_size() const;
+
+	GradientTextureEdit();
+	virtual ~GradientTextureEdit();
+};
+
+class GradientTextureEditorPlugin : public EditorPlugin {
+
+	GDCLASS(GradientTextureEditorPlugin, EditorPlugin);
+
+	bool _2d;
+	Ref<GradientTexture> gradient_texture_ref;
+	GradientTextureEdit *ramp_editor;
+	EditorNode *editor;
+	ToolButton *gradient_button;
+
+protected:
+	static void _bind_methods();
+	void _ramp_changed();
+	void _undo_redo_gradient_texture(const Vector<float> &offsets, const Vector<Color> &colors);
+
+public:
+	virtual String get_name() const { return "GradientTexture"; }
+	bool has_main_screen() const { return false; }
+	virtual void edit(Object *p_node);
+	virtual bool handles(Object *p_node) const;
+	virtual void make_visible(bool p_visible);
+
+	GradientTextureEditorPlugin(EditorNode *p_node);
+	~GradientTextureEditorPlugin();
+};
+
+#endif // GRADIENT_TEXTURE_EDITOR_PLUGIN_H

+ 193 - 159
editor/plugins/particles_editor_plugin.cpp

@@ -27,30 +27,24 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#if 0
 #include "particles_editor_plugin.h"
 #include "editor/plugins/spatial_editor_plugin.h"
 #include "io/resource_loader.h"
-#include "servers/visual/particle_system_sw.h"
-
 
 void ParticlesEditor::_node_removed(Node *p_node) {
 
-	if(p_node==node) {
-		node=NULL;
+	if (p_node == node) {
+		node = NULL;
 		hide();
 	}
-
 }
 
-
-void ParticlesEditor::_resource_seleted(const String& p_res) {
+void ParticlesEditor::_resource_seleted(const String &p_res) {
 
 	//print_line("selected resource path: "+p_res);
 }
 
-void ParticlesEditor::_node_selected(const NodePath& p_path){
-
+void ParticlesEditor::_node_selected(const NodePath &p_path) {
 
 	Node *sel = get_node(p_path);
 	if (!sel)
@@ -66,12 +60,11 @@ void ParticlesEditor::_node_selected(const NodePath& p_path){
 
 	geometry = vi->get_faces(VisualInstance::FACES_SOLID);
 
-	if (geometry.size()==0) {
+	if (geometry.size() == 0) {
 
 		err_dialog->set_text(TTR("Node does not contain geometry (faces)."));
 		err_dialog->popup_centered_minsize();
 		return;
-
 	}
 
 	Transform geom_xform = node->get_global_transform().affine_inverse() * vi->get_global_transform();
@@ -79,20 +72,17 @@ void ParticlesEditor::_node_selected(const NodePath& p_path){
 	int gc = geometry.size();
 	PoolVector<Face3>::Write w = geometry.write();
 
-
-	for(int i=0;i<gc;i++) {
-		for(int j=0;j<3;j++) {
-			w[i].vertex[j] = geom_xform.xform( w[i].vertex[j] );
+	for (int i = 0; i < gc; i++) {
+		for (int j = 0; j < 3; j++) {
+			w[i].vertex[j] = geom_xform.xform(w[i].vertex[j]);
 		}
 	}
 
-
 	w = PoolVector<Face3>::Write();
 
-	emission_dialog->popup_centered(Size2(300,130));
+	emission_dialog->popup_centered(Size2(300, 130));
 }
 
-
 /*
 
 void ParticlesEditor::_populate() {
@@ -112,74 +102,77 @@ void ParticlesEditor::_populate() {
 
 void ParticlesEditor::_notification(int p_notification) {
 
-	if (p_notification==NOTIFICATION_ENTER_TREE) {
-		options->set_icon(options->get_popup()->get_icon("Particles","EditorIcons"));
-
+	if (p_notification == NOTIFICATION_ENTER_TREE) {
+		options->set_icon(options->get_popup()->get_icon("Particles", "EditorIcons"));
 	}
 }
 
-
 void ParticlesEditor::_menu_option(int p_option) {
 
-
-	switch(p_option) {
+	switch (p_option) {
 
 		case MENU_OPTION_GENERATE_AABB: {
-
+#if 0
 			Transform globalizer = node->get_global_transform();
 			ParticleSystemSW pssw;
-			for(int i=0;i<VS::PARTICLE_VAR_MAX;i++) {
+			for (int i = 0; i < VS::PARTICLE_VAR_MAX; i++) {
 
-				pssw.particle_vars[i]=node->get_variable((Particles::Variable)i);
-				pssw.particle_randomness[i]=node->get_randomness((Particles::Variable)i);
+				pssw.particle_vars[i] = node->get_variable((Particles::Variable)i);
+				pssw.particle_randomness[i] = node->get_randomness((Particles::Variable)i);
 			}
 
-			pssw.emission_half_extents=node->get_emission_half_extents();
-			pssw.emission_points=node->get_emission_points();
-			pssw.emission_base_velocity=node->get_emission_base_velocity();
-			pssw.amount=node->get_amount();
-			pssw.gravity_normal=node->get_gravity_normal();
-			pssw.emitting=true;
-			pssw.height_from_velocity=node->has_height_from_velocity();
-			pssw.color_phase_count=1;
-
+			pssw.emission_half_extents = node->get_emission_half_extents();
+			pssw.emission_points = node->get_emission_points();
+			pssw.emission_base_velocity = node->get_emission_base_velocity();
+			pssw.amount = node->get_amount();
+			pssw.gravity_normal = node->get_gravity_normal();
+			pssw.emitting = true;
+			pssw.height_from_velocity = node->has_height_from_velocity();
+			pssw.color_phase_count = 1;
 
 			ParticleSystemProcessSW pp;
-			float delta=0.01;
-			float lifetime=pssw.particle_vars[VS::PARTICLE_LIFETIME];
-
+			float delta = 0.01;
+			float lifetime = pssw.particle_vars[VS::PARTICLE_LIFETIME];
 
 			Transform localizer = globalizer.affine_inverse();
 			AABB aabb;
-			for(float t=0;t<lifetime;t+=delta) {
+			for (float t = 0; t < lifetime; t += delta) {
 
-				pp.process(&pssw,globalizer,delta);
-				for(int i=0;i<pp.particle_data.size();i++) {
+				pp.process(&pssw, globalizer, delta);
+				for (int i = 0; i < pp.particle_data.size(); i++) {
 
 					Vector3 p = localizer.xform(pp.particle_data[i].pos);
 
-					if (t==0 && i==0)
-						aabb.pos=p;
+					if (t == 0 && i == 0)
+						aabb.pos = p;
 					else
 						aabb.expand_to(p);
 				}
 			}
 
-			aabb.grow_by( aabb.get_longest_axis_size()*0.2);
+			aabb.grow_by(aabb.get_longest_axis_size() * 0.2);
 
 			node->set_visibility_aabb(aabb);
-
-
+#endif
 		} break;
 		case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: {
 
-
+			Ref<ParticlesMaterial> material = node->get_process_material();
+			if (material.is_null()) {
+				EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
+				return;
+			}
 			emission_file_dialog->popup_centered_ratio();
 
 		} break;
 
 		case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
-/*
+			Ref<ParticlesMaterial> material = node->get_process_material();
+			if (material.is_null()) {
+				EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
+				return;
+			}
+			/*
 			Node *root = get_scene()->get_root_node();
 			ERR_FAIL_COND(!root);
 			EditorNode *en = root->cast_to<EditorNode>();
@@ -192,50 +185,50 @@ void ParticlesEditor::_menu_option(int p_option) {
 	}
 }
 
-
 void ParticlesEditor::edit(Particles *p_particles) {
 
-	node=p_particles;
-
+	node = p_particles;
 }
 
 void ParticlesEditor::_generate_emission_points() {
 
 	/// hacer codigo aca
-	PoolVector<Vector3> points;
+	PoolVector<float> points;
+	bool use_normals = emission_fill->get_selected() == 1;
+	PoolVector<float> normals;
 
-	if (emission_fill->get_selected()==0) {
+	if (emission_fill->get_selected() < 2) {
 
-		float area_accum=0;
-		Map<float,int> triangle_area_map;
-		print_line("geometry size: "+itos(geometry.size()));
+		float area_accum = 0;
+		Map<float, int> triangle_area_map;
+		print_line("geometry size: " + itos(geometry.size()));
 
-		for(int i=0;i<geometry.size();i++) {
+		for (int i = 0; i < geometry.size(); i++) {
 
 			float area = geometry[i].get_area();
-			if (area<CMP_EPSILON)
+			if (area < CMP_EPSILON)
 				continue;
-			triangle_area_map[area_accum]=i;
-			area_accum+=area;
+			triangle_area_map[area_accum] = i;
+			area_accum += area;
 		}
 
-		if (!triangle_area_map.size() || area_accum==0) {
+		if (!triangle_area_map.size() || area_accum == 0) {
 
 			err_dialog->set_text(TTR("Faces contain no area!"));
 			err_dialog->popup_centered_minsize();
 			return;
 		}
 
-		int emissor_count=emission_amount->get_val();
+		int emissor_count = emission_amount->get_value();
 
-		for(int i=0;i<emissor_count;i++) {
+		for (int i = 0; i < emissor_count; i++) {
 
-			float areapos = Math::random(0,area_accum);
+			float areapos = Math::random(0.0f, area_accum);
 
-			Map<float,int>::Element *E = triangle_area_map.find_closest(areapos);
+			Map<float, int>::Element *E = triangle_area_map.find_closest(areapos);
 			ERR_FAIL_COND(!E)
 			int index = E->get();
-			ERR_FAIL_INDEX(index,geometry.size());
+			ERR_FAIL_INDEX(index, geometry.size());
 
 			// ok FINALLY get face
 			Face3 face = geometry[index];
@@ -243,13 +236,22 @@ void ParticlesEditor::_generate_emission_points() {
 
 			Vector3 pos = face.get_random_point_inside();
 
-			points.push_back(pos);
+			points.push_back(pos.x);
+			points.push_back(pos.y);
+			points.push_back(pos.z);
+
+			if (use_normals) {
+				Vector3 normal = face.get_plane().normal;
+				normals.push_back(normal.x);
+				normals.push_back(normal.y);
+				normals.push_back(normal.z);
+			}
 		}
 	} else {
 
 		int gcount = geometry.size();
 
-		if (gcount==0) {
+		if (gcount == 0) {
 
 			err_dialog->set_text(TTR("No faces!"));
 			err_dialog->popup_centered_minsize();
@@ -258,32 +260,32 @@ void ParticlesEditor::_generate_emission_points() {
 
 		PoolVector<Face3>::Read r = geometry.read();
 
-		AABB aabb;
+		Rect3 aabb;
 
-		for(int i=0;i<gcount;i++) {
+		for (int i = 0; i < gcount; i++) {
 
-			for(int j=0;j<3;j++) {
+			for (int j = 0; j < 3; j++) {
 
-				if (i==0 && j==0)
-					aabb.pos=r[i].vertex[j];
+				if (i == 0 && j == 0)
+					aabb.pos = r[i].vertex[j];
 				else
 					aabb.expand_to(r[i].vertex[j]);
 			}
 		}
 
-		int emissor_count=emission_amount->get_val();
+		int emissor_count = emission_amount->get_value();
 
-		for(int i=0;i<emissor_count;i++) {
+		for (int i = 0; i < emissor_count; i++) {
 
-			int attempts=5;
+			int attempts = 5;
 
-			for(int j=0;j<attempts;j++) {
+			for (int j = 0; j < attempts; j++) {
 
 				Vector3 dir;
-				dir[Math::rand()%3]=1.0;
-				Vector3 ofs = Vector3(1,1,1)-dir;
-				ofs=(Vector3(1,1,1)-dir)*Vector3(Math::randf(),Math::randf(),Math::randf())*aabb.size;
-				ofs+=aabb.pos;
+				dir[Math::rand() % 3] = 1.0;
+				Vector3 ofs = Vector3(1, 1, 1) - dir;
+				ofs = (Vector3(1, 1, 1) - dir) * Vector3(Math::randf(), Math::randf(), Math::randf()) * aabb.size;
+				ofs += aabb.pos;
 
 				Vector3 ofsv = ofs + aabb.size * dir;
 
@@ -291,135 +293,172 @@ void ParticlesEditor::_generate_emission_points() {
 				ofs -= dir;
 				ofsv += dir;
 
-				float max=-1e7,min=1e7;
+				float max = -1e7, min = 1e7;
 
-				for(int k=0;k<gcount;k++) {
+				for (int k = 0; k < gcount; k++) {
 
-					const Face3& f3 = r[k];
+					const Face3 &f3 = r[k];
 
 					Vector3 res;
-					if (f3.intersects_segment(ofs,ofsv,&res)) {
+					if (f3.intersects_segment(ofs, ofsv, &res)) {
 
-						res-=ofs;
+						res -= ofs;
 						float d = dir.dot(res);
 
-						if (d<min)
-							min=d;
-						if (d>max)
-							max=d;
-
+						if (d < min)
+							min = d;
+						if (d > max)
+							max = d;
 					}
 				}
 
-
-				if (max<min)
+				if (max < min)
 					continue; //lost attempt
 
-				float val = min + (max-min)*Math::randf();
+				float val = min + (max - min) * Math::randf();
 
 				Vector3 point = ofs + dir * val;
 
-				points.push_back(point);
+				points.push_back(point.x);
+				points.push_back(point.y);
+				points.push_back(point.z);
 				break;
 			}
 		}
 	}
 
-	//print_line("point count: "+itos(points.size()));
-	node->set_emission_points(points);
+	int point_count = points.size() / 3;
+
+	int w = 2048;
+	int h = (point_count / 2048) + 1;
 
+	PoolVector<uint8_t> point_img;
+	point_img.resize(w * h * 3 * sizeof(float));
+
+	{
+		PoolVector<uint8_t>::Write iw = point_img.write();
+		zeromem(iw.ptr(), w * h * 3 * sizeof(float));
+		PoolVector<float>::Read r = points.read();
+		copymem(iw.ptr(), r.ptr(), point_count * sizeof(float) * 3);
+	}
+
+	Image image(w, h, false, Image::FORMAT_RGBF, point_img);
+
+	Ref<ImageTexture> tex;
+	tex.instance();
+	tex->create_from_image(image, Texture::FLAG_FILTER);
+
+	Ref<ParticlesMaterial> material = node->get_process_material();
+	ERR_FAIL_COND(material.is_null());
+
+	if (use_normals) {
+
+		material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
+		material->set_emission_point_count(point_count);
+		material->set_emission_point_texture(tex);
+
+		PoolVector<uint8_t> point_img2;
+		point_img2.resize(w * h * 3 * sizeof(float));
+
+		{
+			PoolVector<uint8_t>::Write iw = point_img2.write();
+			zeromem(iw.ptr(), w * h * 3 * sizeof(float));
+			PoolVector<float>::Read r = normals.read();
+			copymem(iw.ptr(), r.ptr(), point_count * sizeof(float) * 3);
+		}
+
+		Image image2(w, h, false, Image::FORMAT_RGBF, point_img2);
+
+		Ref<ImageTexture> tex2;
+		tex2.instance();
+		tex2->create_from_image(image2, Texture::FLAG_FILTER);
+
+		material->set_emission_normal_texture(tex2);
+	} else {
+
+		material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
+		material->set_emission_point_count(point_count);
+		material->set_emission_point_texture(tex);
+	}
+
+	//print_line("point count: "+itos(points.size()));
+	//node->set_emission_points(points);
 }
 
 void ParticlesEditor::_bind_methods() {
 
-	ClassDB::bind_method("_menu_option",&ParticlesEditor::_menu_option);
-	ClassDB::bind_method("_resource_seleted",&ParticlesEditor::_resource_seleted);
-	ClassDB::bind_method("_node_selected",&ParticlesEditor::_node_selected);
-	ClassDB::bind_method("_generate_emission_points",&ParticlesEditor::_generate_emission_points);
+	ClassDB::bind_method("_menu_option", &ParticlesEditor::_menu_option);
+	ClassDB::bind_method("_resource_seleted", &ParticlesEditor::_resource_seleted);
+	ClassDB::bind_method("_node_selected", &ParticlesEditor::_node_selected);
+	ClassDB::bind_method("_generate_emission_points", &ParticlesEditor::_generate_emission_points);
 
 	//ClassDB::bind_method("_populate",&ParticlesEditor::_populate);
-
 }
 
 ParticlesEditor::ParticlesEditor() {
 
-	particles_editor_hb = memnew ( HBoxContainer );
+	particles_editor_hb = memnew(HBoxContainer);
 	SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
-	options = memnew( MenuButton );
+	options = memnew(MenuButton);
 	particles_editor_hb->add_child(options);
 	particles_editor_hb->hide();
 
 	options->set_text("Particles");
-	options->get_popup()->add_item(TTR("Generate AABB"),MENU_OPTION_GENERATE_AABB);
+	options->get_popup()->add_item(TTR("Generate AABB"), MENU_OPTION_GENERATE_AABB);
 	options->get_popup()->add_separator();
-	options->get_popup()->add_item(TTR("Create Emitter From Mesh"),MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH);
-	options->get_popup()->add_item(TTR("Create Emitter From Node"),MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
-	options->get_popup()->add_item(TTR("Clear Emitter"),MENU_OPTION_CLEAR_EMISSION_VOLUME);
+	options->get_popup()->add_item(TTR("Create Emission Points From Mesh"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH);
+	options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
+	//	options->get_popup()->add_item(TTR("Clear Emitter"), MENU_OPTION_CLEAR_EMISSION_VOLUME);
 
-	options->get_popup()->connect("id_pressed", this,"_menu_option");
+	options->get_popup()->connect("id_pressed", this, "_menu_option");
 
-	emission_dialog = memnew( ConfirmationDialog );
+	emission_dialog = memnew(ConfirmationDialog);
 	emission_dialog->set_title(TTR("Create Emitter"));
 	add_child(emission_dialog);
-	Label *l = memnew(Label);
-	l->set_pos(Point2(5,5));
-	l->set_text(TTR("Emission Positions:"));
-	emission_dialog->add_child(l);
-
+	VBoxContainer *emd_vb = memnew(VBoxContainer);
+	emission_dialog->add_child(emd_vb);
 
-	emission_amount = memnew( SpinBox );
-	emission_amount->set_anchor(MARGIN_RIGHT,ANCHOR_END);
-	emission_amount->set_begin( Point2(20,23));
-	emission_amount->set_end( Point2(5,25));
+	emission_amount = memnew(SpinBox);
 	emission_amount->set_min(1);
-	emission_amount->set_max(65536);
-	emission_amount->set_val(512);
-	emission_dialog->add_child(emission_amount);
-	emission_dialog->get_ok()->set_text(TTR("Create"));
-	emission_dialog->connect("confirmed",this,"_generate_emission_points");
-
-	l = memnew(Label);
-	l->set_pos(Point2(5,50));
-	l->set_text(TTR("Emission Fill:"));
-	emission_dialog->add_child(l);
-
-	emission_fill = memnew( OptionButton );
-	emission_fill->set_anchor(MARGIN_RIGHT,ANCHOR_END);
-	emission_fill->set_begin( Point2(20,70));
-	emission_fill->set_end( Point2(5,75));
-	emission_fill->add_item(TTR("Surface"));
+	emission_amount->set_max(100000);
+	emission_amount->set_value(512);
+	emd_vb->add_margin_child(TTR("Emission Points:"), emission_amount);
+
+	emission_fill = memnew(OptionButton);
+	emission_fill->add_item(TTR("Surface Points"));
+	emission_fill->add_item(TTR("Surface Points+Normal (Directed)"));
 	emission_fill->add_item(TTR("Volume"));
-	emission_dialog->add_child(emission_fill);
+	emd_vb->add_margin_child(TTR("Emission Source: "), emission_fill);
+
+	emission_dialog->get_ok()->set_text(TTR("Create"));
+	emission_dialog->connect("confirmed", this, "_generate_emission_points");
 
-	err_dialog = memnew( ConfirmationDialog );
+	err_dialog = memnew(ConfirmationDialog);
 	//err_dialog->get_cancel()->hide();
 	add_child(err_dialog);
 
-
-	emission_file_dialog = memnew( EditorFileDialog );
+	emission_file_dialog = memnew(EditorFileDialog);
 	add_child(emission_file_dialog);
-	emission_file_dialog->connect("file_selected",this,"_resource_seleted");
-	emission_tree_dialog = memnew( SceneTreeDialog );
+	emission_file_dialog->connect("file_selected", this, "_resource_seleted");
+	emission_tree_dialog = memnew(SceneTreeDialog);
 	add_child(emission_tree_dialog);
-	emission_tree_dialog->connect("selected",this,"_node_selected");
+	emission_tree_dialog->connect("selected", this, "_node_selected");
 
 	List<String> extensions;
-	ResourceLoader::get_recognized_extensions_for_type("Mesh",&extensions);
+	ResourceLoader::get_recognized_extensions_for_type("Mesh", &extensions);
 
 	emission_file_dialog->clear_filters();
-	for(int i=0;i<extensions.size();i++) {
+	for (int i = 0; i < extensions.size(); i++) {
 
-		emission_file_dialog->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper());
+		emission_file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
 	}
 
 	emission_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
 
 	//options->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
 	//options->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
-
 }
 
-
 void ParticlesEditorPlugin::edit(Object *p_object) {
 
 	particles_editor->edit(p_object->cast_to<Particles>());
@@ -427,7 +466,7 @@ void ParticlesEditorPlugin::edit(Object *p_object) {
 
 bool ParticlesEditorPlugin::handles(Object *p_object) const {
 
-	return p_object->is_type("Particles");
+	return p_object->is_class("Particles");
 }
 
 void ParticlesEditorPlugin::make_visible(bool p_visible) {
@@ -440,21 +479,16 @@ void ParticlesEditorPlugin::make_visible(bool p_visible) {
 		particles_editor->hide();
 		particles_editor->edit(NULL);
 	}
-
 }
 
 ParticlesEditorPlugin::ParticlesEditorPlugin(EditorNode *p_node) {
 
-	editor=p_node;
-	particles_editor = memnew( ParticlesEditor );
+	editor = p_node;
+	particles_editor = memnew(ParticlesEditor);
 	editor->get_viewport()->add_child(particles_editor);
 
 	particles_editor->hide();
 }
 
-
-ParticlesEditorPlugin::~ParticlesEditorPlugin()
-{
+ParticlesEditorPlugin::~ParticlesEditorPlugin() {
 }
-
-#endif

+ 7 - 15
editor/plugins/particles_editor_plugin.h

@@ -37,17 +37,16 @@
 /**
 	@author Juan Linietsky <[email protected]>
 */
-#if 0
+
 class ParticlesEditor : public Control {
 
-	GDCLASS(ParticlesEditor, Control );
+	GDCLASS(ParticlesEditor, Control);
 
 	Panel *panel;
 	MenuButton *options;
 	HBoxContainer *particles_editor_hb;
 	Particles *node;
 
-
 	EditorFileDialog *emission_file_dialog;
 	SceneTreeDialog *emission_tree_dialog;
 
@@ -57,9 +56,6 @@ class ParticlesEditor : public Control {
 	SpinBox *emission_amount;
 	OptionButton *emission_fill;
 
-
-
-
 	enum Menu {
 
 		MENU_OPTION_GENERATE_AABB,
@@ -72,35 +68,33 @@ class ParticlesEditor : public Control {
 	PoolVector<Face3> geometry;
 
 	void _generate_emission_points();
-	void _resource_seleted(const String& p_res);
-	void _node_selected(const NodePath& p_path);
+	void _resource_seleted(const String &p_res);
+	void _node_selected(const NodePath &p_path);
 
 	void _menu_option(int);
 
 	void _populate();
 
-friend class ParticlesEditorPlugin;
+	friend class ParticlesEditorPlugin;
 
 protected:
-
 	void _notification(int p_notification);
 	void _node_removed(Node *p_node);
 	static void _bind_methods();
-public:
 
+public:
 	void edit(Particles *p_particles);
 	ParticlesEditor();
 };
 
 class ParticlesEditorPlugin : public EditorPlugin {
 
-	GDCLASS( ParticlesEditorPlugin, EditorPlugin );
+	GDCLASS(ParticlesEditorPlugin, EditorPlugin);
 
 	ParticlesEditor *particles_editor;
 	EditorNode *editor;
 
 public:
-
 	virtual String get_name() const { return "Particles"; }
 	bool has_main_screen() const { return false; }
 	virtual void edit(Object *p_node);
@@ -109,8 +103,6 @@ public:
 
 	ParticlesEditorPlugin(EditorNode *p_node);
 	~ParticlesEditorPlugin();
-
 };
 
 #endif // PARTICLES_EDITOR_PLUGIN_H
-#endif

+ 6 - 6
editor/plugins/path_editor_plugin.cpp

@@ -530,16 +530,16 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) {
 	editor=p_node;
 	singleton=this;
 
-	path_material = Ref<FixedSpatialMaterial>( memnew( FixedSpatialMaterial ));
-	path_material->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.8) );
-	path_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true);
+	path_material = Ref<SpatialMaterial>( memnew( SpatialMaterial ));
+	path_material->set_parameter( SpatialMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.8) );
+	path_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true);
 	path_material->set_line_width(3);
 	path_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
 	path_material->set_flag(Material::FLAG_UNSHADED,true);
 
-	path_thin_material = Ref<FixedSpatialMaterial>( memnew( FixedSpatialMaterial ));
-	path_thin_material->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.4) );
-	path_thin_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true);
+	path_thin_material = Ref<SpatialMaterial>( memnew( SpatialMaterial ));
+	path_thin_material->set_parameter( SpatialMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.4) );
+	path_thin_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true);
 	path_thin_material->set_line_width(1);
 	path_thin_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
 	path_thin_material->set_flag(Material::FLAG_UNSHADED,true);

+ 2 - 2
editor/plugins/path_editor_plugin.h

@@ -78,8 +78,8 @@ public:
 	Path *get_edited_path() { return path; }
 
 	static PathEditorPlugin* singleton;
-	Ref<FixedSpatialMaterial> path_material;
-	Ref<FixedSpatialMaterial> path_thin_material;
+	Ref<SpatialMaterial> path_material;
+	Ref<SpatialMaterial> path_thin_material;
 	virtual bool forward_spatial_gui_input(Camera* p_camera,const InputEvent& p_event);
 
 	//virtual bool forward_gui_input(const InputEvent& p_event) { return collision_polygon_editor->forward_gui_input(p_event); }

+ 26 - 3
editor/plugins/shader_editor_plugin.cpp

@@ -137,14 +137,35 @@ void ShaderTextEditor::_load_theme_settings() {
 	}*/
 }
 
+void ShaderTextEditor::_check_shader_mode() {
+
+	String type = ShaderLanguage::get_shader_type(get_text_edit()->get_text());
+
+	print_line("type is: " + type);
+	Shader::Mode mode;
+
+	if (type == "canvas_item") {
+		mode = Shader::MODE_CANVAS_ITEM;
+	} else if (type == "particles") {
+		mode = Shader::MODE_PARTICLES;
+	} else {
+		mode = Shader::MODE_SPATIAL;
+	}
+
+	if (shader->get_mode() != mode) {
+		shader->set_code(get_text_edit()->get_text());
+		_load_theme_settings();
+	}
+}
+
 void ShaderTextEditor::_code_complete_script(const String &p_code, List<String> *r_options) {
 
-	print_line("code complete");
+	_check_shader_mode();
 
 	ShaderLanguage sl;
 	String calltip;
 
-	Error err = sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), r_options, calltip);
+	Error err = sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), r_options, calltip);
 
 	if (calltip != "") {
 		get_text_edit()->set_code_hint(calltip);
@@ -153,13 +174,15 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<String>
 
 void ShaderTextEditor::_validate_script() {
 
+	_check_shader_mode();
+
 	String code = get_text_edit()->get_text();
 	//List<StringName> params;
 	//shader->get_param_list(&params);
 
 	ShaderLanguage sl;
 
-	Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())));
+	Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types());
 
 	if (err != OK) {
 		String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text();

+ 2 - 0
editor/plugins/shader_editor_plugin.h

@@ -44,6 +44,8 @@ class ShaderTextEditor : public CodeTextEditor {
 
 	Ref<Shader> shader;
 
+	void _check_shader_mode();
+
 protected:
 	static void _bind_methods();
 	virtual void _load_theme_settings();

+ 19 - 19
editor/plugins/spatial_editor_plugin.cpp

@@ -2329,12 +2329,12 @@ void SpatialEditor::_generate_selection_box() {
 		st->add_vertex(b);
 	}
 
-	Ref<FixedSpatialMaterial> mat = memnew(FixedSpatialMaterial);
-	mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
+	Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
+	mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
 	mat->set_albedo(Color(1, 1, 1));
-	mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
-	mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-	mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+	mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+	mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+	mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
 	st->set_material(mat);
 	selection_box = st->commit();
 }
@@ -2888,12 +2888,12 @@ void SpatialEditor::_init_indicators() {
 	{
 
 		indicator_mat.instance();
-		indicator_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-		//indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP,true);
-		indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-		indicator_mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+		indicator_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+		//indicator_mat->set_flag(SpatialMaterial::FLAG_ONTOP,true);
+		indicator_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+		indicator_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
 
-		indicator_mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+		indicator_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 
 		PoolVector<Color> grid_colors[3];
 		PoolVector<Vector3> grid_points[3];
@@ -2980,7 +2980,7 @@ void SpatialEditor::_init_indicators() {
 		cursor_points.push_back(Vector3(0, 0, -cs));
 		cursor_material.instance();
 		cursor_material->set_albedo(Color(0, 1, 1));
-		cursor_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
+		cursor_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
 
 		Array d;
 		d.resize(VS::ARRAY_MAX);
@@ -3000,10 +3000,10 @@ void SpatialEditor::_init_indicators() {
 
 		float gizmo_alph = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_opacity");
 
-		gizmo_hl = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-		gizmo_hl->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-		gizmo_hl->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true);
-		gizmo_hl->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+		gizmo_hl = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+		gizmo_hl->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+		gizmo_hl->set_flag(SpatialMaterial::FLAG_ONTOP, true);
+		gizmo_hl->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 		gizmo_hl->set_albedo(Color(1, 1, 1, gizmo_alph + 0.2f));
 
 		for (int i = 0; i < 3; i++) {
@@ -3011,10 +3011,10 @@ void SpatialEditor::_init_indicators() {
 			move_gizmo[i] = Ref<Mesh>(memnew(Mesh));
 			rotate_gizmo[i] = Ref<Mesh>(memnew(Mesh));
 
-			Ref<FixedSpatialMaterial> mat = memnew(FixedSpatialMaterial);
-			mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-			mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true);
-			mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+			Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
+			mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+			mat->set_flag(SpatialMaterial::FLAG_ONTOP, true);
+			mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 			Color col;
 			col[i] = 1.0;
 			col.a = gizmo_alph;

+ 4 - 4
editor/plugins/spatial_editor_plugin.h

@@ -323,8 +323,8 @@ private:
 	bool grid_enabled;
 
 	Ref<Mesh> move_gizmo[3], rotate_gizmo[3];
-	Ref<FixedSpatialMaterial> gizmo_color[3];
-	Ref<FixedSpatialMaterial> gizmo_hl;
+	Ref<SpatialMaterial> gizmo_color[3];
+	Ref<SpatialMaterial> gizmo_hl;
 
 	int over_gizmo_handle;
 
@@ -333,8 +333,8 @@ private:
 	RID indicators_instance;
 	RID cursor_mesh;
 	RID cursor_instance;
-	Ref<FixedSpatialMaterial> indicator_mat;
-	Ref<FixedSpatialMaterial> cursor_material;
+	Ref<SpatialMaterial> indicator_mat;
+	Ref<SpatialMaterial> cursor_material;
 
 	/*
 	struct Selected {

+ 1 - 1
editor/plugins/tile_set_editor_plugin.cpp

@@ -58,7 +58,7 @@ void TileSetEditor::_import_scene(Node *scene, Ref<TileSet> p_library, bool p_me
 
 		Sprite *mi = child->cast_to<Sprite>();
 		Ref<Texture> texture = mi->get_texture();
-		Ref<CanvasItemMaterial> material = mi->get_material();
+		Ref<ShaderMaterial> material = mi->get_material();
 
 		if (texture.is_null())
 			continue;

+ 92 - 87
editor/spatial_editor_gizmos.cpp

@@ -70,10 +70,6 @@ void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) {
 
 	instance = VS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario());
 	VS::get_singleton()->instance_attach_object_instance_ID(instance, p_base->get_instance_ID());
-	if (billboard)
-		VS::get_singleton()->instance_geometry_set_flag(instance, VS::INSTANCE_FLAG_BILLBOARD, true);
-	if (unscaled)
-		VS::get_singleton()->instance_geometry_set_flag(instance, VS::INSTANCE_FLAG_DEPH_SCALE, true);
 	if (skeleton.is_valid())
 		VS::get_singleton()->instance_attach_skeleton(instance, skeleton);
 	if (extra_margin)
@@ -228,7 +224,6 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi
 	Array a;
 	a.resize(VS::ARRAY_MAX);
 	a[VS::ARRAY_VERTEX] = p_handles;
-	print_line("handles?: " + itos(p_handles.size()));
 	PoolVector<Color> colors;
 	{
 		colors.resize(p_handles.size());
@@ -243,7 +238,10 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi
 	}
 	a[VS::ARRAY_COLOR] = colors;
 	mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a);
-	mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material);
+	if (p_billboard)
+		mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material_billboard);
+	else
+		mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material);
 
 	if (p_billboard) {
 		float md = 0;
@@ -390,7 +388,7 @@ bool EditorSpatialGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_p
 		Transform t = spatial_node->get_global_transform();
 		t.orthonormalize();
 		if (billboard_handle) {
-			t.set_look_at(t.origin, t.origin + p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
+			t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
 		}
 
 		float min_d = 1e20;
@@ -452,7 +450,7 @@ bool EditorSpatialGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_p
 		const Vector3 *vptr = collision_segments.ptr();
 		Transform t = spatial_node->get_global_transform();
 		if (billboard_handle) {
-			t.set_look_at(t.origin, t.origin + p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
+			t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
 		}
 
 		Vector3 cp;
@@ -504,7 +502,7 @@ bool EditorSpatialGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_p
 		Transform gt = spatial_node->get_global_transform();
 
 		if (billboard_handle) {
-			gt.set_look_at(gt.origin, gt.origin + p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
+			gt.set_look_at(gt.origin, gt.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
 		}
 
 		Transform ai = gt.affine_inverse();
@@ -777,7 +775,7 @@ void LightSpatialGizmo::redraw() {
 			points.push_back(Vector3(b.x, b.y, 0));
 		}
 
-		add_lines(points, SpatialEditorGizmos::singleton->light_material, true);
+		add_lines(points, SpatialEditorGizmos::singleton->light_material_omni, true);
 		add_collision_segments(points);
 
 		add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_omni_icon, 0.05);
@@ -2994,24 +2992,24 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
 	return Ref<SpatialEditorGizmo>();
 }
 
-Ref<FixedSpatialMaterial> SpatialEditorGizmos::create_line_material(const Color &p_base_color) {
+Ref<SpatialMaterial> SpatialEditorGizmos::create_line_material(const Color &p_base_color) {
 
-	Ref<FixedSpatialMaterial> line_material = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	line_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
+	Ref<SpatialMaterial> line_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	line_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
 	line_material->set_line_width(3.0);
-	line_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
-	//line_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-	//->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+	line_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+	//line_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+	//->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
 	line_material->set_albedo(p_base_color);
 
 	return line_material;
 }
 
-Ref<FixedSpatialMaterial> SpatialEditorGizmos::create_solid_material(const Color &p_base_color) {
+Ref<SpatialMaterial> SpatialEditorGizmos::create_solid_material(const Color &p_base_color) {
 
-	Ref<FixedSpatialMaterial> line_material = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	line_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	line_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+	Ref<SpatialMaterial> line_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	line_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	line_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 	line_material->set_albedo(p_base_color);
 
 	return line_material;
@@ -3021,58 +3019,65 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 
 	singleton = this;
 
-	handle_material = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	handle_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
+	handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
 	handle_material->set_albedo(Color(0.8, 0.8, 0.8));
+	handle_material_billboard = handle_material->duplicate();
+	handle_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
 
-	handle2_material = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	handle2_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	handle2_material->set_flag(FixedSpatialMaterial::FLAG_USE_POINT_SIZE, true);
+	handle2_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	handle2_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	handle2_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true);
 	handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons");
 	handle2_material->set_point_size(handle_t->get_width());
-	handle2_material->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, handle_t);
+	handle2_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t);
 	handle2_material->set_albedo(Color(1, 1, 1));
-	handle2_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
-	handle2_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-	handle2_material->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+	handle2_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+	handle2_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+	handle2_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+	handle2_material_billboard = handle2_material->duplicate();
+	handle2_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
 
 	light_material = create_line_material(Color(1, 1, 0.2));
-
-	light_material_omni_icon = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	light_material_omni_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	light_material_omni_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
-	light_material_omni_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED);
-	light_material_omni_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+	light_material_omni = create_line_material(Color(1, 1, 0.2));
+	light_material_omni->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
+
+	light_material_omni_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	light_material_omni_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	light_material_omni_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+	light_material_omni_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
+	light_material_omni_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 	light_material_omni_icon->set_albedo(Color(1, 1, 1, 0.9));
-	light_material_omni_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons"));
-
-	light_material_directional_icon = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	light_material_directional_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	light_material_directional_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
-	light_material_directional_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED);
-	light_material_directional_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+	light_material_omni_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons"));
+	light_material_omni_icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true);
+
+	light_material_directional_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	light_material_directional_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	light_material_directional_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+	light_material_directional_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
+	light_material_directional_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 	light_material_directional_icon->set_albedo(Color(1, 1, 1, 0.9));
-	light_material_directional_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons"));
+	light_material_directional_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons"));
 
 	camera_material = create_line_material(Color(1.0, 0.5, 1.0));
 
 	navmesh_edge_material = create_line_material(Color(0.1, 0.8, 1.0));
 	navmesh_solid_material = create_solid_material(Color(0.1, 0.8, 1.0, 0.4));
-	navmesh_edge_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false);
-	navmesh_edge_material->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false);
-	navmesh_solid_material->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
+	navmesh_edge_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false);
+	navmesh_edge_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false);
+	navmesh_solid_material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
 
 	navmesh_edge_material_disabled = create_line_material(Color(1.0, 0.8, 0.1));
 	navmesh_solid_material_disabled = create_solid_material(Color(1.0, 0.8, 0.1, 0.4));
-	navmesh_edge_material_disabled->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false);
-	navmesh_edge_material_disabled->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false);
-	navmesh_solid_material_disabled->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
+	navmesh_edge_material_disabled->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false);
+	navmesh_edge_material_disabled->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false);
+	navmesh_solid_material_disabled->set_cull_mode(SpatialMaterial::CULL_DISABLED);
 
 	skeleton_material = create_line_material(Color(0.6, 1.0, 0.3));
-	skeleton_material->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
-	skeleton_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	skeleton_material->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true);
-	skeleton_material->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED);
+	skeleton_material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+	skeleton_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	skeleton_material->set_flag(SpatialMaterial::FLAG_ONTOP, true);
+	skeleton_material->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
 
 	//position 3D Shared mesh
 
@@ -3095,11 +3100,11 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 		cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
 		cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
 
-		Ref<FixedSpatialMaterial> mat = memnew(FixedSpatialMaterial);
-		mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-		mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-		mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
-		mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+		Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
+		mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+		mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+		mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+		mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 		mat->set_line_width(3);
 		Array d;
 		d.resize(VS::ARRAY_MAX);
@@ -3119,11 +3124,11 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 		cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
 		cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
 
-		Ref<FixedSpatialMaterial> mat = memnew(FixedSpatialMaterial);
-		mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-		mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-		mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
-		mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+		Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
+		mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+		mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+		mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+		mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 		mat->set_line_width(3);
 		Array d;
 		d.resize(VS::ARRAY_MAX);
@@ -3133,13 +3138,13 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 		listener_line_mesh->surface_set_material(0, mat);
 	}
 
-	sample_player_icon = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	sample_player_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	sample_player_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
-	sample_player_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED);
-	sample_player_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+	sample_player_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	sample_player_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	sample_player_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+	sample_player_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
+	sample_player_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 	sample_player_icon->set_albedo(Color(1, 1, 1, 0.9));
-	sample_player_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons"));
+	sample_player_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons"));
 
 	room_material = create_line_material(Color(1.0, 0.6, 0.9));
 	portal_material = create_line_material(Color(1.0, 0.8, 0.6));
@@ -3152,29 +3157,29 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 	gi_probe_material_internal = create_line_material(Color(0.5, 0.8, 0.3, 0.1));
 	joint_material = create_line_material(Color(0.6, 0.8, 1.0));
 
-	stream_player_icon = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	stream_player_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	stream_player_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
-	stream_player_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED);
-	stream_player_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+	stream_player_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	stream_player_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	stream_player_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+	stream_player_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
+	stream_player_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 	stream_player_icon->set_albedo(Color(1, 1, 1, 0.9));
-	stream_player_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer", "EditorIcons"));
+	stream_player_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer", "EditorIcons"));
 
-	visibility_notifier_icon = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	visibility_notifier_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	visibility_notifier_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
-	visibility_notifier_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED);
-	visibility_notifier_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+	visibility_notifier_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	visibility_notifier_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	visibility_notifier_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+	visibility_notifier_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
+	visibility_notifier_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 	visibility_notifier_icon->set_albedo(Color(1, 1, 1, 0.9));
-	visibility_notifier_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("Visible", "EditorIcons"));
+	visibility_notifier_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("Visible", "EditorIcons"));
 
-	listener_icon = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
-	listener_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-	listener_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
-	listener_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED);
-	listener_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+	listener_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+	listener_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+	listener_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+	listener_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
+	listener_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 	listener_icon->set_albedo(Color(1, 1, 1, 0.9));
-	listener_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons"));
+	listener_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons"));
 
 	{
 

+ 35 - 32
editor/spatial_editor_gizmos.h

@@ -399,38 +399,41 @@ public:
 
 class SpatialEditorGizmos {
 public:
-	Ref<FixedSpatialMaterial> create_line_material(const Color &p_base_color);
-	Ref<FixedSpatialMaterial> create_solid_material(const Color &p_base_color);
-	Ref<FixedSpatialMaterial> handle2_material;
-	Ref<FixedSpatialMaterial> handle_material;
-	Ref<FixedSpatialMaterial> light_material;
-	Ref<FixedSpatialMaterial> light_material_omni_icon;
-	Ref<FixedSpatialMaterial> light_material_directional_icon;
-	Ref<FixedSpatialMaterial> camera_material;
-	Ref<FixedSpatialMaterial> skeleton_material;
-	Ref<FixedSpatialMaterial> reflection_probe_material;
-	Ref<FixedSpatialMaterial> reflection_probe_material_internal;
-	Ref<FixedSpatialMaterial> gi_probe_material;
-	Ref<FixedSpatialMaterial> gi_probe_material_internal;
-	Ref<FixedSpatialMaterial> room_material;
-	Ref<FixedSpatialMaterial> portal_material;
-	Ref<FixedSpatialMaterial> raycast_material;
-	Ref<FixedSpatialMaterial> visibility_notifier_material;
-	Ref<FixedSpatialMaterial> car_wheel_material;
-	Ref<FixedSpatialMaterial> joint_material;
-
-	Ref<FixedSpatialMaterial> navmesh_edge_material;
-	Ref<FixedSpatialMaterial> navmesh_solid_material;
-	Ref<FixedSpatialMaterial> navmesh_edge_material_disabled;
-	Ref<FixedSpatialMaterial> navmesh_solid_material_disabled;
-
-	Ref<FixedSpatialMaterial> listener_icon;
-
-	Ref<FixedSpatialMaterial> sample_player_icon;
-	Ref<FixedSpatialMaterial> stream_player_icon;
-	Ref<FixedSpatialMaterial> visibility_notifier_icon;
-
-	Ref<FixedSpatialMaterial> shape_material;
+	Ref<SpatialMaterial> create_line_material(const Color &p_base_color);
+	Ref<SpatialMaterial> create_solid_material(const Color &p_base_color);
+	Ref<SpatialMaterial> handle2_material;
+	Ref<SpatialMaterial> handle2_material_billboard;
+	Ref<SpatialMaterial> handle_material;
+	Ref<SpatialMaterial> handle_material_billboard;
+	Ref<SpatialMaterial> light_material;
+	Ref<SpatialMaterial> light_material_omni;
+	Ref<SpatialMaterial> light_material_omni_icon;
+	Ref<SpatialMaterial> light_material_directional_icon;
+	Ref<SpatialMaterial> camera_material;
+	Ref<SpatialMaterial> skeleton_material;
+	Ref<SpatialMaterial> reflection_probe_material;
+	Ref<SpatialMaterial> reflection_probe_material_internal;
+	Ref<SpatialMaterial> gi_probe_material;
+	Ref<SpatialMaterial> gi_probe_material_internal;
+	Ref<SpatialMaterial> room_material;
+	Ref<SpatialMaterial> portal_material;
+	Ref<SpatialMaterial> raycast_material;
+	Ref<SpatialMaterial> visibility_notifier_material;
+	Ref<SpatialMaterial> car_wheel_material;
+	Ref<SpatialMaterial> joint_material;
+
+	Ref<SpatialMaterial> navmesh_edge_material;
+	Ref<SpatialMaterial> navmesh_solid_material;
+	Ref<SpatialMaterial> navmesh_edge_material_disabled;
+	Ref<SpatialMaterial> navmesh_solid_material_disabled;
+
+	Ref<SpatialMaterial> listener_icon;
+
+	Ref<SpatialMaterial> sample_player_icon;
+	Ref<SpatialMaterial> stream_player_icon;
+	Ref<SpatialMaterial> visibility_notifier_icon;
+
+	Ref<SpatialMaterial> shape_material;
 	Ref<Texture> handle_t;
 
 	Ref<Mesh> pos3d_mesh;

+ 3 - 1
main/tests/test_shader_lang.cpp

@@ -323,8 +323,10 @@ MainLoop *test() {
 
 	Set<String> rm;
 	rm.insert("popo");
+	Set<String> types;
+	types.insert("spatial");
 
-	Error err = sl.compile(code, dt, rm);
+	Error err = sl.compile(code, dt, rm, types);
 
 	if (err) {
 

+ 9 - 9
modules/gridmap/grid_map_editor_plugin.cpp

@@ -834,9 +834,9 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
 
 		//update grids
 		indicator_mat.instance();
-		indicator_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-		indicator_mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
-		indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+		indicator_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+		indicator_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+		indicator_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
 		indicator_mat->set_albedo(Color(0.8, 0.5, 0.1));
 
 		Vector<Vector3> grid_points[3];
@@ -1309,9 +1309,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
 
 		inner_mat.instance();
 		inner_mat->set_albedo(Color(0.7, 0.7, 1.0, 0.3));
-		inner_mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true);
-		inner_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
-		inner_mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+		inner_mat->set_flag(SpatialMaterial::FLAG_ONTOP, true);
+		inner_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+		inner_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 
 		d[VS::ARRAY_VERTEX] = triangles;
 		VisualServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, VS::PRIMITIVE_TRIANGLES, d);
@@ -1319,10 +1319,10 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
 
 		outer_mat.instance();
 		outer_mat->set_albedo(Color(0.7, 0.7, 1.0, 0.3));
-		outer_mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true);
-		outer_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
+		outer_mat->set_flag(SpatialMaterial::FLAG_ONTOP, true);
+		outer_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
 		outer_mat->set_line_width(3.0);
-		outer_mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
+		outer_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
 
 		d[VS::ARRAY_VERTEX] = lines;
 		VisualServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, VS::PRIMITIVE_LINES, d);

+ 3 - 3
modules/gridmap/grid_map_editor_plugin.h

@@ -112,9 +112,9 @@ class GridMapEditor : public VBoxContainer {
 	RID duplicate_mesh;
 	RID duplicate_instance;
 
-	Ref<FixedSpatialMaterial> indicator_mat;
-	Ref<FixedSpatialMaterial> inner_mat;
-	Ref<FixedSpatialMaterial> outer_mat;
+	Ref<SpatialMaterial> indicator_mat;
+	Ref<SpatialMaterial> inner_mat;
+	Ref<SpatialMaterial> outer_mat;
 
 	bool updating;
 

+ 8 - 8
platform/iphone/rasterizer_iphone.cpp

@@ -447,7 +447,7 @@ RID RasterizerIPhone::material_create() {
 	return material_owner.make_rid(memnew(Material));
 }
 
-void RasterizerIPhone::fixed_material_set_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter, const Variant &p_value) {
+void RasterizerIPhone::fixed_material_set_parameter(RID p_material, VS::SpatialMaterialParam p_parameter, const Variant &p_value) {
 
 	Material *m = material_owner.get(p_material);
 	ERR_FAIL_COND(!m);
@@ -455,7 +455,7 @@ void RasterizerIPhone::fixed_material_set_parameter(RID p_material, VS::FixedSpa
 
 	m->parameters[p_parameter] = p_value;
 }
-Variant RasterizerIPhone::fixed_material_get_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter) const {
+Variant RasterizerIPhone::fixed_material_get_parameter(RID p_material, VS::SpatialMaterialParam p_parameter) const {
 
 	Material *m = material_owner.get(p_material);
 	ERR_FAIL_COND_V(!m, Variant());
@@ -464,7 +464,7 @@ Variant RasterizerIPhone::fixed_material_get_parameter(RID p_material, VS::Fixed
 	return m->parameters[p_parameter];
 }
 
-void RasterizerIPhone::fixed_material_set_texture(RID p_material, VS::FixedSpatialMaterialParam p_parameter, RID p_texture) {
+void RasterizerIPhone::fixed_material_set_texture(RID p_material, VS::SpatialMaterialParam p_parameter, RID p_texture) {
 
 	Material *m = material_owner.get(p_material);
 	ERR_FAIL_COND(!m);
@@ -472,7 +472,7 @@ void RasterizerIPhone::fixed_material_set_texture(RID p_material, VS::FixedSpati
 
 	m->textures[p_parameter] = p_texture;
 }
-RID RasterizerIPhone::fixed_material_get_texture(RID p_material, VS::FixedSpatialMaterialParam p_parameter) const {
+RID RasterizerIPhone::fixed_material_get_texture(RID p_material, VS::SpatialMaterialParam p_parameter) const {
 
 	Material *m = material_owner.get(p_material);
 	ERR_FAIL_COND_V(!m, RID());
@@ -496,7 +496,7 @@ VS::MaterialBlendMode RasterizerIPhone::fixed_material_get_detail_blend_mode(RID
 	return m->detail_blend_mode;
 }
 
-void RasterizerIPhone::fixed_material_set_texcoord_mode(RID p_material, VS::FixedSpatialMaterialParam p_parameter, VS::FixedSpatialMaterialTexCoordMode p_mode) {
+void RasterizerIPhone::fixed_material_set_texcoord_mode(RID p_material, VS::SpatialMaterialParam p_parameter, VS::SpatialMaterialTexCoordMode p_mode) {
 
 	Material *m = material_owner.get(p_material);
 	ERR_FAIL_COND(!m);
@@ -504,7 +504,7 @@ void RasterizerIPhone::fixed_material_set_texcoord_mode(RID p_material, VS::Fixe
 
 	m->texcoord_mode[p_parameter] = p_mode;
 }
-VS::FixedSpatialMaterialTexCoordMode RasterizerIPhone::fixed_material_get_texcoord_mode(RID p_material, VS::FixedSpatialMaterialParam p_parameter) const {
+VS::SpatialMaterialTexCoordMode RasterizerIPhone::fixed_material_get_texcoord_mode(RID p_material, VS::SpatialMaterialParam p_parameter) const {
 
 	Material *m = material_owner.get(p_material);
 	ERR_FAIL_COND_V(!m, VS::FIXED_MATERIAL_TEXCOORD_TEXGEN);
@@ -513,7 +513,7 @@ VS::FixedSpatialMaterialTexCoordMode RasterizerIPhone::fixed_material_get_texcoo
 	return m->texcoord_mode[p_parameter]; // for now
 }
 
-void RasterizerIPhone::fixed_material_set_texgen_mode(RID p_material, VS::FixedSpatialMaterialTexGenMode p_mode) {
+void RasterizerIPhone::fixed_material_set_texgen_mode(RID p_material, VS::SpatialMaterialTexGenMode p_mode) {
 
 	Material *m = material_owner.get(p_material);
 	ERR_FAIL_COND(!m);
@@ -521,7 +521,7 @@ void RasterizerIPhone::fixed_material_set_texgen_mode(RID p_material, VS::FixedS
 	m->texgen_mode = p_mode;
 };
 
-VS::FixedSpatialMaterialTexGenMode RasterizerIPhone::fixed_material_get_texgen_mode(RID p_material) const {
+VS::SpatialMaterialTexGenMode RasterizerIPhone::fixed_material_get_texgen_mode(RID p_material) const {
 
 	Material *m = material_owner.get(p_material);
 	ERR_FAIL_COND_V(!m, VS::FIXED_MATERIAL_TEXGEN_SPHERE);

+ 10 - 10
platform/iphone/rasterizer_iphone.h

@@ -100,11 +100,11 @@ class RasterizerIPhone : public Rasterizer {
 		RID textures[VisualServer::FIXED_MATERIAL_PARAM_MAX];
 
 		Transform uv_transform;
-		VS::FixedSpatialMaterialTexCoordMode texcoord_mode[VisualServer::FIXED_MATERIAL_PARAM_MAX];
+		VS::SpatialMaterialTexCoordMode texcoord_mode[VisualServer::FIXED_MATERIAL_PARAM_MAX];
 
 		VS::MaterialBlendMode detail_blend_mode;
 
-		VS::FixedSpatialMaterialTexGenMode texgen_mode;
+		VS::SpatialMaterialTexGenMode texgen_mode;
 
 		Material() {
 
@@ -614,20 +614,20 @@ public:
 
 	virtual RID material_create();
 
-	virtual void fixed_material_set_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter, const Variant &p_value);
-	virtual Variant fixed_material_get_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter) const;
+	virtual void fixed_material_set_parameter(RID p_material, VS::SpatialMaterialParam p_parameter, const Variant &p_value);
+	virtual Variant fixed_material_get_parameter(RID p_material, VS::SpatialMaterialParam p_parameter) const;
 
-	virtual void fixed_material_set_texture(RID p_material, VS::FixedSpatialMaterialParam p_parameter, RID p_texture);
-	virtual RID fixed_material_get_texture(RID p_material, VS::FixedSpatialMaterialParam p_parameter) const;
+	virtual void fixed_material_set_texture(RID p_material, VS::SpatialMaterialParam p_parameter, RID p_texture);
+	virtual RID fixed_material_get_texture(RID p_material, VS::SpatialMaterialParam p_parameter) const;
 
 	virtual void fixed_material_set_detail_blend_mode(RID p_material, VS::MaterialBlendMode p_mode);
 	virtual VS::MaterialBlendMode fixed_material_get_detail_blend_mode(RID p_material) const;
 
-	virtual void fixed_material_set_texgen_mode(RID p_material, VS::FixedSpatialMaterialTexGenMode p_mode);
-	virtual VS::FixedSpatialMaterialTexGenMode fixed_material_get_texgen_mode(RID p_material) const;
+	virtual void fixed_material_set_texgen_mode(RID p_material, VS::SpatialMaterialTexGenMode p_mode);
+	virtual VS::SpatialMaterialTexGenMode fixed_material_get_texgen_mode(RID p_material) const;
 
-	virtual void fixed_material_set_texcoord_mode(RID p_material, VS::FixedSpatialMaterialParam p_parameter, VS::FixedSpatialMaterialTexCoordMode p_mode);
-	virtual VS::FixedSpatialMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material, VS::FixedSpatialMaterialParam p_parameter) const;
+	virtual void fixed_material_set_texcoord_mode(RID p_material, VS::SpatialMaterialParam p_parameter, VS::SpatialMaterialTexCoordMode p_mode);
+	virtual VS::SpatialMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material, VS::SpatialMaterialParam p_parameter) const;
 
 	virtual void fixed_material_set_uv_transform(RID p_material, const Transform &p_transform);
 	virtual Transform fixed_material_get_uv_transform(RID p_material) const;

+ 6 - 124
scene/2d/canvas_item.cpp

@@ -37,124 +37,6 @@
 #include "scene/scene_string_names.h"
 #include "servers/visual_server.h"
 
-bool CanvasItemMaterial::_set(const StringName &p_name, const Variant &p_value) {
-
-	if (p_name == SceneStringNames::get_singleton()->shader_shader) {
-		set_shader(p_value);
-		return true;
-	} else {
-
-		if (shader.is_valid()) {
-
-			StringName pr = shader->remap_param(p_name);
-			if (!pr) {
-				String n = p_name;
-				if (n.find("param/") == 0) { //backwards compatibility
-					pr = n.substr(6, n.length());
-				}
-			}
-			if (pr) {
-				VisualServer::get_singleton()->material_set_param(_get_material(), pr, p_value);
-				return true;
-			}
-		}
-	}
-
-	return false;
-}
-
-bool CanvasItemMaterial::_get(const StringName &p_name, Variant &r_ret) const {
-
-	if (p_name == SceneStringNames::get_singleton()->shader_shader) {
-
-		r_ret = get_shader();
-		return true;
-
-	} else {
-
-		if (shader.is_valid()) {
-
-			StringName pr = shader->remap_param(p_name);
-			if (pr) {
-				r_ret = VisualServer::get_singleton()->material_get_param(_get_material(), pr);
-				return true;
-			}
-		}
-	}
-
-	return false;
-}
-
-void CanvasItemMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
-
-	p_list->push_back(PropertyInfo(Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph"));
-
-	if (!shader.is_null()) {
-
-		shader->get_param_list(p_list);
-	}
-}
-
-void CanvasItemMaterial::set_shader(const Ref<Shader> &p_shader) {
-
-	ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode() != Shader::MODE_CANVAS_ITEM);
-
-	shader = p_shader;
-
-	RID rid;
-	if (shader.is_valid())
-		rid = shader->get_rid();
-
-	VS::get_singleton()->material_set_shader(_get_material(), rid);
-	_change_notify(); //properties for shader exposed
-	emit_changed();
-}
-
-Ref<Shader> CanvasItemMaterial::get_shader() const {
-
-	return shader;
-}
-
-void CanvasItemMaterial::set_shader_param(const StringName &p_param, const Variant &p_value) {
-
-	VS::get_singleton()->material_set_param(_get_material(), p_param, p_value);
-}
-
-Variant CanvasItemMaterial::get_shader_param(const StringName &p_param) const {
-
-	return VS::get_singleton()->material_get_param(_get_material(), p_param);
-}
-
-void CanvasItemMaterial::_bind_methods() {
-
-	ClassDB::bind_method(D_METHOD("set_shader", "shader:Shader"), &CanvasItemMaterial::set_shader);
-	ClassDB::bind_method(D_METHOD("get_shader:Shader"), &CanvasItemMaterial::get_shader);
-	ClassDB::bind_method(D_METHOD("set_shader_param", "param", "value"), &CanvasItemMaterial::set_shader_param);
-	ClassDB::bind_method(D_METHOD("get_shader_param", "param"), &CanvasItemMaterial::get_shader_param);
-}
-
-void CanvasItemMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-
-	String f = p_function.operator String();
-	if ((f == "get_shader_param" || f == "set_shader_param") && p_idx == 0) {
-
-		if (shader.is_valid()) {
-			List<PropertyInfo> pl;
-			shader->get_param_list(&pl);
-			for (List<PropertyInfo>::Element *E = pl.front(); E; E = E->next()) {
-				r_options->push_back("\"" + E->get().name.replace_first("shader_param/", "") + "\"");
-			}
-		}
-	}
-	Resource::get_argument_options(p_function, p_idx, r_options);
-}
-
-CanvasItemMaterial::CanvasItemMaterial() {
-}
-
-CanvasItemMaterial::~CanvasItemMaterial() {
-}
-
 ///////////////////////////////////////////////////////////////////
 
 bool CanvasItem::is_visible_in_tree() const {
@@ -770,7 +652,7 @@ bool CanvasItem::is_draw_behind_parent_enabled() const {
 	return behind;
 }
 
-void CanvasItem::set_material(const Ref<CanvasItemMaterial> &p_material) {
+void CanvasItem::set_material(const Ref<ShaderMaterial> &p_material) {
 
 	material = p_material;
 	RID rid;
@@ -791,7 +673,7 @@ bool CanvasItem::get_use_parent_material() const {
 	return use_parent_material;
 }
 
-Ref<CanvasItemMaterial> CanvasItem::get_material() const {
+Ref<ShaderMaterial> CanvasItem::get_material() const {
 
 	return material;
 }
@@ -801,7 +683,7 @@ Vector2 CanvasItem::make_canvas_pos_local(const Vector2 &screen_point) const {
 	ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
 
 	Transform2D local_matrix = (get_canvas_transform() *
-								get_global_transform())
+									   get_global_transform())
 									   .affine_inverse();
 
 	return local_matrix.xform(screen_point);
@@ -895,8 +777,8 @@ void CanvasItem::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d);
 	//ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport);
 
-	ClassDB::bind_method(D_METHOD("set_material", "material:CanvasItemMaterial"), &CanvasItem::set_material);
-	ClassDB::bind_method(D_METHOD("get_material:CanvasItemMaterial"), &CanvasItem::get_material);
+	ClassDB::bind_method(D_METHOD("set_material", "material:ShaderMaterial"), &CanvasItem::set_material);
+	ClassDB::bind_method(D_METHOD("get_material:ShaderMaterial"), &CanvasItem::get_material);
 
 	ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
 	ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
@@ -922,7 +804,7 @@ void CanvasItem::_bind_methods() {
 	ADD_PROPERTYNO(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
 
 	ADD_GROUP("Material", "");
-	ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial"), "set_material", "get_material");
+	ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"), "set_material", "get_material");
 	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
 	//exporting these two things doesn't really make much sense i think
 	//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), "set_as_toplevel","is_set_as_toplevel") ;

+ 3 - 35
scene/2d/canvas_item.h

@@ -41,38 +41,6 @@ class Font;
 
 class StyleBox;
 
-class CanvasItemMaterial : public Material {
-
-	GDCLASS(CanvasItemMaterial, Material);
-	Ref<Shader> shader;
-
-public:
-	/*enum ShadingMode {
-		SHADING_NORMAL,
-		SHADING_UNSHADED,
-		SHADING_ONLY_LIGHT,
-	};*/
-
-protected:
-	bool _set(const StringName &p_name, const Variant &p_value);
-	bool _get(const StringName &p_name, Variant &r_ret) const;
-	void _get_property_list(List<PropertyInfo> *p_list) const;
-
-	static void _bind_methods();
-
-	void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
-
-public:
-	void set_shader(const Ref<Shader> &p_shader);
-	Ref<Shader> get_shader() const;
-
-	void set_shader_param(const StringName &p_param, const Variant &p_value);
-	Variant get_shader_param(const StringName &p_param) const;
-
-	CanvasItemMaterial();
-	~CanvasItemMaterial();
-};
-
 class CanvasItem : public Node {
 
 	GDCLASS(CanvasItem, Node);
@@ -114,7 +82,7 @@ private:
 	bool notify_local_transform;
 	bool notify_transform;
 
-	Ref<CanvasItemMaterial> material;
+	Ref<ShaderMaterial> material;
 
 	mutable Transform2D global_transform;
 	mutable bool global_invalid;
@@ -234,8 +202,8 @@ public:
 	RID get_canvas() const;
 	Ref<World2D> get_world_2d() const;
 
-	void set_material(const Ref<CanvasItemMaterial> &p_material);
-	Ref<CanvasItemMaterial> get_material() const;
+	void set_material(const Ref<ShaderMaterial> &p_material);
+	Ref<ShaderMaterial> get_material() const;
 
 	void set_use_parent_material(bool p_use_parent_material);
 	bool get_use_parent_material() const;

+ 2 - 2
scene/2d/tile_map.cpp

@@ -304,7 +304,7 @@ void TileMap::_update_dirty_quadrants() {
 			VS::get_singleton()->free(E->get().id);
 		}
 		q.occluder_instances.clear();
-		Ref<CanvasItemMaterial> prev_material;
+		Ref<ShaderMaterial> prev_material;
 		RID prev_canvas_item;
 		RID prev_debug_canvas_item;
 
@@ -324,7 +324,7 @@ void TileMap::_update_dirty_quadrants() {
 			if (!tex.is_valid())
 				continue;
 
-			Ref<CanvasItemMaterial> mat = tile_set->tile_get_material(c.id);
+			Ref<ShaderMaterial> mat = tile_set->tile_get_material(c.id);
 
 			RID canvas_item;
 			RID debug_canvas_item;

+ 7 - 7
scene/3d/baked_light_instance.cpp

@@ -250,7 +250,7 @@ Vector<Color> BakedLight::_get_bake_texture(Image &p_image, const Color &p_color
 BakedLight::MaterialCache BakedLight::_get_material_cache(Ref<Material> p_material) {
 
 	//this way of obtaining materials is inaccurate and also does not support some compressed formats very well
-	Ref<FixedSpatialMaterial> mat = p_material;
+	Ref<SpatialMaterial> mat = p_material;
 
 	Ref<Material> material = mat; //hack for now
 
@@ -262,7 +262,7 @@ BakedLight::MaterialCache BakedLight::_get_material_cache(Ref<Material> p_materi
 
 	if (mat.is_valid()) {
 
-		Ref<ImageTexture> albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO);
+		Ref<ImageTexture> albedo_tex = mat->get_texture(SpatialMaterial::TEXTURE_ALBEDO);
 
 		Image img_albedo;
 		if (albedo_tex.is_valid()) {
@@ -272,7 +272,7 @@ BakedLight::MaterialCache BakedLight::_get_material_cache(Ref<Material> p_materi
 
 		mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo());
 
-		Ref<ImageTexture> emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION);
+		Ref<ImageTexture> emission_tex = mat->get_texture(SpatialMaterial::TEXTURE_EMISSION);
 
 		Color emission_col = mat->get_emission();
 		emission_col.r *= mat->get_emission_energy();
@@ -1591,11 +1591,11 @@ void BakedLight::create_debug_mesh(DebugMode p_mode) {
 	}
 
 	{
-		Ref<FixedSpatialMaterial> fsm;
+		Ref<SpatialMaterial> fsm;
 		fsm.instance();
-		fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
-		fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-		fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
+		fsm->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+		fsm->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+		fsm->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
 		fsm->set_albedo(Color(1, 1, 1, 1));
 
 		mesh->surface_set_material(0, fsm);

+ 7 - 7
scene/3d/gi_probe.cpp

@@ -919,7 +919,7 @@ Vector<Color> GIProbe::_get_bake_texture(Image &p_image, const Color &p_color) {
 GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_material, Baker *p_baker) {
 
 	//this way of obtaining materials is inaccurate and also does not support some compressed formats very well
-	Ref<FixedSpatialMaterial> mat = p_material;
+	Ref<SpatialMaterial> mat = p_material;
 
 	Ref<Material> material = mat; //hack for now
 
@@ -931,7 +931,7 @@ GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_mater
 
 	if (mat.is_valid()) {
 
-		Ref<Texture> albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO);
+		Ref<Texture> albedo_tex = mat->get_texture(SpatialMaterial::TEXTURE_ALBEDO);
 
 		Image img_albedo;
 		if (albedo_tex.is_valid()) {
@@ -942,7 +942,7 @@ GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_mater
 
 		mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo());
 
-		Ref<ImageTexture> emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION);
+		Ref<ImageTexture> emission_tex = mat->get_texture(SpatialMaterial::TEXTURE_EMISSION);
 
 		Color emission_col = mat->get_emission();
 		emission_col.r *= mat->get_emission_energy();
@@ -1365,11 +1365,11 @@ void GIProbe::_create_debug_mesh(Baker *p_baker) {
 	}
 
 	{
-		Ref<FixedSpatialMaterial> fsm;
+		Ref<SpatialMaterial> fsm;
 		fsm.instance();
-		fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
-		fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-		fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
+		fsm->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+		fsm->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+		fsm->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
 		fsm->set_albedo(Color(1, 1, 1, 1));
 
 		mesh->surface_set_material(0, fsm);

+ 1184 - 363
scene/3d/particles.cpp

@@ -30,532 +30,1353 @@
 #include "scene/resources/surface_tool.h"
 #include "servers/visual_server.h"
 
-#if 0
-/*
-static const char* _var_names[Particles::VAR_MAX]={
-	"vars/lifetime",
-	"vars/spread",
-	"vars/gravity",
-	"vars/linear_vel",
-	"vars/angular_vel",
-	"vars/linear_accel",
-	"vars/radial_accel",
-	"vars/tan_accel",
-	"vars/initial_size",
-	"vars/final_size",
-	"vars/initial_angle",
-	"vars/height",
-	"vars/height_speed_scale",
-};
-*/
-static const char* _rand_names[Particles::VAR_MAX]={
-	"rand/lifetime",
-	"rand/spread",
-	"rand/gravity",
-	"rand/linear_vel",
-	"rand/angular_vel",
-	"rand/linear_accel",
-	"rand/radial_accel",
-	"rand/tan_accel",
-	"rand/damping",
-	"rand/initial_size",
-	"rand/final_size",
-	"rand/initial_angle",
-	"rand/height",
-	"rand/height_speed_scale",
-};
-
-static const Particles::Variable _var_indices[Particles::VAR_MAX]={
-	Particles::VAR_LIFETIME,
-	Particles::VAR_SPREAD,
-	Particles::VAR_GRAVITY,
-	Particles::VAR_LINEAR_VELOCITY,
-	Particles::VAR_ANGULAR_VELOCITY,
-	Particles::VAR_LINEAR_ACCELERATION,
-	Particles::VAR_DRAG,
-	Particles::VAR_TANGENTIAL_ACCELERATION,
-	Particles::VAR_DAMPING,
-	Particles::VAR_INITIAL_SIZE,
-	Particles::VAR_FINAL_SIZE,
-	Particles::VAR_INITIAL_ANGLE,
-	Particles::VAR_HEIGHT,
-	Particles::VAR_HEIGHT_SPEED_SCALE,
-};
-
-
-
-AABB Particles::get_aabb() const {
-
-	return AABB( Vector3(-1,-1,-1), Vector3(2, 2, 2 ) );
+Rect3 Particles::get_aabb() const {
+
+	return Rect3();
 }
 PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const {
 
 	return PoolVector<Face3>();
 }
 
+void Particles::set_emitting(bool p_emitting) {
+
+	emitting = p_emitting;
+	VS::get_singleton()->particles_set_emitting(particles, emitting);
+}
 
 void Particles::set_amount(int p_amount) {
 
-	ERR_FAIL_INDEX(p_amount,1024);
-	amount=p_amount;
-	VisualServer::get_singleton()->particles_set_amount(particles,p_amount);
+	amount = p_amount;
+	VS::get_singleton()->particles_set_amount(particles, amount);
 }
-int Particles::get_amount() const {
+void Particles::set_lifetime(float p_lifetime) {
 
-	return amount;
+	lifetime = p_lifetime;
+	VS::get_singleton()->particles_set_lifetime(particles, lifetime);
 }
+void Particles::set_pre_process_time(float p_time) {
 
-void Particles::set_emitting(bool p_emitting) {
+	pre_process_time = p_time;
+	VS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
+}
+void Particles::set_explosiveness_ratio(float p_ratio) {
+
+	explosiveness_ratio = p_ratio;
+	VS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
+}
+void Particles::set_randomness_ratio(float p_ratio) {
 
-	emitting=p_emitting;
-	VisualServer::get_singleton()->particles_set_emitting(particles,p_emitting);
+	randomness_ratio = p_ratio;
+	VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
+}
+void Particles::set_custom_aabb(const Rect3 &p_aabb) {
+
+	custom_aabb = p_aabb;
+	VS::get_singleton()->particles_set_custom_aabb(particles, custom_aabb);
+}
+void Particles::set_gravity(const Vector3 &p_gravity) {
+
+	gravity = p_gravity;
+	VS::get_singleton()->particles_set_gravity(particles, gravity);
+}
+void Particles::set_use_local_coordinates(bool p_enable) {
 
-	setup_timer();
+	local_coords = p_enable;
+	VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
 }
+void Particles::set_process_material(const Ref<Material> &p_material) {
+
+	process_material = p_material;
+	RID material_rid;
+	if (process_material.is_valid())
+		material_rid = process_material->get_rid();
+	VS::get_singleton()->particles_set_process_material(particles, material_rid);
+}
+
 bool Particles::is_emitting() const {
 
 	return emitting;
 }
+int Particles::get_amount() const {
 
-void Particles::set_visibility_aabb(const AABB& p_aabb) {
+	return amount;
+}
+float Particles::get_lifetime() const {
+
+	return lifetime;
+}
+float Particles::get_pre_process_time() const {
+
+	return pre_process_time;
+}
+float Particles::get_explosiveness_ratio() const {
 
-	visibility_aabb=p_aabb;
-	VisualServer::get_singleton()->particles_set_visibility_aabb(particles,p_aabb);
-	update_gizmo();
+	return explosiveness_ratio;
+}
+float Particles::get_randomness_ratio() const {
 
+	return randomness_ratio;
 }
-AABB Particles::get_visibility_aabb() const {
+Rect3 Particles::get_custom_aabb() const {
 
-	return visibility_aabb;
+	return custom_aabb;
 }
+Vector3 Particles::get_gravity() const {
 
+	return gravity;
+}
+bool Particles::get_use_local_coordinates() const {
 
-void Particles::set_emission_points(const PoolVector<Vector3>& p_points) {
+	return local_coords;
+}
+Ref<Material> Particles::get_process_material() const {
 
-	using_points = p_points.size();
-	VisualServer::get_singleton()->particles_set_emission_points(particles,p_points);
+	return process_material;
 }
 
-PoolVector<Vector3> Particles::get_emission_points() const {
+void Particles::set_draw_order(DrawOrder p_order) {
 
-	if (!using_points)
-		return PoolVector<Vector3>();
+	draw_order = p_order;
+	VS::get_singleton()->particles_set_draw_order(particles, VS::ParticlesDrawOrder(p_order));
+}
 
-	return VisualServer::get_singleton()->particles_get_emission_points(particles);
+Particles::DrawOrder Particles::get_draw_order() const {
 
+	return draw_order;
 }
 
-void Particles::set_emission_half_extents(const Vector3& p_half_extents) {
+void Particles::set_draw_passes(int p_count) {
 
-	emission_half_extents=p_half_extents;
-	VisualServer::get_singleton()->particles_set_emission_half_extents(particles,p_half_extents);
+	ERR_FAIL_COND(p_count < 1);
+	draw_passes.resize(p_count);
+	VS::get_singleton()->particles_set_draw_passes(particles, p_count);
+	_change_notify();
+}
+int Particles::get_draw_passes() const {
 
+	return draw_passes.size();
 }
 
-Vector3 Particles::get_emission_half_extents() const {
+void Particles::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
 
-	return emission_half_extents;
+	ERR_FAIL_INDEX(p_pass, draw_passes.size());
+
+	draw_passes[p_pass] = p_mesh;
+
+	RID mesh_rid;
+	if (p_mesh.is_valid())
+		mesh_rid = p_mesh->get_rid();
+
+	VS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
 }
 
-void Particles::set_emission_base_velocity(const Vector3& p_base_velocity) {
+Ref<Mesh> Particles::get_draw_pass_mesh(int p_pass) const {
 
-	emission_base_velocity=p_base_velocity;
-	VisualServer::get_singleton()->particles_set_emission_base_velocity(particles,p_base_velocity);
+	ERR_FAIL_INDEX_V(p_pass, draw_passes.size(), Ref<Mesh>());
 
+	return draw_passes[p_pass];
 }
 
-Vector3 Particles::get_emission_base_velocity() const {
+void Particles::set_fixed_fps(int p_count) {
+	fixed_fps = p_count;
+	VS::get_singleton()->particles_set_fixed_fps(particles, p_count);
+}
 
-	return emission_base_velocity;
+int Particles::get_fixed_fps() const {
+	return fixed_fps;
 }
 
-void Particles::set_gravity_normal(const Vector3& p_normal)  {
+void Particles::set_fractional_delta(bool p_enable) {
+	fractional_delta = p_enable;
+	VS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
+}
 
-	gravity_normal=p_normal;
-	VisualServer::get_singleton()->particles_set_gravity_normal(particles,p_normal);
+bool Particles::get_fractional_delta() const {
+	return fractional_delta;
+}
+
+void Particles::_validate_property(PropertyInfo &property) const {
+
+	if (property.name.begins_with("draw_pass_")) {
+		int index = property.name.get_slicec('_', 2).to_int() - 1;
+		if (index >= draw_passes.size()) {
+			property.usage = 0;
+			return;
+		}
+	}
 }
 
-Vector3 Particles::get_gravity_normal() const {
+void Particles::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles::set_emitting);
+	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles::set_amount);
+	ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles::set_lifetime);
+	ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles::set_pre_process_time);
+	ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles::set_explosiveness_ratio);
+	ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles::set_randomness_ratio);
+	ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &Particles::set_custom_aabb);
+	ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &Particles::set_gravity);
+	ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles::set_use_local_coordinates);
+	ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles::set_fixed_fps);
+	ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles::set_fractional_delta);
+	ClassDB::bind_method(D_METHOD("set_process_material", "material:Material"), &Particles::set_process_material);
+
+	ClassDB::bind_method(D_METHOD("is_emitting"), &Particles::is_emitting);
+	ClassDB::bind_method(D_METHOD("get_amount"), &Particles::get_amount);
+	ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles::get_lifetime);
+	ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles::get_pre_process_time);
+	ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles::get_explosiveness_ratio);
+	ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles::get_randomness_ratio);
+	ClassDB::bind_method(D_METHOD("get_custom_aabb"), &Particles::get_custom_aabb);
+	ClassDB::bind_method(D_METHOD("get_gravity"), &Particles::get_gravity);
+	ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles::get_use_local_coordinates);
+	ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles::get_fixed_fps);
+	ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles::get_fractional_delta);
+	ClassDB::bind_method(D_METHOD("get_process_material:Material"), &Particles::get_process_material);
+
+	ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles::set_draw_order);
+
+	ClassDB::bind_method(D_METHOD("get_draw_order"), &Particles::get_draw_order);
+
+	ClassDB::bind_method(D_METHOD("set_draw_passes", "passes"), &Particles::set_draw_passes);
+	ClassDB::bind_method(D_METHOD("set_draw_pass_mesh", "pass", "mesh:Mesh"), &Particles::set_draw_pass_mesh);
+
+	ClassDB::bind_method(D_METHOD("get_draw_passes"), &Particles::get_draw_passes);
+	ClassDB::bind_method(D_METHOD("get_draw_pass_mesh:Mesh", "pass"), &Particles::get_draw_pass_mesh);
+
+	ADD_GROUP("Parameters", "");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
+	ADD_PROPERTY(PropertyInfo(Variant::RECT3, "custom_aabb"), "set_custom_aabb", "get_custom_aabb");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ParticlesMaterial,ShaderMaterial"), "set_process_material", "get_process_material");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
+	ADD_GROUP("Draw Passes", "draw_");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes");
+	for (int i = 0; i < MAX_DRAW_PASSES; i++) {
+
+		ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "draw_pass_" + itos(i + 1), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_draw_pass_mesh", "get_draw_pass_mesh", i);
+	}
+
+	BIND_CONSTANT(DRAW_ORDER_INDEX);
+	BIND_CONSTANT(DRAW_ORDER_LIFETIME);
+	BIND_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
+	BIND_CONSTANT(MAX_DRAW_PASSES);
+}
 
-	return gravity_normal;
+Particles::Particles() {
 
+	particles = VS::get_singleton()->particles_create();
+	set_base(particles);
+	set_emitting(true);
+	set_amount(100);
+	set_lifetime(1);
+	set_fixed_fps(0);
+	set_fractional_delta(true);
+	set_pre_process_time(0);
+	set_explosiveness_ratio(0);
+	set_randomness_ratio(0);
+	set_gravity(Vector3(0, -9.8, 0));
+	set_use_local_coordinates(true);
+	set_draw_passes(1);
 }
 
-void Particles::set_variable(Variable p_variable,float p_value) {
+Particles::~Particles() {
 
-	ERR_FAIL_INDEX(p_variable,VAR_MAX);
-	var[p_variable]=p_value;
-	VisualServer::get_singleton()->particles_set_variable(particles,(VS::ParticleVariable)p_variable,p_value);
-	if (p_variable==VAR_SPREAD)
-		update_gizmo();
+	VS::get_singleton()->free(particles);
 }
 
-float Particles::get_variable(Variable p_variable) const {
+//////////////////////////////////////
 
-	ERR_FAIL_INDEX_V(p_variable,VAR_MAX,-1);
-	return var[p_variable];
+Mutex *ParticlesMaterial::material_mutex = NULL;
+SelfList<ParticlesMaterial>::List ParticlesMaterial::dirty_materials;
+Map<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData> ParticlesMaterial::shader_map;
+ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = NULL;
 
+void ParticlesMaterial::init_shaders() {
+
+#ifndef NO_THREADS
+	material_mutex = Mutex::create();
+#endif
+
+	shader_names = memnew(ShaderNames);
+
+	shader_names->spread = "spread";
+	shader_names->flatness = "flatness";
+	shader_names->initial_linear_velocity = "initial_linear_velocity";
+	shader_names->initial_angle = "initial_angle";
+	shader_names->angular_velocity = "angular_velocity";
+	shader_names->orbit_velocity = "orbit_velocity";
+	shader_names->linear_accel = "linear_accel";
+	shader_names->radial_accel = "radial_accel";
+	shader_names->tangent_accel = "tangent_accel";
+	shader_names->damping = "damping";
+	shader_names->scale = "scale";
+	shader_names->hue_variation = "hue_variation";
+	shader_names->anim_speed = "anim_speed";
+	shader_names->anim_offset = "anim_offset";
+
+	shader_names->initial_linear_velocity = "initial_linear_velocity_random";
+	shader_names->initial_angle_random = "initial_angle_random";
+	shader_names->angular_velocity_random = "angular_velocity_random";
+	shader_names->orbit_velocity_random = "orbit_velocity_random";
+	shader_names->linear_accel_random = "linear_accel_random";
+	shader_names->radial_accel_random = "radial_accel_random";
+	shader_names->tangent_accel_random = "tangent_accel_random";
+	shader_names->damping_random = "damping_random";
+	shader_names->scale_random = "scale_random";
+	shader_names->hue_variation_random = "hue_variation_random";
+	shader_names->anim_speed_random = "anim_speed_random";
+	shader_names->anim_offset_random = "anim_offset_random";
+
+	shader_names->angle_texture = "angle_texture";
+	shader_names->angular_velocity_texture = "angular_velocity_texture";
+	shader_names->orbit_velocity_texture = "orbit_velocity_texture";
+	shader_names->linear_accel_texture = "linear_accel_texture";
+	shader_names->radial_accel_texture = "radial_accel_texture";
+	shader_names->tangent_accel_texture = "tangent_accel_texture";
+	shader_names->damping_texture = "damping_texture";
+	shader_names->scale_texture = "scale_texture";
+	shader_names->hue_variation_texture = "hue_variation_texture";
+	shader_names->anim_speed_texture = "anim_speed_texture";
+	shader_names->anim_offset_texture = "anim_offset_texture";
+
+	shader_names->color = "color_value";
+	shader_names->color_ramp = "color_ramp";
+
+	shader_names->emission_sphere_radius = "emission_sphere_radius";
+	shader_names->emission_box_extents = "emission_box_extents";
+	shader_names->emission_texture_point_count = "emission_texture_point_count";
+	shader_names->emission_texture_points = "emission_texture_points";
+	shader_names->emission_texture_normal = "emission_texture_normal";
+
+	shader_names->trail_divisor = "trail_divisor";
+	shader_names->trail_size_modifier = "trail_size_modifier";
+	shader_names->trail_color_modifier = "trail_color_modifier";
 }
 
-void Particles::set_randomness(Variable p_variable,float p_randomness) {
+void ParticlesMaterial::finish_shaders() {
 
-	ERR_FAIL_INDEX(p_variable,VAR_MAX);
-	var_random[p_variable]=p_randomness;
-	VisualServer::get_singleton()->particles_set_randomness(particles,(VS::ParticleVariable)p_variable,p_randomness);
+#ifndef NO_THREADS
+	memdelete(material_mutex);
+#endif
 
+	memdelete(shader_names);
 }
-float Particles::get_randomness(Variable p_variable) const {
 
-	ERR_FAIL_INDEX_V(p_variable,VAR_MAX,-1);
-	return var_random[p_variable];
+void ParticlesMaterial::_update_shader() {
+
+	print_line("updating shader");
+
+	dirty_materials.remove(&element);
+
+	MaterialKey mk = _compute_key();
+	if (mk.key == current_key.key)
+		return; //no update required in the end
+
+	if (shader_map.has(current_key)) {
+		shader_map[current_key].users--;
+		if (shader_map[current_key].users == 0) {
+			//deallocate shader, as it's no longer in use
+			VS::get_singleton()->free(shader_map[current_key].shader);
+			shader_map.erase(current_key);
+		}
+	}
 
+	current_key = mk;
+
+	if (shader_map.has(mk)) {
+
+		VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
+		shader_map[mk].users++;
+		return;
+	}
+
+	//must create a shader!
+
+	String code = "shader_type particles;\n";
+
+	code += "uniform float spread;\n";
+	code += "uniform float flatness;\n";
+	code += "uniform float initial_linear_velocity;\n";
+	code += "uniform float initial_angle;\n";
+	code += "uniform float angular_velocity;\n";
+	code += "uniform float orbit_velocity;\n";
+	code += "uniform float linear_accel;\n";
+	code += "uniform float radial_accel;\n";
+	code += "uniform float tangent_accel;\n";
+	code += "uniform float damping;\n";
+	code += "uniform float scale;\n";
+	code += "uniform float hue_variation;\n";
+	code += "uniform float anim_speed;\n";
+	code += "uniform float anim_offset;\n";
+
+	code += "uniform float initial_linear_velocity_random;\n";
+	code += "uniform float initial_angle_random;\n";
+	code += "uniform float angular_velocity_random;\n";
+	code += "uniform float orbit_velocity_random;\n";
+	code += "uniform float linear_accel_random;\n";
+	code += "uniform float radial_accel_random;\n";
+	code += "uniform float tangent_accel_random;\n";
+	code += "uniform float damping_random;\n";
+	code += "uniform float scale_random;\n";
+	code += "uniform float hue_variation_random;\n";
+	code += "uniform float anim_speed_random;\n";
+	code += "uniform float anim_offset_random;\n";
+
+	code += "uniform vec4 color_value : hint_color;\n";
+
+	code += "uniform int trail_divisor;\n";
+
+	if (color_ramp.is_valid())
+		code += "uniform sampler2D color_ramp;\n";
+
+	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
+		code += "uniform sampler2D linear_velocity_texture;\n";
+	if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid())
+		code += "uniform sampler2D orbit_velocity_texture;\n";
+	if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid())
+		code += "uniform sampler2D angular_velocity_texture;\n";
+	if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid())
+		code += "uniform sampler2D linear_accel_texture;\n";
+	if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid())
+		code += "uniform sampler2D radial_accel_texture;\n";
+	if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid())
+		code += "uniform sampler2D tangent_accel_texture;\n";
+	if (tex_parameters[PARAM_DAMPING].is_valid())
+		code += "uniform sampler2D damping_texture;\n";
+	if (tex_parameters[PARAM_ANGLE].is_valid())
+		code += "uniform sampler2D angle_texture;\n";
+	if (tex_parameters[PARAM_SCALE].is_valid())
+		code += "uniform sampler2D scale_texture;\n";
+	if (tex_parameters[PARAM_HUE_VARIATION].is_valid())
+		code += "uniform sampler2D hue_variation_texture;\n";
+	if (tex_parameters[PARAM_ANIM_SPEED].is_valid())
+		code += "uniform sampler2D anim_speed_texture;\n";
+	if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
+		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()) {
+		code += "uniform sampler2D trail_size_modifier;\n";
+	}
+
+	if (trail_color_modifier.is_valid()) {
+		code += "uniform sampler2D trail_color_modifier;\n";
+	}
+
+	//need a random function
+	code += "\n\n";
+	code += "float rand_from_seed(inout uint seed) {\n";
+	code += "   int k;\n";
+	code += "   int s = int(seed);\n";
+	code += "   if (s == 0)\n";
+	code += "	s = 305420679;\n";
+	code += "   k = s / 127773;\n";
+	code += "   s = 16807 * (s - k * 127773) - 2836 * k;\n";
+	code += "   if (s < 0)\n";
+	code += "	s += 2147483647;\n";
+	code += "   seed = uint(s);\n";
+	code += "   return float(seed % uint(65536))/65535.0;\n";
+	code += "}\n";
+	//improve seed quality
+	code += "uint hash(uint x) {\n";
+	code += "   x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
+	code += "   x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
+	code += "   x = (x >> uint(16)) ^ x;\n";
+	code += "   return x;\n";
+	code += "}\n";
+	code += "void vertex() {\n\n";
+	code += "\n";
+
+	code += " uint base_number=NUMBER/uint(trail_divisor);\n";
+	code += " uint alt_seed=hash(base_number+uint(1));\n";
+	code += " float angle_rand=rand_from_seed(alt_seed);\n";
+	code += " float scale_rand=rand_from_seed(alt_seed);\n";
+	code += " float hue_rot_rand=rand_from_seed(alt_seed);\n";
+	code += " float anim_offset_rand=rand_from_seed(alt_seed);\n";
+	code += "\n";
+	code += "\n";
+	code += "\n";
+	code += "\n";
+	code += " if (RESTART) {\n";
+
+	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
+		code += "    float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(0.0,0.0),0.0).r;\n";
+	else
+		code += "    float tex_linear_velocity = 0.0;\n";
+
+	if (tex_parameters[PARAM_ANGLE].is_valid())
+		code += "    float tex_angle = textureLod(angle_texture,vec2(0.0,0.0),0.0).r;\n";
+	else
+		code += "    float tex_angle = 0.0;\n";
+
+	if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
+		code += "    float tex_anim_offset = textureLod(anim_offset_texture,vec2(0.0,0.0),0.0).r;\n";
+	else
+		code += "    float tex_anim_offset = 0.0;\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 += "    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 += "    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 += "    CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle
+	code += "    CUSTOM.y=0.0;\n"; //phase
+	code += "    CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random);\n"; //animation offset (0-1)
+	switch (emission_shape) {
+		case EMISSION_SHAPE_POINT: {
+			//do none
+		} break;
+		case EMISSION_SHAPE_SPHERE: {
+			code += "    TRANSFORM[3].xyz = normalize(vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0 ))*emission_sphere_radius;\n";
+		} break;
+		case EMISSION_SHAPE_BOX: {
+			code += "    TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0)*emission_box_extents;\n";
+		} break;
+		case EMISSION_SHAPE_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 += "    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) {
+				code += "    vec3 normal = texelFetch(emission_texture_normal, 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 tangent = normalize(cross(v0, normal));\n";
+				code += "    vec3 bitangent = normalize(cross(tangent, normal));\n";
+				code += "    VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n";
+			}
+		} break;
+	}
+	code += "    VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n";
+	code += "    TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
+
+	code += " } else {\n";
+
+	code += "    CUSTOM.y+=DELTA/LIFETIME;\n";
+	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
+		code += "    float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_linear_velocity = 0.0;\n";
+
+	if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid())
+		code += "    float tex_orbit_velocity = textureLod(orbit_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_orbit_velocity = 0.0;\n";
+
+	if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid())
+		code += "    float tex_angular_velocity = textureLod(angular_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_angular_velocity = 0.0;\n";
+
+	if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid())
+		code += "    float tex_linear_accel = textureLod(linear_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_linear_accel = 0.0;\n";
+
+	if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid())
+		code += "    float tex_radial_accel = textureLod(radial_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_radial_accel = 0.0;\n";
+
+	if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid())
+		code += "    float tex_tangent_accel = textureLod(tangent_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_tangent_accel = 0.0;\n";
+
+	if (tex_parameters[PARAM_DAMPING].is_valid())
+		code += "    float tex_damping = textureLod(damping_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_damping = 0.0;\n";
+
+	if (tex_parameters[PARAM_ANGLE].is_valid())
+		code += "    float tex_angle = textureLod(angle_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_angle = 0.0;\n";
+
+	if (tex_parameters[PARAM_ANIM_SPEED].is_valid())
+		code += "    float tex_anim_speed = textureLod(anim_speed_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_anim_speed = 0.0;\n";
+
+	if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
+		code += "    float tex_anim_offset = textureLod(anim_offset_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += "    float tex_anim_offset = 0.0;\n";
+
+	code += "    vec3 force = vec3(0.0); \n";
+	code += "    vec3 pos = TRANSFORM[3].xyz; \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 += "    //apply radial acceleration\n";
+	code += "    vec3 org = vec3(0.0);\n";
+	code += "   // if (!p_system->local_coordinates)\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 += "    //apply tangential acceleration;\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 += "    VELOCITY+=force * DELTA;\n";
+	if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
+		code += "    VELOCITY=normalize(VELOCITY)*tex_linear_velocity;\n";
+	code += "    if (damping+tex_damping>0.0) {\n";
+	code += "    \n";
+	code += "    	float v = length(VELOCITY);\n";
+	code += "    	float damp = (damping+tex_damping)*mix(1.0,rand_from_seed(alt_seed),damping_random);\n";
+	code += "    	v -= damp * DELTA;\n";
+	code += "    	if (v<0.0) {\n";
+	code += "    		VELOCITY=vec3(0.0);\n";
+	code += "    	} else {\n";
+	code += "    		VELOCITY=normalize(VELOCITY) * v;\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 += "    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 += "    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 += "  }\n";
+	//apply color
+	//apply hue rotation
+	if (tex_parameters[PARAM_SCALE].is_valid())
+		code += " float tex_scale = textureLod(scale_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += " float tex_scale = 1.0;\n";
+
+	if (tex_parameters[PARAM_HUE_VARIATION].is_valid())
+		code += " float tex_hue_variation = textureLod(hue_variation_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
+	else
+		code += " float tex_hue_variation = 0.0;\n";
+
+	code += "  float hue_rot_angle = (hue_variation+tex_hue_variation)*3.1416*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n";
+	code += "  float hue_rot_c = cos(hue_rot_angle);\n";
+	code += "  float hue_rot_s = sin(hue_rot_angle);\n";
+	code += "  mat4 hue_rot_mat =	mat4( vec4(0.299,  0.587,  0.114, 0.0),\n";
+	code += "			    	 vec4(0.299,  0.587,  0.114, 0.0),\n";
+	code += "			    	 vec4(0.299,  0.587,  0.114, 0.0),\n";
+	code += "				 vec4(0.000,  0.000,  0.000, 1.0)) +\n";
+	code += "	\n";
+	code += "			mat4(	 vec4(0.701, -0.587, -0.114, 0.0),\n";
+	code += "				vec4(-0.299,  0.413, -0.114, 0.0),\n";
+	code += "				vec4(-0.300, -0.588,  0.886, 0.0),\n";
+	code += "			 	 vec4(0.000,  0.000,  0.000, 0.0)) * hue_rot_c +\n";
+	code += "\n";
+	code += "			mat4(	 vec4(0.168,  0.330, -0.497, 0.0),\n";
+	code += "				vec4(-0.328,  0.035,  0.292, 0.0),\n";
+	code += "				 vec4(1.250, -1.050, -0.203, 0.0),\n";
+	code += "				 vec4(0.000,  0.000,  0.000, 0.0)) * hue_rot_s;\n";
+	if (color_ramp.is_valid()) {
+		code += " COLOR = textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0) * hue_rot_mat;\n";
+	} else {
+		code += " COLOR = color_value * hue_rot_mat;\n";
+	}
+	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 += "\n";
+	//orient particle Y towards 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 (TRANSFORM[1].xyz==normalize(TRANSFORM[0].xyz)) {\n";
+		code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
+		code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
+		code += " } else {\n";
+		code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
+		code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
+		code += " }\n";
+	} else {
+		code += "\tTRANSFORM[0].xyz=normalize(TRANSFORM[0].xyz);\n";
+		code += "\tTRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);\n";
+		code += "\tTRANSFORM[2].xyz=normalize(TRANSFORM[2].xyz);\n";
+	}
+	//turn particle by rotation in 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";
+	}
+	//scale by scale
+	code += " float base_scale=mix(scale*tex_scale,1.0,scale_random*scale_rand);\n";
+	if (trail_size_modifier.is_valid()) {
+		code += "if (trail_divisor>1) { base_scale*=textureLod(trail_size_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0).r; } \n";
+	}
+
+	code += " TRANSFORM[0].xyz*=base_scale;\n";
+	code += " TRANSFORM[1].xyz*=base_scale;\n";
+	code += " TRANSFORM[2].xyz*=base_scale;\n";
+	code += "}\n";
+	code += "\n";
+
+	ShaderData shader_data;
+	shader_data.shader = VS::get_singleton()->shader_create();
+	shader_data.users = 1;
+
+	VS::get_singleton()->shader_set_code(shader_data.shader, code);
+
+	shader_map[mk] = shader_data;
+
+	VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
 }
 
-void Particles::set_color_phase_pos(int p_phase, float p_pos) {
+void ParticlesMaterial::flush_changes() {
 
-	ERR_FAIL_INDEX(p_phase,VS::MAX_PARTICLE_COLOR_PHASES);
-	color_phase[p_phase].pos=p_pos;
-	VisualServer::get_singleton()->particles_set_color_phase_pos(particles,p_phase,p_pos);
+	if (material_mutex)
+		material_mutex->lock();
 
+	while (dirty_materials.first()) {
+
+		dirty_materials.first()->self()->_update_shader();
+	}
+
+	if (material_mutex)
+		material_mutex->unlock();
 }
-float Particles::get_color_phase_pos(int p_phase) const {
 
-	ERR_FAIL_INDEX_V(p_phase,VS::MAX_PARTICLE_COLOR_PHASES,-1);
-	return color_phase[p_phase].pos;
+void ParticlesMaterial::_queue_shader_change() {
+
+	if (material_mutex)
+		material_mutex->lock();
+
+	print_line("queuing change");
+	if (!element.in_list()) {
+		print_line("not in list, adding");
+		dirty_materials.add(&element);
+	}
+
+	if (material_mutex)
+		material_mutex->unlock();
 }
 
-void Particles::set_color_phase_color(int p_phase, const Color& p_color) {
+bool ParticlesMaterial::_is_shader_dirty() const {
+
+	bool dirty = false;
+
+	if (material_mutex)
+		material_mutex->lock();
+
+	dirty = element.in_list();
 
-	ERR_FAIL_INDEX(p_phase,VS::MAX_PARTICLE_COLOR_PHASES);
-	color_phase[p_phase].color=p_color;
-	VisualServer::get_singleton()->particles_set_color_phase_color(particles,p_phase,p_color);
+	if (material_mutex)
+		material_mutex->unlock();
 
+	return dirty;
 }
-Color Particles::get_color_phase_color(int p_phase) const {
 
-	ERR_FAIL_INDEX_V(p_phase,VS::MAX_PARTICLE_COLOR_PHASES,Color());
-	return color_phase[p_phase].color;
+void ParticlesMaterial::set_spread(float p_spread) {
 
+	spread = p_spread;
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread);
 }
 
-void Particles::set_material(const Ref<Material>& p_material) {
+float ParticlesMaterial::get_spread() const {
 
-	material=p_material;
-	if(material.is_null()) {
-		VisualServer::get_singleton()->particles_set_material(particles,RID());
-	} else {
-		VisualServer::get_singleton()->particles_set_material(particles,material->get_rid());
+	return spread;
+}
+
+void ParticlesMaterial::set_flatness(float p_flatness) {
+
+	flatness = p_flatness;
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness);
+}
+float ParticlesMaterial::get_flatness() const {
+
+	return flatness;
+}
+
+void ParticlesMaterial::set_param(Parameter p_param, float p_value) {
+
+	ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+	parameters[p_param] = p_value;
+
+	switch (p_param) {
+		case PARAM_INITIAL_LINEAR_VELOCITY: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity, p_value);
+		} break;
+		case PARAM_ANGULAR_VELOCITY: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity, p_value);
+		} break;
+		case PARAM_ORBIT_VELOCITY: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity, p_value);
+		} break;
+		case PARAM_LINEAR_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel, p_value);
+		} break;
+		case PARAM_RADIAL_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel, p_value);
+		} break;
+		case PARAM_TANGENTIAL_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel, p_value);
+		} break;
+		case PARAM_DAMPING: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping, p_value);
+		} break;
+		case PARAM_ANGLE: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle, p_value);
+		} break;
+		case PARAM_SCALE: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale, p_value);
+		} break;
+		case PARAM_HUE_VARIATION: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation, p_value);
+		} break;
+		case PARAM_ANIM_SPEED: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed, p_value);
+		} break;
+		case PARAM_ANIM_OFFSET: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value);
+		} break;
+		case PARAM_MAX: {
+		};
 	}
+}
+float ParticlesMaterial::get_param(Parameter p_param) const {
+
+	ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
 
+	return parameters[p_param];
 }
 
-void Particles::setup_timer() {
+void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) {
+
+	ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+	randomness[p_param] = p_value;
+
+	switch (p_param) {
+		case PARAM_INITIAL_LINEAR_VELOCITY: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_random, p_value);
+		} break;
+		case PARAM_ANGULAR_VELOCITY: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_random, p_value);
+		} break;
+		case PARAM_ORBIT_VELOCITY: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_random, p_value);
+		} break;
+		case PARAM_LINEAR_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_random, p_value);
+		} break;
+		case PARAM_RADIAL_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_random, p_value);
+		} break;
+		case PARAM_TANGENTIAL_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_random, p_value);
+		} break;
+		case PARAM_DAMPING: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_random, p_value);
+		} break;
+		case PARAM_ANGLE: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_random, p_value);
+		} break;
+		case PARAM_SCALE: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_random, p_value);
+		} break;
+		case PARAM_HUE_VARIATION: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_random, p_value);
+		} break;
+		case PARAM_ANIM_SPEED: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_random, p_value);
+		} break;
+		case PARAM_ANIM_OFFSET: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value);
+		} break;
+		case PARAM_MAX: {
+		};
+	}
+}
+float ParticlesMaterial::get_param_randomness(Parameter p_param) const {
 
-	if (emitting && emit_timeout > 0) {
+	ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
 
-		timer->set_wait_time(emit_timeout);
-		timer->start();
-		timer->set_one_shot(true);
-	};
-};
+	return randomness[p_param];
+}
 
-void Particles::set_emit_timeout(float p_timeout) {
+static void _adjust_curve_range(const Ref<Texture> &p_texture, float p_min, float p_max) {
 
-	emit_timeout = p_timeout;
-	setup_timer();
-};
+	Ref<CurveTexture> curve = p_texture;
+	if (!curve.is_valid())
+		return;
 
-float Particles::get_emit_timeout() const {
+	if (curve->get_max() == 1.0) {
+		curve->set_max(p_max);
+	}
+	if (curve->get_min() == 0.0) {
+		curve->set_min(p_min);
+	}
+}
 
-	return emit_timeout;
-};
+void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> &p_texture) {
+
+	ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+	tex_parameters[p_param] = p_texture;
+
+	switch (p_param) {
+		case PARAM_INITIAL_LINEAR_VELOCITY: {
+			//do none for this one
+		} break;
+		case PARAM_ANGULAR_VELOCITY: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture);
+			_adjust_curve_range(p_texture, -360, 360);
+		} break;
+		case PARAM_ORBIT_VELOCITY: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture);
+			_adjust_curve_range(p_texture, -500, 500);
+		} break;
+		case PARAM_LINEAR_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture);
+			_adjust_curve_range(p_texture, -200, 200);
+		} break;
+		case PARAM_RADIAL_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture);
+			_adjust_curve_range(p_texture, -200, 200);
+		} break;
+		case PARAM_TANGENTIAL_ACCEL: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture);
+			_adjust_curve_range(p_texture, -200, 200);
+		} break;
+		case PARAM_DAMPING: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture);
+			_adjust_curve_range(p_texture, 0, 100);
+		} break;
+		case PARAM_ANGLE: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture);
+			_adjust_curve_range(p_texture, -360, 360);
+		} break;
+		case PARAM_SCALE: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture);
+
+			Ref<CurveTexture> curve = p_texture;
+			if (curve.is_valid()) {
+				if (curve->get_min() == 0 && curve->get_max() == 1) {
+
+					curve->set_max(32);
+					PoolVector<Vector2> points;
+					points.push_back(Vector2(0, 1));
+					points.push_back(Vector2(1, 1));
+					curve->set_points(points);
+				}
+			}
 
+		} break;
+		case PARAM_HUE_VARIATION: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture);
+			_adjust_curve_range(p_texture, -1, 1);
+		} break;
+		case PARAM_ANIM_SPEED: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture);
+			_adjust_curve_range(p_texture, 0, 200);
+		} break;
+		case PARAM_ANIM_OFFSET: {
+			VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture);
+		} break;
+		case PARAM_MAX: {
+		};
+	}
+
+	_queue_shader_change();
+}
+Ref<Texture> ParticlesMaterial::get_param_texture(Parameter p_param) const {
 
-Ref<Material> Particles::get_material() const {
+	ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Texture>());
 
-	return material;
+	return tex_parameters[p_param];
 }
 
-void Particles::set_height_from_velocity(bool p_enable) {
+void ParticlesMaterial::set_color(const Color &p_color) {
 
-	height_from_velocity=p_enable;
-	VisualServer::get_singleton()->particles_set_height_from_velocity(particles,height_from_velocity);
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color);
+	color = p_color;
 }
 
-bool Particles::has_height_from_velocity() const {
+Color ParticlesMaterial::get_color() const {
 
-	return height_from_velocity;
+	return color;
 }
 
-void Particles::set_color_phases(int p_phases) {
+void ParticlesMaterial::set_color_ramp(const Ref<Texture> &p_texture) {
 
-	color_phase_count=p_phases;
-	VisualServer::get_singleton()->particles_set_color_phases(particles,p_phases);
+	color_ramp = p_texture;
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture);
+	_queue_shader_change();
+	_change_notify();
 }
 
-int Particles::get_color_phases() const{
+Ref<Texture> ParticlesMaterial::get_color_ramp() const {
 
-	return color_phase_count;
+	return color_ramp;
 }
 
-bool Particles::_can_gizmo_scale() const {
+void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) {
+	ERR_FAIL_INDEX(p_flag, FLAG_MAX);
+	flags[p_flag] = p_enable;
+	_queue_shader_change();
+}
 
-	return false;
+bool ParticlesMaterial::get_flag(Flags p_flag) const {
+	ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+	return flags[p_flag];
 }
 
-void Particles::set_use_local_coordinates(bool p_use) {
+void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) {
 
-	local_coordinates=p_use;
-	VisualServer::get_singleton()->particles_set_use_local_coordinates(particles,local_coordinates);
+	emission_shape = p_shape;
+	_change_notify();
+	_queue_shader_change();
 }
 
-bool Particles::is_using_local_coordinates() const{
+void ParticlesMaterial::set_emission_sphere_radius(float p_radius) {
 
-	return local_coordinates;
+	emission_sphere_radius = p_radius;
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius);
 }
 
+void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) {
 
-RES Particles::_get_gizmo_geometry() const {
+	emission_box_extents = p_extents;
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents);
+}
 
-	Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
+void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) {
 
-	Ref<FixedSpatialMaterial> mat( memnew( FixedSpatialMaterial ));
+	emission_point_texture = p_points;
+	RID texture;
+	if (p_points.is_valid())
+		texture = p_points->get_rid();
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, texture);
+}
 
-	mat->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.2) );
-	mat->set_parameter( FixedSpatialMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) );
-	mat->set_blend_mode( Material::BLEND_MODE_ADD );
-	mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
-	//mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
+void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normals) {
 
+	emission_normal_texture = p_normals;
+	RID texture;
+	if (p_normals.is_valid())
+		texture = p_normals->get_rid();
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture);
+}
 
-	surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
-	surface_tool->set_material(mat);
+void ParticlesMaterial::set_emission_point_count(int p_count) {
 
-	int sides=16;
-	int sections=24;
+	emission_point_count = p_count;
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count);
+}
 
-	//float len=1;
-	float deg=Math::deg2rad(var[VAR_SPREAD]*180);
-	if (deg==180)
-		deg=179.5;
+ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const {
 
-	Vector3 to=Vector3(0,0,-1);
+	return emission_shape;
+}
 
-	for(int j=0;j<sections;j++) {
+float ParticlesMaterial::get_emission_sphere_radius() const {
 
-		Vector3 p1=Matrix3(Vector3(1,0,0),deg*j/sections).xform(to);
-		Vector3 p2=Matrix3(Vector3(1,0,0),deg*(j+1)/sections).xform(to);
+	return emission_sphere_radius;
+}
+Vector3 ParticlesMaterial::get_emission_box_extents() const {
 
-		for(int i=0;i<sides;i++) {
+	return emission_box_extents;
+}
+Ref<Texture> ParticlesMaterial::get_emission_point_texture() const {
 
-			Vector3 p1r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p1);
-			Vector3 p1s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p1);
-			Vector3 p2s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p2);
-			Vector3 p2r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p2);
+	return emission_point_texture;
+}
+Ref<Texture> ParticlesMaterial::get_emission_normal_texture() const {
 
-			surface_tool->add_normal(p1r.normalized());
-			surface_tool->add_vertex(p1r);
-			surface_tool->add_normal(p1s.normalized());
-			surface_tool->add_vertex(p1s);
-			surface_tool->add_normal(p2s.normalized());
-			surface_tool->add_vertex(p2s);
+	return emission_normal_texture;
+}
 
-			surface_tool->add_normal(p1r.normalized());
-			surface_tool->add_vertex(p1r);
-			surface_tool->add_normal(p2s.normalized());
-			surface_tool->add_vertex(p2s);
-			surface_tool->add_normal(p2r.normalized());
-			surface_tool->add_vertex(p2r);
+int ParticlesMaterial::get_emission_point_count() const {
 
-			if (j==sections-1) {
+	return emission_point_count;
+}
 
-				surface_tool->add_normal(p2r.normalized());
-				surface_tool->add_vertex(p2r);
-				surface_tool->add_normal(p2s.normalized());
-				surface_tool->add_vertex(p2s);
-				surface_tool->add_normal(Vector3(0,0,1));
-				surface_tool->add_vertex(Vector3());
-			}
-		}
-	}
+void ParticlesMaterial::set_trail_divisor(int p_divisor) {
 
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor);
+	trail_divisor = p_divisor;
+	_change_notify();
+}
 
-	Ref<Mesh> mesh = surface_tool->commit();
+int ParticlesMaterial::get_trail_divisor() const {
 
-	Ref<FixedSpatialMaterial> mat_aabb( memnew( FixedSpatialMaterial ));
+	return trail_divisor;
+}
 
-	mat_aabb->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.9,0.7) );
-	mat_aabb->set_line_width(3);
-	mat_aabb->set_flag( Material::FLAG_UNSHADED, true );
+void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier) {
 
-	surface_tool->begin(Mesh::PRIMITIVE_LINES);
-	surface_tool->set_material(mat_aabb);
+	trail_size_modifier = p_trail_size_modifier;
 
-	for(int i=0;i<12;i++) {
+	Ref<CurveTexture> curve = trail_size_modifier;
+	if (curve.is_valid()) {
+		if (curve->get_min() == 0 && curve->get_max() == 1) {
 
-		Vector3 f,t;
-		visibility_aabb.get_edge(i,f,t);
-		surface_tool->add_vertex(f);
-		surface_tool->add_vertex(t);
+			curve->set_max(32);
+			PoolVector<Vector2> points;
+			points.push_back(Vector2(0, 1));
+			points.push_back(Vector2(1, 1));
+			curve->set_points(points);
+		}
 	}
 
-	return surface_tool->commit(mesh);
-
+	RID texture;
+	if (p_trail_size_modifier.is_valid())
+		texture = p_trail_size_modifier->get_rid();
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, texture);
+	_queue_shader_change();
 }
 
+Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const {
 
-void Particles::_bind_methods() {
+	return trail_size_modifier;
+}
 
-	ClassDB::bind_method(D_METHOD("set_amount","amount"),&Particles::set_amount);
-	ClassDB::bind_method(D_METHOD("get_amount"),&Particles::get_amount);
-	ClassDB::bind_method(D_METHOD("set_emitting","enabled"),&Particles::set_emitting);
-	ClassDB::bind_method(D_METHOD("is_emitting"),&Particles::is_emitting);
-	ClassDB::bind_method(D_METHOD("set_visibility_aabb","aabb"),&Particles::set_visibility_aabb);
-	ClassDB::bind_method(D_METHOD("get_visibility_aabb"),&Particles::get_visibility_aabb);
-	ClassDB::bind_method(D_METHOD("set_emission_half_extents","half_extents"),&Particles::set_emission_half_extents);
-	ClassDB::bind_method(D_METHOD("get_emission_half_extents"),&Particles::get_emission_half_extents);
-	ClassDB::bind_method(D_METHOD("set_emission_base_velocity","base_velocity"),&Particles::set_emission_base_velocity);
-	ClassDB::bind_method(D_METHOD("get_emission_base_velocity"),&Particles::get_emission_base_velocity);
-	ClassDB::bind_method(D_METHOD("set_emission_points","points"),&Particles::set_emission_points);
-	ClassDB::bind_method(D_METHOD("get_emission_points"),&Particles::get_emission_points);
-	ClassDB::bind_method(D_METHOD("set_gravity_normal","normal"),&Particles::set_gravity_normal);
-	ClassDB::bind_method(D_METHOD("get_gravity_normal"),&Particles::get_gravity_normal);
-	ClassDB::bind_method(D_METHOD("set_variable","variable","value"),&Particles::set_variable);
-	ClassDB::bind_method(D_METHOD("get_variable","variable"),&Particles::get_variable);
-	ClassDB::bind_method(D_METHOD("set_randomness","variable","randomness"),&Particles::set_randomness);
-	ClassDB::bind_method(D_METHOD("get_randomness","variable"),&Particles::get_randomness);
-	ClassDB::bind_method(D_METHOD("set_color_phase_pos","phase","pos"),&Particles::set_color_phase_pos);
-	ClassDB::bind_method(D_METHOD("get_color_phase_pos","phase"),&Particles::get_color_phase_pos);
-	ClassDB::bind_method(D_METHOD("set_color_phase_color","phase","color"),&Particles::set_color_phase_color);
-	ClassDB::bind_method(D_METHOD("get_color_phase_color","phase"),&Particles::get_color_phase_color);
-	ClassDB::bind_method(D_METHOD("set_material","material:Material"),&Particles::set_material);
-	ClassDB::bind_method(D_METHOD("get_material:Material"),&Particles::get_material);
-	ClassDB::bind_method(D_METHOD("set_emit_timeout","timeout"),&Particles::set_emit_timeout);
-	ClassDB::bind_method(D_METHOD("get_emit_timeout"),&Particles::get_emit_timeout);
-	ClassDB::bind_method(D_METHOD("set_height_from_velocity","enable"),&Particles::set_height_from_velocity);
-	ClassDB::bind_method(D_METHOD("has_height_from_velocity"),&Particles::has_height_from_velocity);
-	ClassDB::bind_method(D_METHOD("set_use_local_coordinates","enable"),&Particles::set_use_local_coordinates);
-	ClassDB::bind_method(D_METHOD("is_using_local_coordinates"),&Particles::is_using_local_coordinates);
-
-	ClassDB::bind_method(D_METHOD("set_color_phases","count"),&Particles::set_color_phases);
-	ClassDB::bind_method(D_METHOD("get_color_phases"),&Particles::get_color_phases);
-
-	ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material" ), "set_material", "get_material") ;
-
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1024,1" ), "set_amount", "get_amount") ;
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "emitting" ), "set_emitting", "is_emitting") ;
-	ADD_PROPERTY( PropertyInfo( Variant::_AABB, "visibility" ), "set_visibility_aabb", "get_visibility_aabb") ;
-	ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "emission_extents" ), "set_emission_half_extents", "get_emission_half_extents") ;
-	ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "emission_base_velocity" ), "set_emission_base_velocity", "get_emission_base_velocity") ;
-	ADD_PROPERTY( PropertyInfo( Variant::VECTOR3_ARRAY, "emission_points" ), "set_emission_points", "get_emission_points") ;
-	ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "gravity_normal" ), "set_gravity_normal", "get_gravity_normal") ;
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "local_coords" ), "set_use_local_coordinates", "is_using_local_coordinates") ;
-	ADD_PROPERTY( PropertyInfo( Variant::REAL, "emit_timeout",PROPERTY_HINT_RANGE,"0,256,0.01"), "set_emit_timeout", "get_emit_timeout") ;
-
-
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/lifetime", PROPERTY_HINT_RANGE,"0.1,60,0.01"), "set_variable", "get_variable", VAR_LIFETIME );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/spread", PROPERTY_HINT_RANGE,"0,1,0.01"), "set_variable", "get_variable", VAR_SPREAD );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/gravity", PROPERTY_HINT_RANGE,"-48,48,0.01"), "set_variable", "get_variable", VAR_GRAVITY );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/linear_vel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_LINEAR_VELOCITY );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/angular_vel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_ANGULAR_VELOCITY );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/linear_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_LINEAR_ACCELERATION );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/radial_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_DRAG );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/tan_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_TANGENTIAL_ACCELERATION );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/damping", PROPERTY_HINT_RANGE,"0,128,0.01"), "set_variable", "get_variable", VAR_DAMPING );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/initial_size", PROPERTY_HINT_RANGE,"0,100,0.01"), "set_variable", "get_variable", VAR_INITIAL_SIZE );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/final_size", PROPERTY_HINT_RANGE,"0,100,0.01"), "set_variable", "get_variable", VAR_FINAL_SIZE );
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/initial_angle",PROPERTY_HINT_RANGE,"0,1,0.01"), "set_variable", "get_variable", VAR_INITIAL_ANGLE );
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "vars/height_from_velocity"), "set_height_from_velocity", "has_height_from_velocity") ;
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/height",PROPERTY_HINT_RANGE,"0,4096,0.01"), "set_variable", "get_variable", VAR_HEIGHT);
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/height_speed_scale",PROPERTY_HINT_RANGE,"0,4096,0.01"), "set_variable", "get_variable", VAR_HEIGHT_SPEED_SCALE );
-
-	for(int i=0;i<VAR_MAX;i++)
-		ADD_PROPERTYI( PropertyInfo( Variant::REAL, _rand_names[i], PROPERTY_HINT_RANGE,"-16.0,16.0,0.01"),"set_randomness", "get_randomness",_var_indices[i] );
-
-
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1"), "set_color_phases", "get_color_phases");
-
-	for(int i=0;i<VS::MAX_PARTICLE_COLOR_PHASES;i++) {
-		String phase="phase_"+itos(i)+"/";
-		ADD_PROPERTYI( PropertyInfo( Variant::REAL, phase+"pos", PROPERTY_HINT_RANGE,"0,1,0.01"),"set_color_phase_pos","get_color_phase_pos",i );
-		ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color"),"set_color_phase_color","get_color_phase_color",i );
-	}
+void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) {
+
+	trail_color_modifier = p_trail_color_modifier;
+	RID texture;
+	if (p_trail_color_modifier.is_valid())
+		texture = p_trail_color_modifier->get_rid();
+	VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, texture);
+	_queue_shader_change();
+}
 
-	BIND_CONSTANT( VAR_LIFETIME );
-	BIND_CONSTANT( VAR_SPREAD );
-	BIND_CONSTANT( VAR_GRAVITY );
-	BIND_CONSTANT( VAR_LINEAR_VELOCITY );
-	BIND_CONSTANT( VAR_ANGULAR_VELOCITY );
-	BIND_CONSTANT( VAR_LINEAR_ACCELERATION );
-	BIND_CONSTANT( VAR_DRAG );
-	BIND_CONSTANT( VAR_TANGENTIAL_ACCELERATION );
-	BIND_CONSTANT( VAR_INITIAL_SIZE );
-	BIND_CONSTANT( VAR_FINAL_SIZE );
-	BIND_CONSTANT( VAR_INITIAL_ANGLE );
-	BIND_CONSTANT( VAR_HEIGHT );
-	BIND_CONSTANT( VAR_HEIGHT_SPEED_SCALE );
-	BIND_CONSTANT( VAR_MAX );
+Ref<GradientTexture> ParticlesMaterial::get_trail_color_modifier() const {
 
+	return trail_color_modifier;
 }
 
-Particles::Particles() {
+void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
 
-	particles = VisualServer::get_singleton()->particles_create();
-	timer = memnew(Timer);
-	add_child(timer);
-	emit_timeout = 0;
+	if (property.name == "color" && color_ramp.is_valid()) {
+		property.usage = 0;
+	}
 
-	set_amount(64);
-	set_emitting(true);
-	set_visibility_aabb(AABB( Vector3(-4,-4,-4), Vector3(8,8,8) ) );
+	if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
+		property.usage = 0;
+	}
 
-	for (int i=0;i<VAR_MAX;i++) {
-		set_randomness((Variable)i,0.0);
+	if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+		property.usage = 0;
 	}
 
-	set_variable( VAR_LIFETIME, 5.0);
-	set_variable( VAR_SPREAD, 0.2);
-	set_variable( VAR_GRAVITY, 9.8);
-	set_variable( VAR_LINEAR_VELOCITY, 0.2);
-	set_variable( VAR_ANGULAR_VELOCITY, 0.0);
-	set_variable( VAR_LINEAR_ACCELERATION, 0.0);
-	set_variable( VAR_DRAG, 0.0);
-	set_variable( VAR_TANGENTIAL_ACCELERATION, 0.0);
-	set_variable( VAR_DAMPING, 0.0);
-	set_variable( VAR_INITIAL_SIZE, 1.0);
-	set_variable( VAR_FINAL_SIZE, 1.0);
-	set_variable( VAR_INITIAL_ANGLE, 0.0);
-	set_variable( VAR_HEIGHT, 1.0);
-	set_variable( VAR_HEIGHT_SPEED_SCALE, 0.0);
-
-	color_phase_count=0;
-
-	set_color_phase_pos(0,0.0);
-	set_color_phase_pos(1,1.0);
-	set_color_phase_pos(2,1.0);
-	set_color_phase_pos(3,1.0);
-
-	set_color_phase_color(0,Color(1,1,1));
-	set_color_phase_color(1,Color(0,0,0));
-	set_color_phase_color(2,Color(0,0,0));
-	set_color_phase_color(3,Color(0,0,0));
-
-	set_gravity_normal(Vector3(0,-1.0,0));
-	set_emission_half_extents(Vector3(0.1,0.1,0.1));
-
-	height_from_velocity=false;
-
-	Vector<Variant> pars;
-	pars.push_back(false);
-	timer->connect("timeout", this, "set_emitting", pars);
-	set_base(particles);
-	local_coordinates=false;
+	if (property.name == "emission_point_texture" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+		property.usage = 0;
+	}
+
+	if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+		property.usage = 0;
+	}
+
+	if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+		property.usage = 0;
+	}
 }
 
+void ParticlesMaterial::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread);
+	ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread);
+
+	ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness);
+	ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness);
+
+	ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ParticlesMaterial::set_param);
+	ClassDB::bind_method(D_METHOD("get_param", "param"), &ParticlesMaterial::get_param);
+
+	ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &ParticlesMaterial::set_param_randomness);
+	ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &ParticlesMaterial::get_param_randomness);
+
+	ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture);
+	ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture);
+
+	ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color);
+	ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color);
+
+	ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp:Texture"), &ParticlesMaterial::set_color_ramp);
+	ClassDB::bind_method(D_METHOD("get_color_ramp:Texture"), &ParticlesMaterial::get_color_ramp);
+
+	ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag);
+	ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag);
+
+	ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape);
+	ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape);
+
+	ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius);
+	ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius);
+
+	ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents);
+	ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents);
+
+	ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture:Texture"), &ParticlesMaterial::set_emission_point_texture);
+	ClassDB::bind_method(D_METHOD("get_emission_point_texture:Texture"), &ParticlesMaterial::get_emission_point_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("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("set_trail_divisor", "divisor"), &ParticlesMaterial::set_trail_divisor);
+	ClassDB::bind_method(D_METHOD("get_trail_divisor"), &ParticlesMaterial::get_trail_divisor);
+
+	ClassDB::bind_method(D_METHOD("set_trail_size_modifier", "texture:CurveTexture"), &ParticlesMaterial::set_trail_size_modifier);
+	ClassDB::bind_method(D_METHOD("get_trail_size_modifier:CurveTexture"), &ParticlesMaterial::get_trail_size_modifier);
+
+	ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture:GradientTexture"), &ParticlesMaterial::set_trail_color_modifier);
+	ClassDB::bind_method(D_METHOD("get_trail_color_modifier:GradientTexture"), &ParticlesMaterial::get_trail_color_modifier);
+
+	ADD_GROUP("Trail", "trail_");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier");
+	ADD_GROUP("Emission Shape", "emission_");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
+	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_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture");
+	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_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_GROUP("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_GROUP("Initial Velocity", "initial_");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
+	ADD_GROUP("Angular Velocity", "angular_");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
+	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
+	ADD_GROUP("Orbit Velocity", "orbit_");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
+	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY);
+	ADD_GROUP("Linear Accel", "linear_");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
+	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL);
+	ADD_GROUP("Radial Accel", "radial_");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
+	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL);
+	ADD_GROUP("Tangential Accel", "tangential_");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
+	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL);
+	ADD_GROUP("Damping", "");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
+	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING);
+	ADD_GROUP("Angle", "");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1"), "set_param", "get_param", PARAM_ANGLE);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
+	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE);
+	ADD_GROUP("Scale", "");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_SCALE);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
+	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE);
+	ADD_GROUP("Color", "");
+	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp");
+
+	ADD_GROUP("Hue Variation", "hue_");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.1"), "set_param", "get_param", 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_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_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::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::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
+
+	BIND_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
+	BIND_CONSTANT(PARAM_ANGULAR_VELOCITY);
+	BIND_CONSTANT(PARAM_ORBIT_VELOCITY);
+	BIND_CONSTANT(PARAM_LINEAR_ACCEL);
+	BIND_CONSTANT(PARAM_RADIAL_ACCEL);
+	BIND_CONSTANT(PARAM_TANGENTIAL_ACCEL);
+	BIND_CONSTANT(PARAM_DAMPING);
+	BIND_CONSTANT(PARAM_ANGLE);
+	BIND_CONSTANT(PARAM_SCALE);
+	BIND_CONSTANT(PARAM_HUE_VARIATION);
+	BIND_CONSTANT(PARAM_ANIM_SPEED);
+	BIND_CONSTANT(PARAM_ANIM_OFFSET);
+	BIND_CONSTANT(PARAM_MAX);
+
+	BIND_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
+	BIND_CONSTANT(FLAG_ROTATE_Y);
+	BIND_CONSTANT(FLAG_MAX);
+
+	BIND_CONSTANT(EMISSION_SHAPE_POINT);
+	BIND_CONSTANT(EMISSION_SHAPE_SPHERE);
+	BIND_CONSTANT(EMISSION_SHAPE_BOX);
+	BIND_CONSTANT(EMISSION_SHAPE_POINTS);
+	BIND_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
+}
 
-Particles::~Particles() {
+ParticlesMaterial::ParticlesMaterial()
+	: element(this) {
+
+	set_spread(45);
+	set_flatness(0);
+	set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1);
+	set_param(PARAM_ORBIT_VELOCITY, 0);
+	set_param(PARAM_LINEAR_ACCEL, 0);
+	set_param(PARAM_RADIAL_ACCEL, 0);
+	set_param(PARAM_TANGENTIAL_ACCEL, 0);
+	set_param(PARAM_DAMPING, 0);
+	set_param(PARAM_ANGLE, 0);
+	set_param(PARAM_SCALE, 1);
+	set_param(PARAM_HUE_VARIATION, 0);
+	set_param(PARAM_ANIM_SPEED, 0);
+	set_param(PARAM_ANIM_OFFSET, 0);
+	set_emission_shape(EMISSION_SHAPE_POINT);
+	set_emission_sphere_radius(1);
+	set_emission_box_extents(Vector3(1, 1, 1));
+	set_trail_divisor(1);
+	emission_point_count = 1;
+
+	for (int i = 0; i < PARAM_MAX; i++) {
+		set_param_randomness(Parameter(i), 0);
+	}
+
+	for (int i = 0; i < FLAG_MAX; i++) {
+		flags[i] = false;
+	}
 
-	VisualServer::get_singleton()->free(particles);
+	set_color(Color(1, 1, 1, 1));
+
+	current_key.key = 0;
+	current_key.invalid_key = 1;
+
+	_queue_shader_change();
 }
 
-#endif
+ParticlesMaterial::~ParticlesMaterial() {
+}

+ 290 - 84
scene/3d/particles.h

@@ -37,130 +37,336 @@
 /**
 	@author Juan Linietsky <[email protected]>
 */
-#if 0
+
 class Particles : public GeometryInstance {
+private:
+	GDCLASS(Particles, GeometryInstance);
+
 public:
+	enum DrawOrder {
+		DRAW_ORDER_INDEX,
+		DRAW_ORDER_LIFETIME,
+		DRAW_ORDER_VIEW_DEPTH,
+	};
 
-	enum Variable {
-		VAR_LIFETIME=VS::PARTICLE_LIFETIME,
-		VAR_SPREAD=VS::PARTICLE_SPREAD,
-		VAR_GRAVITY=VS::PARTICLE_GRAVITY,
-		VAR_LINEAR_VELOCITY=VS::PARTICLE_LINEAR_VELOCITY,
-		VAR_ANGULAR_VELOCITY=VS::PARTICLE_ANGULAR_VELOCITY,
-		VAR_LINEAR_ACCELERATION=VS::PARTICLE_LINEAR_ACCELERATION,
-		VAR_DRAG=VS::PARTICLE_RADIAL_ACCELERATION,
-		VAR_TANGENTIAL_ACCELERATION=VS::PARTICLE_TANGENTIAL_ACCELERATION,
-		VAR_DAMPING=VS::PARTICLE_DAMPING,
-		VAR_INITIAL_SIZE=VS::PARTICLE_INITIAL_SIZE,
-		VAR_FINAL_SIZE=VS::PARTICLE_FINAL_SIZE,
-		VAR_INITIAL_ANGLE=VS::PARTICLE_INITIAL_ANGLE,
-		VAR_HEIGHT=VS::PARTICLE_HEIGHT,
-		VAR_HEIGHT_SPEED_SCALE=VS::PARTICLE_HEIGHT_SPEED_SCALE,
-		VAR_MAX=VS::PARTICLE_VAR_MAX
+	enum {
+		MAX_DRAW_PASSES = 4
 	};
 
 private:
-	GDCLASS( Particles, GeometryInstance );
-
 	RID particles;
 
-	int amount;
 	bool emitting;
-	float emit_timeout;
-	AABB visibility_aabb;
-	Vector3 gravity_normal;
-	Vector3 emission_half_extents;
-	bool using_points;
-	float var[VAR_MAX];
-	float var_random[VAR_MAX];
-	bool height_from_velocity;
-	Vector3 emission_base_velocity;
-	bool local_coordinates;
-
-	struct ColorPhase {
-
-		Color color;
-		float pos;
-	};
-
-	virtual bool _can_gizmo_scale() const;
-	virtual RES _get_gizmo_geometry() const;
-
-	int color_phase_count;
+	int amount;
+	float lifetime;
+	float pre_process_time;
+	float explosiveness_ratio;
+	float randomness_ratio;
+	Rect3 custom_aabb;
+	Vector3 gravity;
+	bool local_coords;
+	int fixed_fps;
+	bool fractional_delta;
 
-	ColorPhase color_phase[4];
+	Ref<Material> process_material;
 
-	Ref<Material> material;
+	DrawOrder draw_order;
 
-	Timer* timer;
-	void setup_timer();
+	Vector<Ref<Mesh> > draw_passes;
 
 protected:
-
 	static void _bind_methods();
+	virtual void _validate_property(PropertyInfo &property) const;
 
 public:
-
-
-	AABB get_aabb() const;
+	Rect3 get_aabb() const;
 	PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
 
+	void set_emitting(bool p_emitting);
 	void set_amount(int p_amount);
-	int get_amount() const;
+	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_custom_aabb(const Rect3 &p_aabb);
+	void set_gravity(const Vector3 &p_gravity);
+	void set_use_local_coordinates(bool p_enable);
+	void set_process_material(const Ref<Material> &p_material);
 
-	void set_emitting(bool p_emitting);
 	bool is_emitting() const;
+	int get_amount() const;
+	float get_lifetime() const;
+	float get_pre_process_time() const;
+	float get_explosiveness_ratio() const;
+	float get_randomness_ratio() const;
+	Rect3 get_custom_aabb() const;
+	Vector3 get_gravity() const;
+	bool get_use_local_coordinates() const;
+	Ref<Material> get_process_material() const;
 
-	void set_visibility_aabb(const AABB& p_aabb);
-	AABB get_visibility_aabb() const;
+	void set_fixed_fps(int p_count);
+	int get_fixed_fps() const;
 
-	void set_emission_half_extents(const Vector3& p_half_extents);
-	Vector3 get_emission_half_extents() const;
+	void set_fractional_delta(bool p_enable);
+	bool get_fractional_delta() const;
 
-	void set_emission_base_velocity(const Vector3& p_base_velocity);
-	Vector3 get_emission_base_velocity() const;
+	void set_draw_order(DrawOrder p_order);
+	DrawOrder get_draw_order() const;
 
-	void set_emission_points(const PoolVector<Vector3>& p_points);
-	PoolVector<Vector3> get_emission_points() const;
+	void set_draw_passes(int p_count);
+	int get_draw_passes() const;
 
-	void set_gravity_normal(const Vector3& p_normal);
-	Vector3 get_gravity_normal() const;
+	void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);
+	Ref<Mesh> get_draw_pass_mesh(int p_pass) const;
 
-	void set_variable(Variable p_variable,float p_value);
-	float get_variable(Variable p_variable) const;
+	Particles();
+	~Particles();
+};
 
-	void set_randomness(Variable p_variable,float p_randomness);
-	float get_randomness(Variable p_variable) const;
+VARIANT_ENUM_CAST(Particles::DrawOrder)
 
-	void set_color_phases(int p_phases);
-	int get_color_phases() const;
+class ParticlesMaterial : public Material {
 
-	void set_color_phase_pos(int p_phase, float p_pos);
-	float get_color_phase_pos(int p_phase) const;
+	GDCLASS(ParticlesMaterial, Material)
 
-	void set_color_phase_color(int p_phase, const Color& p_color);
-	Color get_color_phase_color(int p_phase) const;
+public:
+	enum Parameter {
+
+		PARAM_INITIAL_LINEAR_VELOCITY,
+		PARAM_ANGULAR_VELOCITY,
+		PARAM_ORBIT_VELOCITY,
+		PARAM_LINEAR_ACCEL,
+		PARAM_RADIAL_ACCEL,
+		PARAM_TANGENTIAL_ACCEL,
+		PARAM_DAMPING,
+		PARAM_ANGLE,
+		PARAM_SCALE,
+		PARAM_HUE_VARIATION,
+		PARAM_ANIM_SPEED,
+		PARAM_ANIM_OFFSET,
+		PARAM_MAX
+	};
 
-	void set_height_from_velocity(bool p_enable);
-	bool has_height_from_velocity() const;
+	enum Flags {
+		FLAG_ALIGN_Y_TO_VELOCITY,
+		FLAG_ROTATE_Y,
+		FLAG_MAX
+	};
 
-	void set_material(const Ref<Material>& p_material);
-	Ref<Material> get_material() const;
+	enum EmissionShape {
+		EMISSION_SHAPE_POINT,
+		EMISSION_SHAPE_SPHERE,
+		EMISSION_SHAPE_BOX,
+		EMISSION_SHAPE_POINTS,
+		EMISSION_SHAPE_DIRECTED_POINTS,
+	};
 
-	void set_emit_timeout(float p_timeout);
-	float get_emit_timeout() const;
+private:
+	union MaterialKey {
+
+		struct {
+			uint32_t texture_mask : 16;
+			uint32_t texture_color : 1;
+			uint32_t flags : 2;
+			uint32_t emission_shape : 2;
+			uint32_t trail_size_texture : 1;
+			uint32_t trail_color_texture : 1;
+			uint32_t invalid_key : 1;
+		};
+
+		uint32_t key;
+
+		bool operator<(const MaterialKey &p_key) const {
+			return key < p_key.key;
+		}
+	};
 
-	void set_use_local_coordinates(bool p_use);
-	bool is_using_local_coordinates() const;
+	struct ShaderData {
+		RID shader;
+		int users;
+	};
 
-	void start_emitting(float p_time);
+	static Map<MaterialKey, ShaderData> shader_map;
+
+	MaterialKey current_key;
+
+	_FORCE_INLINE_ MaterialKey _compute_key() const {
+
+		MaterialKey mk;
+		mk.key = 0;
+		for (int i = 0; i < PARAM_MAX; i++) {
+			if (tex_parameters[i].is_valid()) {
+				mk.texture_mask |= (1 << i);
+			}
+		}
+		for (int i = 0; i < FLAG_MAX; i++) {
+			if (flags[i]) {
+				mk.flags |= (1 << i);
+			}
+		}
+
+		mk.texture_color = color_ramp.is_valid() ? 1 : 0;
+		mk.emission_shape = emission_shape;
+		mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0;
+		mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0;
+
+		return mk;
+	}
+
+	static Mutex *material_mutex;
+	static SelfList<ParticlesMaterial>::List dirty_materials;
+
+	struct ShaderNames {
+		StringName spread;
+		StringName flatness;
+		StringName initial_linear_velocity;
+		StringName initial_angle;
+		StringName angular_velocity;
+		StringName orbit_velocity;
+		StringName linear_accel;
+		StringName radial_accel;
+		StringName tangent_accel;
+		StringName damping;
+		StringName scale;
+		StringName hue_variation;
+		StringName anim_speed;
+		StringName anim_offset;
+
+		StringName initial_linear_velocity_random;
+		StringName initial_angle_random;
+		StringName angular_velocity_random;
+		StringName orbit_velocity_random;
+		StringName linear_accel_random;
+		StringName radial_accel_random;
+		StringName tangent_accel_random;
+		StringName damping_random;
+		StringName scale_random;
+		StringName hue_variation_random;
+		StringName anim_speed_random;
+		StringName anim_offset_random;
+
+		StringName angle_texture;
+		StringName angular_velocity_texture;
+		StringName orbit_velocity_texture;
+		StringName linear_accel_texture;
+		StringName radial_accel_texture;
+		StringName tangent_accel_texture;
+		StringName damping_texture;
+		StringName scale_texture;
+		StringName hue_variation_texture;
+		StringName anim_speed_texture;
+		StringName anim_offset_texture;
+
+		StringName color;
+		StringName color_ramp;
+
+		StringName emission_sphere_radius;
+		StringName emission_box_extents;
+		StringName emission_texture_point_count;
+		StringName emission_texture_points;
+		StringName emission_texture_normal;
+
+		StringName trail_divisor;
+		StringName trail_size_modifier;
+		StringName trail_color_modifier;
+	};
 
+	static ShaderNames *shader_names;
 
-	Particles();
-	~Particles();
+	SelfList<ParticlesMaterial> element;
 
+	void _update_shader();
+	_FORCE_INLINE_ void _queue_shader_change();
+	_FORCE_INLINE_ bool _is_shader_dirty() const;
+
+	float spread;
+	float flatness;
+
+	float parameters[PARAM_MAX];
+	float randomness[PARAM_MAX];
+
+	Ref<Texture> tex_parameters[PARAM_MAX];
+	Color color;
+	Ref<Texture> color_ramp;
+
+	bool flags[FLAG_MAX];
+
+	EmissionShape emission_shape;
+	float emission_sphere_radius;
+	Vector3 emission_box_extents;
+	Ref<Texture> emission_point_texture;
+	Ref<Texture> emission_normal_texture;
+	int emission_point_count;
+
+	int trail_divisor;
+
+	Ref<CurveTexture> trail_size_modifier;
+	Ref<GradientTexture> trail_color_modifier;
+
+	//do not save emission points here
+
+protected:
+	static void _bind_methods();
+	virtual void _validate_property(PropertyInfo &property) const;
+
+public:
+	void set_spread(float p_spread);
+	float get_spread() const;
+
+	void set_flatness(float p_flatness);
+	float get_flatness() const;
+
+	void set_param(Parameter p_param, float p_value);
+	float get_param(Parameter p_param) const;
+
+	void set_param_randomness(Parameter p_param, float p_value);
+	float get_param_randomness(Parameter p_param) const;
+
+	void set_param_texture(Parameter p_param, const Ref<Texture> &p_texture);
+	Ref<Texture> get_param_texture(Parameter p_param) const;
+
+	void set_color(const Color &p_color);
+	Color get_color() const;
+
+	void set_color_ramp(const Ref<Texture> &p_texture);
+	Ref<Texture> get_color_ramp() const;
+
+	void set_flag(Flags p_flag, bool p_enable);
+	bool get_flag(Flags p_flag) const;
+
+	void set_emission_shape(EmissionShape p_shape);
+	void set_emission_sphere_radius(float p_radius);
+	void set_emission_box_extents(Vector3 p_extents);
+	void set_emission_point_texture(const Ref<Texture> &p_points);
+	void set_emission_normal_texture(const Ref<Texture> &p_normals);
+	void set_emission_point_count(int p_count);
+
+	EmissionShape get_emission_shape() const;
+	float get_emission_sphere_radius() const;
+	Vector3 get_emission_box_extents() const;
+	Ref<Texture> get_emission_point_texture() const;
+	Ref<Texture> get_emission_normal_texture() const;
+	int get_emission_point_count() const;
+
+	void set_trail_divisor(int p_divisor);
+	int get_trail_divisor() const;
+
+	void set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier);
+	Ref<CurveTexture> get_trail_size_modifier() const;
+
+	void set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier);
+	Ref<GradientTexture> get_trail_color_modifier() const;
+
+	static void init_shaders();
+	static void finish_shaders();
+	static void flush_changes();
+
+	ParticlesMaterial();
+	~ParticlesMaterial();
 };
 
-VARIANT_ENUM_CAST( Particles::Variable );
-#endif
+VARIANT_ENUM_CAST(ParticlesMaterial::Parameter)
+VARIANT_ENUM_CAST(ParticlesMaterial::Flags)
+VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
+
 #endif

+ 0 - 14
scene/3d/spatial.cpp

@@ -511,17 +511,6 @@ Ref<World> Spatial::get_world() const {
 	return data.viewport->find_world();
 }
 
-#ifdef TOOLS_ENABLED
-void Spatial::set_import_transform(const Transform &p_transform) {
-	data.import_transform = p_transform;
-}
-
-Transform Spatial::get_import_transform() const {
-
-	return data.import_transform;
-}
-#endif
-
 void Spatial::_propagate_visibility_changed() {
 
 	notification(NOTIFICATION_VISIBILITY_CHANGED);
@@ -729,9 +718,6 @@ void Spatial::_bind_methods() {
 
 #ifdef TOOLS_ENABLED
 	ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo);
-	ClassDB::bind_method(D_METHOD("_set_import_transform"), &Spatial::set_import_transform);
-	ClassDB::bind_method(D_METHOD("_get_import_transform"), &Spatial::get_import_transform);
-	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "_import_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_import_transform", "_get_import_transform");
 #endif
 
 	ClassDB::bind_method(D_METHOD("update_gizmo"), &Spatial::update_gizmo);

+ 0 - 6
scene/3d/spatial.h

@@ -94,7 +94,6 @@ class Spatial : public Node {
 		Ref<SpatialGizmo> gizmo;
 		bool gizmo_disabled;
 		bool gizmo_dirty;
-		Transform import_transform;
 #endif
 
 	} data;
@@ -188,11 +187,6 @@ public:
 	void hide();
 	bool is_visible_in_tree() const;
 
-#ifdef TOOLS_ENABLED
-	void set_import_transform(const Transform &p_transform);
-	Transform get_import_transform() const;
-#endif
-
 	Spatial();
 	~Spatial();
 };

+ 0 - 6
scene/3d/visual_instance.cpp

@@ -318,9 +318,6 @@ void GeometryInstance::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material_override", "get_material_override");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0"), "set_extra_cull_margin", "get_extra_cull_margin");
-	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_as_billboard"), "set_flag", "get_flag", FLAG_BILLBOARD);
-	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_as_y_billboard"), "set_flag", "get_flag", FLAG_BILLBOARD_FIX_Y);
-	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_depth_scale"), "set_flag", "get_flag", FLAG_DEPH_SCALE);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "visible_in_all_rooms"), "set_flag", "get_flag", FLAG_VISIBLE_IN_ALL_ROOMS);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT);
 
@@ -333,9 +330,6 @@ void GeometryInstance::_bind_methods() {
 	//ADD_SIGNAL( MethodInfo("visibility_changed"));
 
 	BIND_CONSTANT(FLAG_CAST_SHADOW);
-	BIND_CONSTANT(FLAG_BILLBOARD);
-	BIND_CONSTANT(FLAG_BILLBOARD_FIX_Y);
-	BIND_CONSTANT(FLAG_DEPH_SCALE);
 	BIND_CONSTANT(FLAG_VISIBLE_IN_ALL_ROOMS);
 	BIND_CONSTANT(FLAG_MAX);
 

+ 0 - 3
scene/3d/visual_instance.h

@@ -84,9 +84,6 @@ class GeometryInstance : public VisualInstance {
 public:
 	enum Flags {
 		FLAG_CAST_SHADOW = VS::INSTANCE_FLAG_CAST_SHADOW,
-		FLAG_BILLBOARD = VS::INSTANCE_FLAG_BILLBOARD,
-		FLAG_BILLBOARD_FIX_Y = VS::INSTANCE_FLAG_BILLBOARD_FIX_Y,
-		FLAG_DEPH_SCALE = VS::INSTANCE_FLAG_DEPH_SCALE,
 		FLAG_VISIBLE_IN_ALL_ROOMS = VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,
 		FLAG_USE_BAKED_LIGHT = VS::INSTANCE_FLAG_USE_BAKED_LIGHT,
 		FLAG_MAX = VS::INSTANCE_FLAG_MAX,

+ 15 - 15
scene/main/scene_main_loop.cpp

@@ -765,12 +765,12 @@ Ref<Material> SceneTree::get_debug_navigation_material() {
 	if (navigation_material.is_valid())
 		return navigation_material;
 
-	Ref<FixedSpatialMaterial> line_material = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
+	Ref<SpatialMaterial> line_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
 	/*	line_material->set_flag(Material::FLAG_UNSHADED, true);
 	line_material->set_line_width(3.0);
-	line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true);
-	line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true);
-	line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_color());*/
+	line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true);
+	line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true);
+	line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_color());*/
 
 	navigation_material = line_material;
 
@@ -782,12 +782,12 @@ Ref<Material> SceneTree::get_debug_navigation_disabled_material() {
 	if (navigation_disabled_material.is_valid())
 		return navigation_disabled_material;
 
-	Ref<FixedSpatialMaterial> line_material = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
+	Ref<SpatialMaterial> line_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
 	/*	line_material->set_flag(Material::FLAG_UNSHADED, true);
 	line_material->set_line_width(3.0);
-	line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true);
-	line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true);
-	line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_disabled_color());*/
+	line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true);
+	line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true);
+	line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_disabled_color());*/
 
 	navigation_disabled_material = line_material;
 
@@ -798,12 +798,12 @@ Ref<Material> SceneTree::get_debug_collision_material() {
 	if (collision_material.is_valid())
 		return collision_material;
 
-	Ref<FixedSpatialMaterial> line_material = Ref<FixedSpatialMaterial>(memnew(FixedSpatialMaterial));
+	Ref<SpatialMaterial> line_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
 	/*line_material->set_flag(Material::FLAG_UNSHADED, true);
 	line_material->set_line_width(3.0);
-	line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true);
-	line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true);
-	line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,get_debug_collisions_color());*/
+	line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true);
+	line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true);
+	line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_collisions_color());*/
 
 	collision_material = line_material;
 
@@ -817,11 +817,11 @@ Ref<Mesh> SceneTree::get_debug_contact_mesh() {
 
 	debug_contact_mesh = Ref<Mesh>(memnew(Mesh));
 
-	Ref<FixedSpatialMaterial> mat = memnew(FixedSpatialMaterial);
+	Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
 	/*mat->set_flag(Material::FLAG_UNSHADED,true);
 	mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
-	mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true);
-	mat->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,get_debug_collision_contact_color());*/
+	mat->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true);
+	mat->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_collision_contact_color());*/
 
 	Vector3 diamond[6] = {
 		Vector3(-1, 0, 0),

+ 16 - 12
scene/register_scene_types.cpp

@@ -423,7 +423,7 @@ void register_scene_types() {
 	ClassDB::register_class<GIProbeData>();
 	ClassDB::register_class<AnimationTreePlayer>();
 	ClassDB::register_class<Portal>();
-	//ClassDB::register_type<Particles>();
+	ClassDB::register_class<Particles>();
 	ClassDB::register_class<Position3D>();
 	ClassDB::register_class<Quad>();
 	ClassDB::register_class<NavigationMeshInstance>();
@@ -471,7 +471,8 @@ void register_scene_types() {
 	ClassDB::register_class<MeshLibrary>();
 	AcceptDialog::set_swap_ok_cancel(GLOBAL_DEF("gui/common/swap_ok_cancel", bool(OS::get_singleton()->get_swap_ok_cancel())));
 
-	ClassDB::register_class<CanvasItemMaterial>();
+	ClassDB::register_class<Shader>();
+	ClassDB::register_class<ShaderMaterial>();
 	ClassDB::register_virtual_class<CanvasItem>();
 	ClassDB::register_class<Node2D>();
 	ClassDB::register_class<Particles2D>();
@@ -519,21 +520,21 @@ void register_scene_types() {
 	/* REGISTER RESOURCES */
 
 	ClassDB::register_virtual_class<Shader>();
-	//ClassDB::register_virtual_type<ShaderGraph>();
-	ClassDB::register_class<CanvasItemShader>();
-//ClassDB::register_type<CanvasItemShaderGraph>();
 
 #ifndef _3D_DISABLED
 	ClassDB::register_class<Mesh>();
+	ClassDB::register_class<QuadMesh>();
 	ClassDB::register_virtual_class<Material>();
-	ClassDB::register_class<FixedSpatialMaterial>();
-	SceneTree::add_idle_callback(FixedSpatialMaterial::flush_changes);
-	FixedSpatialMaterial::init_shaders();
+	ClassDB::register_class<SpatialMaterial>();
+	SceneTree::add_idle_callback(SpatialMaterial::flush_changes);
+	SpatialMaterial::init_shaders();
+
+	ClassDB::register_class<ParticlesMaterial>();
+	SceneTree::add_idle_callback(ParticlesMaterial::flush_changes);
+	ParticlesMaterial::init_shaders();
+
 	//ClassDB::register_type<ShaderMaterial>();
 	ClassDB::register_class<RoomBounds>();
-	//ClassDB::register_type<MaterialShaderGraph>();
-	ClassDB::register_class<SpatialShader>();
-	ClassDB::register_class<ParticlesShader>();
 	ClassDB::register_class<MultiMesh>();
 	ClassDB::register_class<MeshLibrary>();
 
@@ -564,6 +565,8 @@ void register_scene_types() {
 	ClassDB::register_class<ImageTexture>();
 	ClassDB::register_class<AtlasTexture>();
 	ClassDB::register_class<LargeTexture>();
+	ClassDB::register_class<CurveTexture>();
+	ClassDB::register_class<GradientTexture>();
 	ClassDB::register_class<CubeMap>();
 	ClassDB::register_class<Animation>();
 	ClassDB::register_virtual_class<Font>();
@@ -651,6 +654,7 @@ void unregister_scene_types() {
 		memdelete(resource_loader_text);
 	}
 
-	FixedSpatialMaterial::finish_shaders();
+	SpatialMaterial::finish_shaders();
+	ParticlesMaterial::finish_shaders();
 	SceneStringNames::free();
 }

+ 1 - 1
scene/resources/default_theme/default_theme.cpp

@@ -120,7 +120,7 @@ static Ref<Texture> make_icon(T p_src) {
 }
 
 static Ref<Shader> make_shader(const char *vertex_code, const char *fragment_code, const char *lighting_code) {
-	Ref<Shader> shader = (memnew(Shader(Shader::MODE_CANVAS_ITEM)));
+	Ref<Shader> shader = (memnew(Shader()));
 	//shader->set_code(vertex_code, fragment_code, lighting_code);
 
 	return shader;

File diff suppressed because it is too large
+ 396 - 145
scene/resources/material.cpp


+ 71 - 17
scene/resources/material.h

@@ -56,9 +56,34 @@ public:
 	virtual ~Material();
 };
 
-class FixedSpatialMaterial : public Material {
+class ShaderMaterial : public Material {
 
-	GDCLASS(FixedSpatialMaterial, Material)
+	GDCLASS(ShaderMaterial, Material);
+	Ref<Shader> shader;
+
+protected:
+	bool _set(const StringName &p_name, const Variant &p_value);
+	bool _get(const StringName &p_name, Variant &r_ret) const;
+	void _get_property_list(List<PropertyInfo> *p_list) const;
+
+	static void _bind_methods();
+
+	void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
+
+public:
+	void set_shader(const Ref<Shader> &p_shader);
+	Ref<Shader> get_shader() const;
+
+	void set_shader_param(const StringName &p_param, const Variant &p_value);
+	Variant get_shader_param(const StringName &p_param) const;
+
+	ShaderMaterial();
+	~ShaderMaterial();
+};
+
+class SpatialMaterial : public Material {
+
+	GDCLASS(SpatialMaterial, Material)
 
 public:
 	enum TextureParam {
@@ -128,6 +153,7 @@ public:
 		FLAG_ALBEDO_FROM_VERTEX_COLOR,
 		FLAG_SRGB_VERTEX_COLOR,
 		FLAG_USE_POINT_SIZE,
+		FLAG_FIXED_SIZE,
 		FLAG_MAX
 	};
 
@@ -143,20 +169,28 @@ public:
 		SPECULAR_MODE_SPECULAR,
 	};
 
+	enum BillboardMode {
+		BILLBOARD_DISABLED,
+		BILLBOARD_ENABLED,
+		BILLBOARD_FIXED_Y,
+		BILLBOARD_PARTICLES,
+	};
+
 private:
 	union MaterialKey {
 
 		struct {
-			uint32_t feature_mask : 14;
+			uint32_t feature_mask : 11;
 			uint32_t detail_uv : 1;
 			uint32_t blend_mode : 2;
 			uint32_t depth_draw_mode : 2;
 			uint32_t cull_mode : 2;
-			uint32_t flags : 5;
+			uint32_t flags : 6;
 			uint32_t detail_blend_mode : 2;
 			uint32_t diffuse_mode : 2;
 			uint32_t invalid_key : 1;
 			uint32_t specular_mode : 1;
+			uint32_t billboard_mode : 2;
 		};
 
 		uint32_t key;
@@ -196,6 +230,7 @@ private:
 		mk.detail_blend_mode = detail_blend_mode;
 		mk.diffuse_mode = diffuse_mode;
 		mk.specular_mode = specular_mode;
+		mk.billboard_mode = billboard_mode;
 
 		return mk;
 	}
@@ -222,14 +257,17 @@ private:
 		StringName uv1_offset;
 		StringName uv2_scale;
 		StringName uv2_offset;
+		StringName particle_h_frames;
+		StringName particle_v_frames;
+		StringName particles_anim_loop;
 		StringName texture_names[TEXTURE_MAX];
 	};
 
 	static Mutex *material_mutex;
-	static SelfList<FixedSpatialMaterial>::List dirty_materials;
+	static SelfList<SpatialMaterial>::List dirty_materials;
 	static ShaderNames *shader_names;
 
-	SelfList<FixedSpatialMaterial> element;
+	SelfList<SpatialMaterial> element;
 
 	void _update_shader();
 	_FORCE_INLINE_ void _queue_shader_change();
@@ -253,6 +291,9 @@ private:
 	float refraction_roughness;
 	float line_width;
 	float point_size;
+	int particles_anim_h_frames;
+	int particles_anim_v_frames;
+	bool particles_anim_loop;
 
 	Vector2 uv1_scale;
 	Vector2 uv1_offset;
@@ -269,6 +310,7 @@ private:
 	bool flags[FLAG_MAX];
 	DiffuseMode diffuse_mode;
 	SpecularMode specular_mode;
+	BillboardMode billboard_mode;
 
 	bool features[FEATURE_MAX];
 
@@ -377,23 +419,35 @@ public:
 	void set_uv2_offset(const Vector2 &p_offset);
 	Vector2 get_uv2_offset() const;
 
+	void set_billboard_mode(BillboardMode p_mode);
+	BillboardMode get_billboard_mode() const;
+
+	void set_particles_anim_h_frames(int p_frames);
+	int get_particles_anim_h_frames() const;
+	void set_particles_anim_v_frames(int p_frames);
+	int get_particles_anim_v_frames() const;
+
+	void set_particles_anim_loop(int p_frames);
+	int get_particles_anim_loop() const;
+
 	static void init_shaders();
 	static void finish_shaders();
 	static void flush_changes();
 
-	FixedSpatialMaterial();
-	virtual ~FixedSpatialMaterial();
+	SpatialMaterial();
+	virtual ~SpatialMaterial();
 };
 
-VARIANT_ENUM_CAST(FixedSpatialMaterial::TextureParam)
-VARIANT_ENUM_CAST(FixedSpatialMaterial::DetailUV)
-VARIANT_ENUM_CAST(FixedSpatialMaterial::Feature)
-VARIANT_ENUM_CAST(FixedSpatialMaterial::BlendMode)
-VARIANT_ENUM_CAST(FixedSpatialMaterial::DepthDrawMode)
-VARIANT_ENUM_CAST(FixedSpatialMaterial::CullMode)
-VARIANT_ENUM_CAST(FixedSpatialMaterial::Flags)
-VARIANT_ENUM_CAST(FixedSpatialMaterial::DiffuseMode)
-VARIANT_ENUM_CAST(FixedSpatialMaterial::SpecularMode)
+VARIANT_ENUM_CAST(SpatialMaterial::TextureParam)
+VARIANT_ENUM_CAST(SpatialMaterial::DetailUV)
+VARIANT_ENUM_CAST(SpatialMaterial::Feature)
+VARIANT_ENUM_CAST(SpatialMaterial::BlendMode)
+VARIANT_ENUM_CAST(SpatialMaterial::DepthDrawMode)
+VARIANT_ENUM_CAST(SpatialMaterial::CullMode)
+VARIANT_ENUM_CAST(SpatialMaterial::Flags)
+VARIANT_ENUM_CAST(SpatialMaterial::DiffuseMode)
+VARIANT_ENUM_CAST(SpatialMaterial::SpecularMode)
+VARIANT_ENUM_CAST(SpatialMaterial::BillboardMode)
 
 //////////////////////
 

+ 74 - 0
scene/resources/mesh.cpp

@@ -192,6 +192,9 @@ bool Mesh::_set(const StringName &p_name, const Variant &p_value) {
 
 bool Mesh::_get(const StringName &p_name, Variant &r_ret) const {
 
+	if (_is_generated())
+		return false;
+
 	String sname = p_name;
 
 	if (p_name == "blend_shape/names") {
@@ -268,6 +271,9 @@ bool Mesh::_get(const StringName &p_name, Variant &r_ret) const {
 
 void Mesh::_get_property_list(List<PropertyInfo> *p_list) const {
 
+	if (_is_generated())
+		return;
+
 	if (blend_shapes.size()) {
 		p_list->push_back(PropertyInfo(Variant::POOL_STRING_ARRAY, "blend_shape/names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
 		p_list->push_back(PropertyInfo(Variant::INT, "blend_shape/mode", PROPERTY_HINT_ENUM, "Normalized,Relative"));
@@ -1025,3 +1031,71 @@ Mesh::~Mesh() {
 
 	VisualServer::get_singleton()->free(mesh);
 }
+
+////////////////////////
+
+void QuadMesh::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &QuadMesh::set_material);
+	ClassDB::bind_method(D_METHOD("get_material:Material"), &QuadMesh::get_material);
+
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material", "get_material");
+}
+
+void QuadMesh::set_material(const Ref<Material> &p_material) {
+
+	surface_set_material(0, p_material);
+}
+
+Ref<Material> QuadMesh::get_material() const {
+
+	return surface_get_material(0);
+}
+
+QuadMesh::QuadMesh() {
+
+	PoolVector<Vector3> faces;
+	PoolVector<Vector3> normals;
+	PoolVector<float> tangents;
+	PoolVector<Vector2> uvs;
+
+	faces.resize(4);
+	normals.resize(4);
+	tangents.resize(4 * 4);
+	uvs.resize(4);
+
+	for (int i = 0; i < 4; i++) {
+
+		static const Vector3 quad_faces[4] = {
+			Vector3(-1, -1, 0),
+			Vector3(-1, 1, 0),
+			Vector3(1, 1, 0),
+			Vector3(1, -1, 0),
+		};
+
+		faces.set(i, quad_faces[i]);
+		normals.set(i, Vector3(0, 0, 1));
+		tangents.set(i * 4 + 0, 1.0);
+		tangents.set(i * 4 + 1, 0.0);
+		tangents.set(i * 4 + 2, 0.0);
+		tangents.set(i * 4 + 3, 1.0);
+
+		static const Vector2 quad_uv[4] = {
+			Vector2(0, 1),
+			Vector2(0, 0),
+			Vector2(1, 0),
+			Vector2(1, 1),
+		};
+
+		uvs.set(i, quad_uv[i]);
+	}
+
+	Array arr;
+	arr.resize(ARRAY_MAX);
+	arr[ARRAY_VERTEX] = faces;
+	arr[ARRAY_NORMAL] = normals;
+	arr[ARRAY_TANGENT] = tangents;
+	arr[ARRAY_TEX_UV] = uvs;
+
+	add_surface_from_arrays(PRIMITIVE_TRIANGLE_FAN, arr);
+}

+ 16 - 0
scene/resources/mesh.h

@@ -128,6 +128,8 @@ private:
 	void _recompute_aabb();
 
 protected:
+	virtual bool _is_generated() const { return false; }
+
 	bool _set(const StringName &p_name, const Variant &p_value);
 	bool _get(const StringName &p_name, Variant &r_ret) const;
 	void _get_property_list(List<PropertyInfo> *p_list) const;
@@ -189,6 +191,20 @@ public:
 	~Mesh();
 };
 
+class QuadMesh : public Mesh {
+
+	GDCLASS(QuadMesh, Mesh)
+
+protected:
+	virtual bool _is_generated() const { return true; }
+	static void _bind_methods();
+
+public:
+	void set_material(const Ref<Material> &p_material);
+	Ref<Material> get_material() const;
+	QuadMesh();
+};
+
 VARIANT_ENUM_CAST(Mesh::ArrayType);
 VARIANT_ENUM_CAST(Mesh::PrimitiveType);
 VARIANT_ENUM_CAST(Mesh::BlendShapeMode);

+ 16 - 3
scene/resources/shader.cpp

@@ -29,6 +29,7 @@
 #include "shader.h"
 #include "os/file_access.h"
 #include "scene/scene_string_names.h"
+#include "servers/visual/shader_language.h"
 #include "servers/visual_server.h"
 #include "texture.h"
 
@@ -39,6 +40,18 @@ Shader::Mode Shader::get_mode() const {
 
 void Shader::set_code(const String &p_code) {
 
+	String type = ShaderLanguage::get_shader_type(p_code);
+
+	print_line("mode: " + type);
+
+	if (type == "canvas_item") {
+		mode = MODE_CANVAS_ITEM;
+	} else if (type == "particles") {
+		mode = MODE_PARTICLES;
+	} else {
+		mode = MODE_SPATIAL;
+	}
+
 	VisualServer::get_singleton()->shader_set_code(shader, p_code);
 	params_cache_dirty = true;
 	emit_signal(SceneStringNames::get_singleton()->changed);
@@ -128,10 +141,10 @@ void Shader::_bind_methods() {
 	BIND_CONSTANT(MODE_PARTICLES);
 }
 
-Shader::Shader(Mode p_mode) {
+Shader::Shader() {
 
-	mode = p_mode;
-	shader = VisualServer::get_singleton()->shader_create(VS::ShaderMode(p_mode));
+	mode = MODE_SPATIAL;
+	shader = VisualServer::get_singleton()->shader_create();
 	params_cache_dirty = true;
 }
 

+ 1 - 28
scene/resources/shader.h

@@ -88,37 +88,10 @@ public:
 
 	virtual RID get_rid() const;
 
-	Shader(Mode p_mode);
+	Shader();
 	~Shader();
 };
 
 VARIANT_ENUM_CAST(Shader::Mode);
 
-class SpatialShader : public Shader {
-
-	GDCLASS(SpatialShader, Shader);
-
-public:
-	SpatialShader()
-		: Shader(MODE_SPATIAL){};
-};
-
-class CanvasItemShader : public Shader {
-
-	GDCLASS(CanvasItemShader, Shader);
-
-public:
-	CanvasItemShader()
-		: Shader(MODE_CANVAS_ITEM){};
-};
-
-class ParticlesShader : public Shader {
-
-	GDCLASS(ParticlesShader, Shader);
-
-public:
-	ParticlesShader()
-		: Shader(MODE_PARTICLES){};
-};
-
 #endif // SHADER_H

+ 468 - 0
scene/resources/texture.cpp

@@ -1367,3 +1367,471 @@ CubeMap::~CubeMap() {
 	BIND_CONSTANT( CUBEMAP_FRONT );
 	BIND_CONSTANT( CUBEMAP_BACK );
 */
+///////////////////////////
+
+void CurveTexture::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("set_max", "max"), &CurveTexture::set_max);
+	ClassDB::bind_method(D_METHOD("get_max"), &CurveTexture::get_max);
+
+	ClassDB::bind_method(D_METHOD("set_min", "min"), &CurveTexture::set_min);
+	ClassDB::bind_method(D_METHOD("get_min"), &CurveTexture::get_min);
+
+	ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
+
+	ClassDB::bind_method(D_METHOD("set_points", "points"), &CurveTexture::set_points);
+	ClassDB::bind_method(D_METHOD("get_points"), &CurveTexture::get_points);
+
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "min", PROPERTY_HINT_RANGE, "-1024,1024"), "set_min", "get_min");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "max", PROPERTY_HINT_RANGE, "-1024,1024"), "set_max", "get_max");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width");
+	ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points");
+}
+void CurveTexture::set_max(float p_max) {
+
+	max = p_max;
+	emit_changed();
+}
+float CurveTexture::get_max() const {
+
+	return max;
+}
+
+void CurveTexture::set_min(float p_min) {
+
+	min = p_min;
+	emit_changed();
+}
+float CurveTexture::get_min() const {
+
+	return min;
+}
+void CurveTexture::set_width(int p_width) {
+
+	ERR_FAIL_COND(p_width < 32 || p_width > 4096);
+	width = p_width;
+	if (points.size())
+		set_points(points);
+}
+int CurveTexture::get_width() const {
+
+	return width;
+}
+
+static void _plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d, float *p_heights, bool *p_useds, int p_width, float p_min, float p_max) {
+
+	float geometry[4][4];
+	float tmp1[4][4];
+	float tmp2[4][4];
+	float deltas[4][4];
+	double x, dx, dx2, dx3;
+	double y, dy, dy2, dy3;
+	double d, d2, d3;
+	int lastx;
+	int newx;
+	float lasty;
+	float newy;
+	int ntimes;
+	int i, j;
+
+	int xmax = p_width;
+
+	/* construct the geometry matrix from the segment */
+	for (i = 0; i < 4; i++) {
+		geometry[i][2] = 0;
+		geometry[i][3] = 0;
+	}
+
+	geometry[0][0] = (p_a[0] * xmax);
+	geometry[1][0] = (p_b[0] * xmax);
+	geometry[2][0] = (p_c[0] * xmax);
+	geometry[3][0] = (p_d[0] * xmax);
+
+	geometry[0][1] = (p_a[1]);
+	geometry[1][1] = (p_b[1]);
+	geometry[2][1] = (p_c[1]);
+	geometry[3][1] = (p_d[1]);
+
+	/* subdivide the curve ntimes (1000) times */
+	ntimes = 4 * xmax;
+	/* ntimes can be adjusted to give a finer or coarser curve */
+	d = 1.0 / ntimes;
+	d2 = d * d;
+	d3 = d * d * d;
+
+	/* construct a temporary matrix for determining the forward differencing deltas */
+	tmp2[0][0] = 0;
+	tmp2[0][1] = 0;
+	tmp2[0][2] = 0;
+	tmp2[0][3] = 1;
+	tmp2[1][0] = d3;
+	tmp2[1][1] = d2;
+	tmp2[1][2] = d;
+	tmp2[1][3] = 0;
+	tmp2[2][0] = 6 * d3;
+	tmp2[2][1] = 2 * d2;
+	tmp2[2][2] = 0;
+	tmp2[2][3] = 0;
+	tmp2[3][0] = 6 * d3;
+	tmp2[3][1] = 0;
+	tmp2[3][2] = 0;
+	tmp2[3][3] = 0;
+
+	/* compose the basis and geometry matrices */
+
+	static const float CR_basis[4][4] = {
+		{ -0.5, 1.5, -1.5, 0.5 },
+		{ 1.0, -2.5, 2.0, -0.5 },
+		{ -0.5, 0.0, 0.5, 0.0 },
+		{ 0.0, 1.0, 0.0, 0.0 },
+	};
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
+						  CR_basis[i][1] * geometry[1][j] +
+						  CR_basis[i][2] * geometry[2][j] +
+						  CR_basis[i][3] * geometry[3][j]);
+		}
+	}
+	/* compose the above results to get the deltas matrix */
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 4; j++) {
+			deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
+							tmp2[i][1] * tmp1[1][j] +
+							tmp2[i][2] * tmp1[2][j] +
+							tmp2[i][3] * tmp1[3][j]);
+		}
+	}
+
+	/* extract the x deltas */
+	x = deltas[0][0];
+	dx = deltas[1][0];
+	dx2 = deltas[2][0];
+	dx3 = deltas[3][0];
+
+	/* extract the y deltas */
+	y = deltas[0][1];
+	dy = deltas[1][1];
+	dy2 = deltas[2][1];
+	dy3 = deltas[3][1];
+
+	lastx = CLAMP(x, 0, xmax);
+	lasty = y;
+
+	p_heights[lastx] = lasty;
+	p_useds[lastx] = true;
+
+	/* loop over the curve */
+	for (i = 0; i < ntimes; i++) {
+		/* increment the x values */
+		x += dx;
+		dx += dx2;
+		dx2 += dx3;
+
+		/* increment the y values */
+		y += dy;
+		dy += dy2;
+		dy2 += dy3;
+
+		newx = CLAMP((Math::round(x)), 0, xmax);
+		newy = CLAMP(y, p_min, p_max);
+
+		/* if this point is different than the last one...then draw it */
+		if ((lastx != newx) || (lasty != newy)) {
+			p_useds[newx] = true;
+			p_heights[newx] = newy;
+		}
+
+		lastx = newx;
+		lasty = newy;
+	}
+}
+
+void CurveTexture::set_points(const PoolVector<Vector2> &p_points) {
+
+	points = p_points;
+
+	PoolVector<uint8_t> data;
+	PoolVector<bool> used;
+	data.resize(width * sizeof(float));
+	used.resize(width);
+	{
+		PoolVector<uint8_t>::Write wd8 = data.write();
+		float *wd = (float *)wd8.ptr();
+		PoolVector<bool>::Write wu = used.write();
+		int pc = p_points.size();
+		PoolVector<Vector2>::Read pr = p_points.read();
+
+		for (int i = 0; i < width; i++) {
+			wd[i] = 0.0;
+			wu[i] = false;
+		}
+
+		Vector2 prev = Vector2(0, 0);
+		Vector2 prev2 = Vector2(0, 0);
+
+		for (int i = -1; i < pc; i++) {
+
+			Vector2 next;
+			Vector2 next2;
+			if (i + 1 >= pc) {
+				next = Vector2(1, 0);
+			} else {
+				next = Vector2(pr[i + 1].x, pr[i + 1].y);
+			}
+
+			if (i + 2 >= pc) {
+				next2 = Vector2(1, 0);
+			} else {
+				next2 = Vector2(pr[i + 2].x, pr[i + 2].y);
+			}
+
+			/*if (i==-1 && prev.offset==next.offset) {
+				prev=next;
+				continue;
+			}*/
+
+			_plot_curve(prev2, prev, next, next2, wd, wu.ptr(), width, min, max);
+
+			prev2 = prev;
+			prev = next;
+		}
+	}
+
+	Image image(width, 1, false, Image::FORMAT_RF, data);
+
+	VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER);
+	VS::get_singleton()->texture_set_data(texture, image);
+
+	emit_changed();
+}
+
+PoolVector<Vector2> CurveTexture::get_points() const {
+
+	return points;
+}
+
+RID CurveTexture::get_rid() const {
+
+	return texture;
+}
+
+CurveTexture::CurveTexture() {
+
+	max = 1;
+	min = 0;
+	width = 2048;
+	texture = VS::get_singleton()->texture_create();
+}
+CurveTexture::~CurveTexture() {
+	VS::get_singleton()->free(texture);
+}
+//////////////////
+
+//setter and getter names for property serialization
+#define COLOR_RAMP_GET_OFFSETS "get_offsets"
+#define COLOR_RAMP_GET_COLORS "get_colors"
+#define COLOR_RAMP_SET_OFFSETS "set_offsets"
+#define COLOR_RAMP_SET_COLORS "set_colors"
+
+GradientTexture::GradientTexture() {
+	//Set initial color ramp transition from black to white
+	points.resize(2);
+	points[0].color = Color(0, 0, 0, 1);
+	points[0].offset = 0;
+	points[1].color = Color(1, 1, 1, 1);
+	points[1].offset = 1;
+	is_sorted = true;
+	update_pending = false;
+	width = 2048;
+
+	texture = VS::get_singleton()->texture_create();
+	_queue_update();
+}
+
+GradientTexture::~GradientTexture() {
+	VS::get_singleton()->free(texture);
+}
+
+void GradientTexture::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &GradientTexture::add_point);
+	ClassDB::bind_method(D_METHOD("remove_point", "offset", "color"), &GradientTexture::remove_point);
+
+	ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &GradientTexture::set_offset);
+	ClassDB::bind_method(D_METHOD("get_offset", "point"), &GradientTexture::get_offset);
+
+	ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &GradientTexture::set_color);
+	ClassDB::bind_method(D_METHOD("get_color", "point"), &GradientTexture::get_color);
+
+	ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture::set_width);
+
+	ClassDB::bind_method(D_METHOD("interpolate", "offset"), &GradientTexture::get_color_at_offset);
+
+	ClassDB::bind_method(D_METHOD("get_point_count"), &GradientTexture::get_points_count);
+
+	ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update);
+
+	ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &GradientTexture::set_offsets);
+	ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &GradientTexture::get_offsets);
+
+	ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &GradientTexture::set_colors);
+	ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &GradientTexture::get_colors);
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "width"), "set_width", "get_width");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS);
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS);
+}
+
+void GradientTexture::_queue_update() {
+
+	if (update_pending)
+		return;
+
+	call_deferred("_update");
+}
+
+void GradientTexture::_update() {
+
+	update_pending = false;
+
+	PoolVector<uint8_t> data;
+	data.resize(width * 4);
+	{
+		PoolVector<uint8_t>::Write wd8 = data.write();
+		for (int i = 0; i < width; i++) {
+			float ofs = float(i) / (width - 1);
+
+			Color color = get_color_at_offset(ofs);
+			wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
+			wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
+			wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
+			wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
+		}
+	}
+
+	Image image(width, 1, false, Image::FORMAT_RGBA8, data);
+
+	VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RGBA8, VS::TEXTURE_FLAG_FILTER);
+	VS::get_singleton()->texture_set_data(texture, image);
+
+	emit_changed();
+}
+
+void GradientTexture::set_width(int p_width) {
+
+	width = p_width;
+	_queue_update();
+}
+int GradientTexture::get_width() const {
+
+	return width;
+}
+
+Vector<float> GradientTexture::get_offsets() const {
+	Vector<float> offsets;
+	offsets.resize(points.size());
+	for (int i = 0; i < points.size(); i++) {
+		offsets[i] = points[i].offset;
+	}
+	return offsets;
+}
+
+Vector<Color> GradientTexture::get_colors() const {
+	Vector<Color> colors;
+	colors.resize(points.size());
+	for (int i = 0; i < points.size(); i++) {
+		colors[i] = points[i].color;
+	}
+	return colors;
+}
+
+void GradientTexture::set_offsets(const Vector<float> &p_offsets) {
+	points.resize(p_offsets.size());
+	for (int i = 0; i < points.size(); i++) {
+		points[i].offset = p_offsets[i];
+	}
+	is_sorted = false;
+	emit_changed();
+	_queue_update();
+}
+
+void GradientTexture::set_colors(const Vector<Color> &p_colors) {
+	if (points.size() < p_colors.size())
+		is_sorted = false;
+	points.resize(p_colors.size());
+	for (int i = 0; i < points.size(); i++) {
+		points[i].color = p_colors[i];
+	}
+	emit_changed();
+	_queue_update();
+}
+
+Vector<GradientTexture::Point> &GradientTexture::get_points() {
+	return points;
+}
+
+void GradientTexture::add_point(float p_offset, const Color &p_color) {
+
+	Point p;
+	p.offset = p_offset;
+	p.color = p_color;
+	is_sorted = false;
+	points.push_back(p);
+
+	emit_changed();
+	_queue_update();
+}
+
+void GradientTexture::remove_point(int p_index) {
+
+	ERR_FAIL_INDEX(p_index, points.size());
+	ERR_FAIL_COND(points.size() <= 2);
+	points.remove(p_index);
+	emit_changed();
+	_queue_update();
+}
+
+void GradientTexture::set_points(Vector<GradientTexture::Point> &p_points) {
+	points = p_points;
+	is_sorted = false;
+	emit_changed();
+	_queue_update();
+}
+
+void GradientTexture::set_offset(int pos, const float offset) {
+	if (points.size() <= pos)
+		points.resize(pos + 1);
+	points[pos].offset = offset;
+	is_sorted = false;
+	emit_changed();
+	_queue_update();
+}
+
+float GradientTexture::get_offset(int pos) const {
+	if (points.size() > pos)
+		return points[pos].offset;
+	return 0; //TODO: Maybe throw some error instead?
+}
+
+void GradientTexture::set_color(int pos, const Color &color) {
+	if (points.size() <= pos) {
+		points.resize(pos + 1);
+		is_sorted = false;
+	}
+	points[pos].color = color;
+	emit_changed();
+	_queue_update();
+}
+
+Color GradientTexture::get_color(int pos) const {
+	if (points.size() > pos)
+		return points[pos].color;
+	return Color(0, 0, 0, 1); //TODO: Maybe throw some error instead?
+}
+
+int GradientTexture::get_points_count() const {
+	return points.size();
+}

+ 141 - 0
scene/resources/texture.h

@@ -394,6 +394,44 @@ VARIANT_ENUM_CAST(CubeMap::Flags);
 VARIANT_ENUM_CAST(CubeMap::Side);
 VARIANT_ENUM_CAST(CubeMap::Storage);
 
+class CurveTexture : public Texture {
+
+	GDCLASS(CurveTexture, Texture);
+	RES_BASE_EXTENSION("cvtex");
+
+private:
+	RID texture;
+	PoolVector<Vector2> points;
+	float min, max;
+	int width;
+
+protected:
+	static void _bind_methods();
+
+public:
+	void set_max(float p_max);
+	float get_max() const;
+
+	void set_min(float p_min);
+	float get_min() const;
+
+	void set_width(int p_width);
+	int get_width() const;
+
+	void set_points(const PoolVector<Vector2> &p_points);
+	PoolVector<Vector2> get_points() const;
+
+	virtual RID get_rid() const;
+
+	virtual int get_height() const { return 1; }
+	virtual bool has_alpha() const { return false; }
+
+	virtual void set_flags(uint32_t p_flags) {}
+	virtual uint32_t get_flags() const { return FLAG_FILTER; }
+
+	CurveTexture();
+	~CurveTexture();
+};
 /*
 	enum CubeMapSide {
 
@@ -408,4 +446,107 @@ VARIANT_ENUM_CAST(CubeMap::Storage);
 */
 //VARIANT_ENUM_CAST( Texture::CubeMapSide );
 
+class GradientTexture : public Texture {
+	GDCLASS(GradientTexture, Texture);
+
+public:
+	struct Point {
+
+		float offset;
+		Color color;
+		bool operator<(const Point &p_ponit) const {
+			return offset < p_ponit.offset;
+		}
+	};
+
+private:
+	Vector<Point> points;
+	bool is_sorted;
+	bool update_pending;
+	RID texture;
+	int width;
+
+	void _queue_update();
+	void _update();
+
+protected:
+	static void _bind_methods();
+
+public:
+	void add_point(float p_offset, const Color &p_color);
+	void remove_point(int p_index);
+
+	void set_points(Vector<Point> &points);
+	Vector<Point> &get_points();
+
+	void set_offset(int pos, const float offset);
+	float get_offset(int pos) const;
+
+	void set_color(int pos, const Color &color);
+	Color get_color(int pos) const;
+
+	void set_offsets(const Vector<float> &offsets);
+	Vector<float> get_offsets() const;
+
+	void set_colors(const Vector<Color> &colors);
+	Vector<Color> get_colors() const;
+
+	void set_width(int p_width);
+	int get_width() const;
+
+	virtual RID get_rid() const { return texture; }
+	virtual int get_height() const { return 1; }
+	virtual bool has_alpha() const { return true; }
+
+	virtual void set_flags(uint32_t p_flags) {}
+	virtual uint32_t get_flags() const { return FLAG_FILTER; }
+
+	_FORCE_INLINE_ Color get_color_at_offset(float p_offset) {
+
+		if (points.empty())
+			return Color(0, 0, 0, 1);
+
+		if (!is_sorted) {
+			points.sort();
+			is_sorted = true;
+		}
+
+		//binary search
+		int low = 0;
+		int high = points.size() - 1;
+		int middle;
+
+		while (low <= high) {
+			middle = (low + high) / 2;
+			Point &point = points[middle];
+			if (point.offset > p_offset) {
+				high = middle - 1; //search low end of array
+			} else if (point.offset < p_offset) {
+				low = middle + 1; //search high end of array
+			} else {
+				return point.color;
+			}
+		}
+
+		//return interpolated value
+		if (points[middle].offset > p_offset) {
+			middle--;
+		}
+		int first = middle;
+		int second = middle + 1;
+		if (second >= points.size())
+			return points[points.size() - 1].color;
+		if (first < 0)
+			return points[0].color;
+		Point &pointFirst = points[first];
+		Point &pointSecond = points[second];
+		return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset));
+	}
+
+	int get_points_count() const;
+
+	GradientTexture();
+	virtual ~GradientTexture();
+};
+
 #endif

+ 6 - 6
scene/resources/tile_set.cpp

@@ -125,7 +125,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
 		p_list->push_back(PropertyInfo(Variant::STRING, pre + "name"));
 		p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"));
 		p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "tex_offset"));
-		p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial"));
+		p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"));
 		p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate"));
 		p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region"));
 		p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "occluder_offset"));
@@ -159,16 +159,16 @@ Ref<Texture> TileSet::tile_get_texture(int p_id) const {
 	return tile_map[p_id].texture;
 }
 
-void TileSet::tile_set_material(int p_id, const Ref<CanvasItemMaterial> &p_material) {
+void TileSet::tile_set_material(int p_id, const Ref<ShaderMaterial> &p_material) {
 
 	ERR_FAIL_COND(!tile_map.has(p_id));
 	tile_map[p_id].material = p_material;
 	emit_changed();
 }
 
-Ref<CanvasItemMaterial> TileSet::tile_get_material(int p_id) const {
+Ref<ShaderMaterial> TileSet::tile_get_material(int p_id) const {
 
-	ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<CanvasItemMaterial>());
+	ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<ShaderMaterial>());
 	return tile_map[p_id].material;
 }
 
@@ -403,8 +403,8 @@ void TileSet::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name);
 	ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture:Texture"), &TileSet::tile_set_texture);
 	ClassDB::bind_method(D_METHOD("tile_get_texture:Texture", "id"), &TileSet::tile_get_texture);
-	ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material:CanvasItemMaterial"), &TileSet::tile_set_material);
-	ClassDB::bind_method(D_METHOD("tile_get_material:CanvasItemMaterial", "id"), &TileSet::tile_get_material);
+	ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material:ShaderMaterial"), &TileSet::tile_set_material);
+	ClassDB::bind_method(D_METHOD("tile_get_material:ShaderMaterial", "id"), &TileSet::tile_get_material);
 	ClassDB::bind_method(D_METHOD("tile_set_texture_offset", "id", "texture_offset"), &TileSet::tile_set_texture_offset);
 	ClassDB::bind_method(D_METHOD("tile_get_texture_offset", "id"), &TileSet::tile_get_texture_offset);
 	ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_offset"), &TileSet::tile_set_shape_offset);

+ 3 - 3
scene/resources/tile_set.h

@@ -51,7 +51,7 @@ class TileSet : public Resource {
 		Ref<OccluderPolygon2D> occluder;
 		Vector2 navigation_polygon_offset;
 		Ref<NavigationPolygon> navigation_polygon;
-		Ref<CanvasItemMaterial> material;
+		Ref<ShaderMaterial> material;
 		Color modulate;
 
 		// Default modulate for back-compat
@@ -92,8 +92,8 @@ public:
 	void tile_set_shape(int p_id, const Ref<Shape2D> &p_shape);
 	Ref<Shape2D> tile_get_shape(int p_id) const;
 
-	void tile_set_material(int p_id, const Ref<CanvasItemMaterial> &p_material);
-	Ref<CanvasItemMaterial> tile_get_material(int p_id) const;
+	void tile_set_material(int p_id, const Ref<ShaderMaterial> &p_material);
+	Ref<ShaderMaterial> tile_get_material(int p_id) const;
 
 	void tile_set_modulate(int p_id, const Color &p_color);
 	Color tile_get_modulate(int p_id) const;

+ 49 - 49
servers/visual/rasterizer.cpp

@@ -54,10 +54,10 @@ RID Rasterizer::create_default_material() {
 
 /* Fixed MAterial SHADER API */
 
-RID Rasterizer::_create_shader(const FixedSpatialMaterialShaderKey& p_key) {
+RID Rasterizer::_create_shader(const SpatialMaterialShaderKey& p_key) {
 
 	ERR_FAIL_COND_V(!p_key.valid,RID());
-	Map<FixedSpatialMaterialShaderKey,FixedSpatialMaterialShader>::Element *E=fixed_material_shaders.find(p_key);
+	Map<SpatialMaterialShaderKey,SpatialMaterialShader>::Element *E=fixed_material_shaders.find(p_key);
 
 	if (E) {
 		E->get().refcount++;
@@ -66,7 +66,7 @@ RID Rasterizer::_create_shader(const FixedSpatialMaterialShaderKey& p_key) {
 
 	uint64_t t = OS::get_singleton()->get_ticks_usec();
 
-	FixedSpatialMaterialShader fms;
+	SpatialMaterialShader fms;
 	fms.refcount=1;
 	fms.shader=shader_create();
 
@@ -312,12 +312,12 @@ RID Rasterizer::_create_shader(const FixedSpatialMaterialShaderKey& p_key) {
 	return fms.shader;
 }
 
-void Rasterizer::_free_shader(const FixedSpatialMaterialShaderKey& p_key) {
+void Rasterizer::_free_shader(const SpatialMaterialShaderKey& p_key) {
 
 	if (p_key.valid==0)
 		return; //not a valid key
 
-	Map<FixedSpatialMaterialShaderKey,FixedSpatialMaterialShader>::Element *E=fixed_material_shaders.find(p_key);
+	Map<SpatialMaterialShaderKey,SpatialMaterialShader>::Element *E=fixed_material_shaders.find(p_key);
 
 	ERR_FAIL_COND(!E);
 	E->get().refcount--;
@@ -329,12 +329,12 @@ void Rasterizer::_free_shader(const FixedSpatialMaterialShaderKey& p_key) {
 }
 
 
-void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedSpatialMaterialFlags p_flag, bool p_enabled) {
+void Rasterizer::fixed_material_set_flag(RID p_material, VS::SpatialMaterialFlags p_flag, bool p_enabled) {
 
 
-	Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND(!E);
-	FixedSpatialMaterial &fm=*E->get();
+	SpatialMaterial &fm=*E->get();
 
 	switch(p_flag) {
 
@@ -350,11 +350,11 @@ void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedSpatialMateria
 
 }
 
-bool Rasterizer::fixed_material_get_flag(RID p_material, VS::FixedSpatialMaterialFlags p_flag) const{
+bool Rasterizer::fixed_material_get_flag(RID p_material, VS::SpatialMaterialFlags p_flag) const{
 
-	const Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	const Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND_V(!E,false);
-	const FixedSpatialMaterial &fm=*E->get();
+	const SpatialMaterial &fm=*E->get();
 	switch(p_flag) {
 
 		case VS::FIXED_MATERIAL_FLAG_USE_ALPHA: return fm.use_alpha;; break;
@@ -373,8 +373,8 @@ bool Rasterizer::fixed_material_get_flag(RID p_material, VS::FixedSpatialMateria
 RID Rasterizer::fixed_material_create() {
 
 	RID mat = material_create();
-	fixed_materials[mat]=memnew( FixedSpatialMaterial() );
-	FixedSpatialMaterial &fm=*fixed_materials[mat];
+	fixed_materials[mat]=memnew( SpatialMaterial() );
+	SpatialMaterial &fm=*fixed_materials[mat];
 	fm.self=mat;
 	fm.get_key();
 	material_set_flag(mat,VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB,true);
@@ -390,11 +390,11 @@ RID Rasterizer::fixed_material_create() {
 
 
 
-void Rasterizer::fixed_material_set_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter, const Variant& p_value){
+void Rasterizer::fixed_material_set_parameter(RID p_material, VS::SpatialMaterialParam p_parameter, const Variant& p_value){
 
-	Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND(!E);
-	FixedSpatialMaterial &fm=*E->get();
+	SpatialMaterial &fm=*E->get();
 	RID material=E->key();
 	ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX);
 
@@ -417,24 +417,24 @@ void Rasterizer::fixed_material_set_parameter(RID p_material, VS::FixedSpatialMa
 
 
 }
-Variant Rasterizer::fixed_material_get_parameter(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const{
+Variant Rasterizer::fixed_material_get_parameter(RID p_material,VS::SpatialMaterialParam p_parameter) const{
 
-	const Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	const Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND_V(!E,Variant());
-	const FixedSpatialMaterial &fm=*E->get();
+	const SpatialMaterial &fm=*E->get();
 	ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,Variant());
 	return fm.param[p_parameter];
 }
 
-void Rasterizer::fixed_material_set_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter, RID p_texture){
+void Rasterizer::fixed_material_set_texture(RID p_material,VS::SpatialMaterialParam p_parameter, RID p_texture){
 
-	Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	if (!E) {
 
 		print_line("Not found: "+itos(p_material.get_id()));
 	}
 	ERR_FAIL_COND(!E);
-	FixedSpatialMaterial &fm=*E->get();
+	SpatialMaterial &fm=*E->get();
 
 
 	ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX);
@@ -449,22 +449,22 @@ void Rasterizer::fixed_material_set_texture(RID p_material,VS::FixedSpatialMater
 
 
 }
-RID Rasterizer::fixed_material_get_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const{
+RID Rasterizer::fixed_material_get_texture(RID p_material,VS::SpatialMaterialParam p_parameter) const{
 
-	const Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	const Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND_V(!E,RID());
-	const FixedSpatialMaterial &fm=*E->get();
+	const SpatialMaterial &fm=*E->get();
 	ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,RID());
 
 	return fm.texture[p_parameter];
 }
 
 
-void Rasterizer::fixed_material_set_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter, VS::FixedSpatialMaterialTexCoordMode p_mode) {
+void Rasterizer::fixed_material_set_texcoord_mode(RID p_material,VS::SpatialMaterialParam p_parameter, VS::SpatialMaterialTexCoordMode p_mode) {
 
-	Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND(!E);
-	FixedSpatialMaterial &fm=*E->get();
+	SpatialMaterial &fm=*E->get();
 	ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX);
 
 	fm.get_key();
@@ -476,11 +476,11 @@ void Rasterizer::fixed_material_set_texcoord_mode(RID p_material,VS::FixedSpatia
 
 }
 
-VS::FixedSpatialMaterialTexCoordMode Rasterizer::fixed_material_get_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const {
+VS::SpatialMaterialTexCoordMode Rasterizer::fixed_material_get_texcoord_mode(RID p_material,VS::SpatialMaterialParam p_parameter) const {
 
-	const Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	const Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND_V(!E,VS::FIXED_MATERIAL_TEXCOORD_UV);
-	const FixedSpatialMaterial &fm=*E->get();
+	const SpatialMaterial &fm=*E->get();
 	ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,VS::FIXED_MATERIAL_TEXCOORD_UV);
 
 	return fm.texture_tc[p_parameter];
@@ -488,9 +488,9 @@ VS::FixedSpatialMaterialTexCoordMode Rasterizer::fixed_material_get_texcoord_mod
 
 void Rasterizer::fixed_material_set_uv_transform(RID p_material,const Transform& p_transform) {
 
-	Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND(!E);
-	FixedSpatialMaterial &fm=*E->get();
+	SpatialMaterial &fm=*E->get();
 	RID material=E->key();
 
 	VS::get_singleton()->material_set_param(material,_fixed_material_uv_xform_name,p_transform);
@@ -503,18 +503,18 @@ void Rasterizer::fixed_material_set_uv_transform(RID p_material,const Transform&
 
 Transform Rasterizer::fixed_material_get_uv_transform(RID p_material) const {
 
-	const Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	const Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND_V(!E,Transform());
-	const FixedSpatialMaterial &fm=*E->get();
+	const SpatialMaterial &fm=*E->get();
 
 	return fm.uv_xform;
 }
 
-void Rasterizer::fixed_material_set_light_shader(RID p_material,VS::FixedSpatialMaterialLightShader p_shader) {
+void Rasterizer::fixed_material_set_light_shader(RID p_material,VS::SpatialMaterialLightShader p_shader) {
 
-	Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND(!E);
-	FixedSpatialMaterial &fm=*E->get();
+	SpatialMaterial &fm=*E->get();
 
 	fm.light_shader=p_shader;
 
@@ -523,20 +523,20 @@ void Rasterizer::fixed_material_set_light_shader(RID p_material,VS::FixedSpatial
 
 }
 
-VS::FixedSpatialMaterialLightShader Rasterizer::fixed_material_get_light_shader(RID p_material) const {
+VS::SpatialMaterialLightShader Rasterizer::fixed_material_get_light_shader(RID p_material) const {
 
-	const Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	const Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND_V(!E,VS::FIXED_MATERIAL_LIGHT_SHADER_LAMBERT);
-	const FixedSpatialMaterial &fm=*E->get();
+	const SpatialMaterial &fm=*E->get();
 
 	return fm.light_shader;
 }
 
 void Rasterizer::fixed_material_set_point_size(RID p_material,float p_size) {
 
-	Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND(!E);
-	FixedSpatialMaterial &fm=*E->get();
+	SpatialMaterial &fm=*E->get();
 	RID material=E->key();
 
 	VS::get_singleton()->material_set_param(material,_fixed_material_point_size_name,p_size);
@@ -548,9 +548,9 @@ void Rasterizer::fixed_material_set_point_size(RID p_material,float p_size) {
 
 float Rasterizer::fixed_material_get_point_size(RID p_material) const{
 
-	const Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	const Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 	ERR_FAIL_COND_V(!E,1.0);
-	const FixedSpatialMaterial &fm=*E->get();
+	const SpatialMaterial &fm=*E->get();
 
 	return fm.point_size;
 
@@ -561,9 +561,9 @@ void Rasterizer::_update_fixed_materials() {
 
 	while(fixed_material_dirty_list.first()) {
 
-		FixedSpatialMaterial &fm=*fixed_material_dirty_list.first()->self();
+		SpatialMaterial &fm=*fixed_material_dirty_list.first()->self();
 
-		FixedSpatialMaterialShaderKey new_key = fm.get_key();
+		SpatialMaterialShaderKey new_key = fm.get_key();
 		if (new_key.key!=fm.current_key.key) {
 
 			_free_shader(fm.current_key);
@@ -593,7 +593,7 @@ void Rasterizer::_update_fixed_materials() {
 
 void Rasterizer::_free_fixed_material(const RID& p_material) {
 
-	Map<RID,FixedSpatialMaterial*>::Element *E = fixed_materials.find(p_material);
+	Map<RID,SpatialMaterial*>::Element *E = fixed_materials.find(p_material);
 
 	if (E) {
 
@@ -636,7 +636,7 @@ Rasterizer::Rasterizer() {
 
 	draw_viewport_func=NULL;
 
-	ERR_FAIL_COND( sizeof(FixedSpatialMaterialShaderKey)!=4);
+	ERR_FAIL_COND( sizeof(SpatialMaterialShaderKey)!=4);
 
 }
 

+ 33 - 42
servers/visual/rasterizer.h

@@ -98,9 +98,6 @@ public:
 		//int baked_lightmap_id;
 
 		bool mirror : 8;
-		bool depth_scale : 8;
-		bool billboard : 8;
-		bool billboard_y : 8;
 		bool receive_shadows : 8;
 		bool visible : 8;
 
@@ -120,9 +117,6 @@ public:
 			base_type = VS::INSTANCE_NONE;
 			cast_shadows = VS::SHADOW_CASTING_SETTING_ON;
 			receive_shadows = true;
-			depth_scale = false;
-			billboard = false;
-			billboard_y = false;
 			visible = true;
 			depth_layer = 0;
 			layer_mask = 1;
@@ -198,10 +192,7 @@ public:
 
 	/* SHADER API */
 
-	virtual RID shader_create(VS::ShaderMode p_mode = VS::SHADER_SPATIAL) = 0;
-
-	virtual void shader_set_mode(RID p_shader, VS::ShaderMode p_mode) = 0;
-	virtual VS::ShaderMode shader_get_mode(RID p_shader) const = 0;
+	virtual RID shader_create() = 0;
 
 	virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
 	virtual String shader_get_code(RID p_shader) const = 0;
@@ -452,19 +443,19 @@ public:
 	virtual void particles_set_gravity(RID p_particles, const Vector3 &p_gravity) = 0;
 	virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
 	virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
-
-	virtual void particles_set_emission_shape(RID p_particles, VS::ParticlesEmissionShape p_shape) = 0;
-	virtual void particles_set_emission_sphere_radius(RID p_particles, float p_radius) = 0;
-	virtual void particles_set_emission_box_extents(RID p_particles, const Vector3 &p_extents) = 0;
-	virtual void particles_set_emission_points(RID p_particles, const PoolVector<Vector3> &p_points) = 0;
+	virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
+	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
 
 	virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) = 0;
 
 	virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0;
-	virtual void particles_set_draw_pass_material(RID p_particles, int p_pass, RID p_material) = 0;
 	virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0;
 
+	virtual void particles_request_process(RID p_particles) = 0;
 	virtual Rect3 particles_get_current_aabb(RID p_particles) = 0;
+	virtual Rect3 particles_get_aabb(RID p_particles) const = 0;
+
+	virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0;
 
 	/* RENDER TARGET */
 
@@ -971,7 +962,7 @@ protected:
 
 	/* Fixed Material Shader API */
 
-	union FixedSpatialMaterialShaderKey {
+	union SpatialMaterialShaderKey {
 
 		struct {
 			uint16_t texcoord_mask;
@@ -987,21 +978,21 @@ protected:
 
 		uint32_t key;
 
-		_FORCE_INLINE_ bool operator<(const FixedSpatialMaterialShaderKey& p_key) const { return key<p_key.key; }
+		_FORCE_INLINE_ bool operator<(const SpatialMaterialShaderKey& p_key) const { return key<p_key.key; }
 	};
 
-	struct FixedSpatialMaterialShader {
+	struct SpatialMaterialShader {
 
 		int refcount;
 		RID shader;
 	};
 
-	Map<FixedSpatialMaterialShaderKey,FixedSpatialMaterialShader> fixed_material_shaders;
+	Map<SpatialMaterialShaderKey,SpatialMaterialShader> fixed_material_shaders;
 
-	RID _create_shader(const FixedSpatialMaterialShaderKey& p_key);
-	void _free_shader(const FixedSpatialMaterialShaderKey& p_key);
+	RID _create_shader(const SpatialMaterialShaderKey& p_key);
+	void _free_shader(const SpatialMaterialShaderKey& p_key);
 
-	struct FixedSpatialMaterial {
+	struct SpatialMaterial {
 
 
 		RID self;
@@ -1012,19 +1003,19 @@ protected:
 		bool use_xy_normalmap;
 		float point_size;
 		Transform uv_xform;
-		VS::FixedSpatialMaterialLightShader light_shader;
+		VS::SpatialMaterialLightShader light_shader;
 		RID texture[VS::FIXED_MATERIAL_PARAM_MAX];
 		Variant param[VS::FIXED_MATERIAL_PARAM_MAX];
-		VS::FixedSpatialMaterialTexCoordMode texture_tc[VS::FIXED_MATERIAL_PARAM_MAX];
+		VS::SpatialMaterialTexCoordMode texture_tc[VS::FIXED_MATERIAL_PARAM_MAX];
 
-		SelfList<FixedSpatialMaterial> dirty_list;
+		SelfList<SpatialMaterial> dirty_list;
 
-		FixedSpatialMaterialShaderKey current_key;
+		SpatialMaterialShaderKey current_key;
 
-		_FORCE_INLINE_ FixedSpatialMaterialShaderKey get_key() const {
+		_FORCE_INLINE_ SpatialMaterialShaderKey get_key() const {
 
 
-			FixedSpatialMaterialShaderKey k;
+			SpatialMaterialShaderKey k;
 			k.key=0;
 			k.use_alpha=use_alpha;
 			k.use_color_array=use_color_array;
@@ -1045,7 +1036,7 @@ protected:
 		}
 
 
-		FixedSpatialMaterial() : dirty_list(this) {
+		SpatialMaterial() : dirty_list(this) {
 
 			use_alpha=false;
 			use_color_array=false;
@@ -1077,9 +1068,9 @@ protected:
 	StringName _fixed_material_uv_xform_name;
 	StringName _fixed_material_point_size_name;
 
-	Map<RID,FixedSpatialMaterial*> fixed_materials;
+	Map<RID,SpatialMaterial*> fixed_materials;
 
-	SelfList<FixedSpatialMaterial>::List fixed_material_dirty_list;
+	SelfList<SpatialMaterial>::List fixed_material_dirty_list;
 
 protected:
 	void _update_fixed_materials();
@@ -1166,23 +1157,23 @@ public:
 
 	virtual RID fixed_material_create();
 
-	virtual void fixed_material_set_flag(RID p_material, VS::FixedSpatialMaterialFlags p_flag, bool p_enabled);
-	virtual bool fixed_material_get_flag(RID p_material, VS::FixedSpatialMaterialFlags p_flag) const;
+	virtual void fixed_material_set_flag(RID p_material, VS::SpatialMaterialFlags p_flag, bool p_enabled);
+	virtual bool fixed_material_get_flag(RID p_material, VS::SpatialMaterialFlags p_flag) const;
 
-	virtual void fixed_material_set_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter, const Variant& p_value);
-	virtual Variant fixed_material_get_parameter(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const;
+	virtual void fixed_material_set_parameter(RID p_material, VS::SpatialMaterialParam p_parameter, const Variant& p_value);
+	virtual Variant fixed_material_get_parameter(RID p_material,VS::SpatialMaterialParam p_parameter) const;
 
-	virtual void fixed_material_set_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter, RID p_texture);
-	virtual RID fixed_material_get_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const;
+	virtual void fixed_material_set_texture(RID p_material,VS::SpatialMaterialParam p_parameter, RID p_texture);
+	virtual RID fixed_material_get_texture(RID p_material,VS::SpatialMaterialParam p_parameter) const;
 
-	virtual void fixed_material_set_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter, VS::FixedSpatialMaterialTexCoordMode p_mode);
-	virtual VS::FixedSpatialMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const;
+	virtual void fixed_material_set_texcoord_mode(RID p_material,VS::SpatialMaterialParam p_parameter, VS::SpatialMaterialTexCoordMode p_mode);
+	virtual VS::SpatialMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material,VS::SpatialMaterialParam p_parameter) const;
 
 	virtual void fixed_material_set_uv_transform(RID p_material,const Transform& p_transform);
 	virtual Transform fixed_material_get_uv_transform(RID p_material) const;
 
-	virtual void fixed_material_set_light_shader(RID p_material,VS::FixedSpatialMaterialLightShader p_shader);
-	virtual VS::FixedSpatialMaterialLightShader fixed_material_get_light_shader(RID p_material) const;
+	virtual void fixed_material_set_light_shader(RID p_material,VS::SpatialMaterialLightShader p_shader);
+	virtual VS::SpatialMaterialLightShader fixed_material_get_light_shader(RID p_material) const;
 
 	virtual void fixed_material_set_point_size(RID p_material,float p_size);
 	virtual float fixed_material_get_point_size(RID p_material) const;

+ 309 - 45
servers/visual/shader_language.cpp

@@ -81,7 +81,8 @@ String ShaderLanguage::get_operator_text(Operator p_op) {
 		"++"
 		"--",
 		"()",
-		"construct" };
+		"construct",
+		"index" };
 
 	return op_names[p_op];
 }
@@ -176,6 +177,9 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
 	"PERIOD",
 	"UNIFORM",
 	"VARYING",
+	"IN",
+	"OUT",
+	"INOUT",
 	"RENDER_MODE",
 	"HINT_WHITE_TEXTURE",
 	"HINT_BLACK_TEXTURE",
@@ -185,6 +189,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
 	"HINT_BLACK_ALBEDO_TEXTURE",
 	"HINT_COLOR",
 	"HINT_RANGE",
+	"SHADER_TYPE",
 	"CURSOR",
 	"ERROR",
 	"EOF",
@@ -258,6 +263,9 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
 	{ TK_CF_RETURN, "return" },
 	{ TK_UNIFORM, "uniform" },
 	{ TK_VARYING, "varying" },
+	{ TK_ARG_IN, "in" },
+	{ TK_ARG_OUT, "out" },
+	{ TK_ARG_INOUT, "inout" },
 	{ TK_RENDER_MODE, "render_mode" },
 	{ TK_HINT_WHITE_TEXTURE, "hint_white" },
 	{ TK_HINT_BLACK_TEXTURE, "hint_black" },
@@ -267,6 +275,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
 	{ TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo" },
 	{ TK_HINT_COLOR, "hint_color" },
 	{ TK_HINT_RANGE, "hint_range" },
+	{ TK_SHADER_TYPE, "shader_type" },
 
 	{ TK_ERROR, NULL }
 };
@@ -368,7 +377,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
 				if (GETCHAR(0) == '=') {
 					char_idx++;
 					return _make_token(TK_OP_GREATER_EQUAL);
-				} else if (GETCHAR(0) == '<') {
+				} else if (GETCHAR(0) == '>') {
 					char_idx++;
 					if (GETCHAR(0) == '=') {
 						char_idx++;
@@ -871,7 +880,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
 			}
 
 			if (na == nb) {
-				valid = (na > TYPE_BOOL && na < TYPE_MAT2) || (p_op->op == OP_MUL && na >= TYPE_MAT2 && na <= TYPE_MAT4);
+				valid = (na > TYPE_BOOL && na <= TYPE_MAT4);
 				ret_type = na;
 			} else if (na == TYPE_INT && nb == TYPE_IVEC2) {
 				valid = true;
@@ -900,15 +909,24 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
 			} else if (na == TYPE_FLOAT && nb == TYPE_VEC4) {
 				valid = true;
 				ret_type = TYPE_VEC4;
-			} else if (p_op->op == OP_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
+			} else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT2) {
 				valid = true;
 				ret_type = TYPE_MAT2;
-			} else if (p_op->op == OP_MUL && na == TYPE_VEC3 && nb == TYPE_MAT3) {
+			} else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT3) {
 				valid = true;
 				ret_type = TYPE_MAT3;
-			} else if (p_op->op == OP_MUL && na == TYPE_VEC4 && nb == TYPE_MAT4) {
+			} else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT4) {
 				valid = true;
 				ret_type = TYPE_MAT4;
+			} else if (p_op->op == OP_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
+				valid = true;
+				ret_type = TYPE_VEC2;
+			} else if (p_op->op == OP_MUL && na == TYPE_VEC3 && nb == TYPE_MAT3) {
+				valid = true;
+				ret_type = TYPE_VEC3;
+			} else if (p_op->op == OP_MUL && na == TYPE_VEC4 && nb == TYPE_MAT4) {
+				valid = true;
+				ret_type = TYPE_VEC4;
 			}
 		} break;
 		case OP_ASSIGN_MOD:
@@ -977,14 +995,6 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
 			DataType na = p_op->arguments[0]->get_datatype();
 			DataType nb = p_op->arguments[1]->get_datatype();
 
-			if (na >= TYPE_UINT && na <= TYPE_UVEC4) {
-				na = DataType(na - 4);
-			}
-
-			if (nb >= TYPE_UINT && nb <= TYPE_UVEC4) {
-				nb = DataType(nb - 4);
-			}
-
 			if (na == TYPE_INT && nb == TYPE_INT) {
 				valid = true;
 				ret_type = TYPE_INT;
@@ -1006,6 +1016,27 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
 			} else if (na == TYPE_IVEC4 && nb == TYPE_IVEC4) {
 				valid = true;
 				ret_type = TYPE_IVEC4;
+			} else if (na == TYPE_UINT && nb == TYPE_UINT) {
+				valid = true;
+				ret_type = TYPE_UINT;
+			} else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
+				valid = true;
+				ret_type = TYPE_UVEC2;
+			} else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
+				valid = true;
+				ret_type = TYPE_UVEC3;
+			} else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
+				valid = true;
+				ret_type = TYPE_UVEC4;
+			} else if (na == TYPE_UVEC2 && nb == TYPE_UVEC2) {
+				valid = true;
+				ret_type = TYPE_UVEC2;
+			} else if (na == TYPE_UVEC3 && nb == TYPE_UVEC3) {
+				valid = true;
+				ret_type = TYPE_UVEC3;
+			} else if (na == TYPE_UVEC4 && nb == TYPE_UVEC4) {
+				valid = true;
+				ret_type = TYPE_UVEC4;
 			}
 		} break;
 		case OP_ASSIGN: {
@@ -1651,25 +1682,19 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
 	{ "not", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID } },
 
 	//builtins - texture
-	{ "textureSize", TYPE_VEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID } },
-	{ "textureSize", TYPE_VEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID } },
-	{ "textureSize", TYPE_VEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID } },
-	{ "textureSize", TYPE_VEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID } },
+	{ "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID } },
+	{ "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID } },
+	{ "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID } },
+	{ "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID } },
 
 	{ "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID } },
-	{ "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID } },
 	{ "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
-	{ "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
 
 	{ "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID } },
-	{ "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_VOID } },
 	{ "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
-	{ "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
 
 	{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID } },
-	{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_VOID } },
 	{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
-	{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
 
 	{ "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID } },
 	{ "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
@@ -1689,9 +1714,9 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
 	{ "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
 	{ "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
 
-	{ "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
-	{ "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
-	{ "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+	{ "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
+	{ "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
+	{ "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
 	{ "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
 
 	{ "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } },
@@ -2308,9 +2333,17 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 
 				bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
 
+				//test if function was parsed first
 				for (int i = 0; i < shader->functions.size(); i++) {
 					if (shader->functions[i].name == name) {
-						shader->functions[i].uses_function.insert(name);
+						//add to current function as dependency
+						for (int j = 0; j < shader->functions.size(); j++) {
+							if (shader->functions[j].name == current_function) {
+								shader->functions[j].uses_function.insert(name);
+								break;
+							}
+						}
+						break;
 					}
 				}
 
@@ -2514,18 +2547,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 						}
 
 					} break;
-					case TYPE_MAT2:
-						ok = (ident == "x" || ident == "y");
-						member_type = TYPE_VEC2;
-						break;
-					case TYPE_MAT3:
-						ok = (ident == "x" || ident == "y" || ident == "z");
-						member_type = TYPE_VEC3;
-						break;
-					case TYPE_MAT4:
-						ok = (ident == "x" || ident == "y" || ident == "z" || ident == "w");
-						member_type = TYPE_VEC4;
-						break;
+
 					default: {}
 				}
 
@@ -2552,6 +2574,116 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 				//creates a subindexing expression in place
 
 	*/
+			} else if (tk.type == TK_BRACKET_OPEN) {
+
+				Node *index = _parse_and_reduce_expression(p_block, p_builtin_types);
+
+				if (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT) {
+					_set_error("Only integer datatypes are allowed for indexing");
+					return NULL;
+				}
+
+				bool index_valid = false;
+				DataType member_type;
+
+				switch (expr->get_datatype()) {
+					case TYPE_BVEC2:
+					case TYPE_VEC2:
+					case TYPE_IVEC2:
+					case TYPE_UVEC2:
+					case TYPE_MAT2:
+						if (index->type == Node::TYPE_CONSTANT) {
+							uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+							if (index_constant >= 2) {
+								_set_error("Index out of range (0-1)");
+								return NULL;
+							}
+						} else {
+							_set_error("Only integer constants are allowed as index at the moment");
+							return NULL;
+						}
+						index_valid = true;
+						switch (expr->get_datatype()) {
+							case TYPE_BVEC2: member_type = TYPE_BOOL; break;
+							case TYPE_VEC2: member_type = TYPE_FLOAT; break;
+							case TYPE_IVEC2: member_type = TYPE_INT; break;
+							case TYPE_UVEC2: member_type = TYPE_UINT; break;
+							case TYPE_MAT2: member_type = TYPE_VEC2; break;
+						}
+
+						break;
+					case TYPE_BVEC3:
+					case TYPE_VEC3:
+					case TYPE_IVEC3:
+					case TYPE_UVEC3:
+					case TYPE_MAT3:
+						if (index->type == Node::TYPE_CONSTANT) {
+							uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+							if (index_constant >= 3) {
+								_set_error("Index out of range (0-2)");
+								return NULL;
+							}
+						} else {
+							_set_error("Only integer constants are allowed as index at the moment");
+							return NULL;
+						}
+						index_valid = true;
+						switch (expr->get_datatype()) {
+							case TYPE_BVEC3: member_type = TYPE_BOOL; break;
+							case TYPE_VEC3: member_type = TYPE_FLOAT; break;
+							case TYPE_IVEC3: member_type = TYPE_INT; break;
+							case TYPE_UVEC3: member_type = TYPE_UINT; break;
+							case TYPE_MAT3: member_type = TYPE_VEC3; break;
+						}
+						break;
+					case TYPE_BVEC4:
+					case TYPE_VEC4:
+					case TYPE_IVEC4:
+					case TYPE_UVEC4:
+					case TYPE_MAT4:
+						if (index->type == Node::TYPE_CONSTANT) {
+							uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+							if (index_constant >= 4) {
+								_set_error("Index out of range (0-3)");
+								return NULL;
+							}
+						} else {
+							_set_error("Only integer constants are allowed as index at the moment");
+							return NULL;
+						}
+						index_valid = true;
+						switch (expr->get_datatype()) {
+							case TYPE_BVEC4: member_type = TYPE_BOOL; break;
+							case TYPE_VEC4: member_type = TYPE_FLOAT; break;
+							case TYPE_IVEC4: member_type = TYPE_INT; break;
+							case TYPE_UVEC4: member_type = TYPE_UINT; break;
+							case TYPE_MAT4: member_type = TYPE_VEC4; break;
+						}
+						break;
+					default: {
+						_set_error("Object of type '" + get_datatype_name(expr->get_datatype()) + "' can't be indexed");
+						return NULL;
+					}
+				}
+
+				if (!index_valid) {
+					_set_error("Invalid index");
+					return NULL;
+				}
+
+				OperatorNode *op = alloc_node<OperatorNode>();
+				op->op = OP_INDEX;
+				op->return_cache = member_type;
+				op->arguments.push_back(expr);
+				op->arguments.push_back(index);
+				expr = op;
+
+				tk = _get_token();
+				if (tk.type != TK_BRACKET_CLOSE) {
+					_set_error("Expected ']' after indexing expression");
+					return NULL;
+				}
+
 			} else if (tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) {
 
 				OperatorNode *op = alloc_node<OperatorNode>();
@@ -3077,6 +3209,52 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Dat
 				_set_tkpos(pos); //rollback
 			}
 
+		} else if (tk.type == TK_CF_RETURN) {
+
+			//check return type
+			BlockNode *b = p_block;
+			while (b && !b->parent_function) {
+				b = b->parent_block;
+			}
+
+			if (!b) {
+				_set_error("Bug");
+				return ERR_BUG;
+			}
+
+			ControlFlowNode *flow = alloc_node<ControlFlowNode>();
+			flow->flow_op = FLOW_OP_RETURN;
+
+			pos = _get_tkpos();
+			tk = _get_token();
+			if (tk.type == TK_SEMICOLON) {
+				//all is good
+				if (b->parent_function->return_type != TYPE_VOID) {
+					_set_error("Expected return with expression of type '" + get_datatype_name(b->parent_function->return_type) + "'");
+					return ERR_PARSE_ERROR;
+				}
+			} else {
+				_set_tkpos(pos); //rollback, wants expression
+				Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+				if (!expr)
+					return ERR_PARSE_ERROR;
+
+				if (b->parent_function->return_type != expr->get_datatype()) {
+					_set_error("Expected return expression of type '" + get_datatype_name(b->parent_function->return_type) + "'");
+					return ERR_PARSE_ERROR;
+				}
+
+				tk = _get_token();
+				if (tk.type != TK_SEMICOLON) {
+					_set_error("Expected ';' after return expression");
+					return ERR_PARSE_ERROR;
+				}
+
+				flow->expressions.push_back(expr);
+			}
+
+			p_block->statements.push_back(flow);
+
 		} else {
 
 			//nothng else, so expression
@@ -3100,10 +3278,47 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Dat
 	return OK;
 }
 
-Error ShaderLanguage::_parse_shader(const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes) {
+Error ShaderLanguage::_parse_shader(const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes, const Set<String> &p_shader_types) {
 
 	Token tk = _get_token();
 
+	if (tk.type != TK_SHADER_TYPE) {
+		_set_error("Expected 'shader_type' at the begining of shader.");
+		return ERR_PARSE_ERROR;
+	}
+
+	tk = _get_token();
+
+	if (tk.type != TK_IDENTIFIER) {
+		_set_error("Expected identifier after 'shader_type', indicating type of shader.");
+		return ERR_PARSE_ERROR;
+	}
+
+	String shader_type_identifier;
+
+	shader_type_identifier = tk.text;
+
+	if (!p_shader_types.has(shader_type_identifier)) {
+
+		String valid;
+		for (Set<String>::Element *E = p_shader_types.front(); E; E = E->next()) {
+			if (valid != String()) {
+				valid += ", ";
+			}
+			valid += "'" + E->get() + "'";
+		}
+		_set_error("Invalid shader type, valid types are: " + valid);
+		return ERR_PARSE_ERROR;
+	}
+
+	tk = _get_token();
+
+	if (tk.type != TK_SEMICOLON) {
+		_set_error("Expected ';' after 'shader_type <type>'.");
+	}
+
+	tk = _get_token();
+
 	int texture_uniforms = 0;
 	int uniforms = 0;
 
@@ -3428,6 +3643,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, Map<StringName, DataTy
 						break;
 					}
 
+					ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN;
+
+					if (tk.type == TK_ARG_IN) {
+						qualifier = ARGUMENT_QUALIFIER_IN;
+						tk = _get_token();
+					} else if (tk.type == TK_ARG_OUT) {
+						qualifier = ARGUMENT_QUALIFIER_OUT;
+						tk = _get_token();
+					} else if (tk.type == TK_ARG_INOUT) {
+						qualifier = ARGUMENT_QUALIFIER_INOUT;
+						tk = _get_token();
+					}
+
 					DataType ptype;
 					StringName pname;
 					DataPrecision pprecision = PRECISION_DEFAULT;
@@ -3466,6 +3694,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, Map<StringName, DataTy
 					arg.type = ptype;
 					arg.name = pname;
 					arg.precision = pprecision;
+					arg.qualifier = qualifier;
 
 					func_node->arguments.push_back(arg);
 
@@ -3515,7 +3744,42 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, Map<StringName, DataTy
 	return OK;
 }
 
-Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes) {
+String ShaderLanguage::get_shader_type(const String &p_code) {
+
+	bool reading_type = false;
+
+	String cur_identifier;
+
+	for (int i = 0; i < p_code.length() + 1; i++) {
+
+		if (p_code[i] == ';') {
+			break;
+
+		} else if (p_code[i] <= 32) {
+			if (cur_identifier != String()) {
+				if (!reading_type) {
+					if (cur_identifier != "shader_type") {
+						return String();
+					}
+
+					reading_type = true;
+					cur_identifier = String();
+				} else {
+					return cur_identifier;
+				}
+			}
+		} else {
+			cur_identifier += String::chr(p_code[i]);
+		}
+	}
+
+	if (reading_type)
+		return cur_identifier;
+
+	return String();
+}
+
+Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes, const Set<String> &p_shader_types) {
 
 	clear();
 
@@ -3524,7 +3788,7 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Map<St
 	nodes = NULL;
 
 	shader = alloc_node<ShaderNode>();
-	Error err = _parse_shader(p_functions, p_render_modes);
+	Error err = _parse_shader(p_functions, p_render_modes, p_shader_types);
 
 	if (err != OK) {
 		return err;
@@ -3532,7 +3796,7 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Map<St
 	return OK;
 }
 
-Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes, List<String> *r_options, String &r_call_hint) {
+Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes, const Set<String> &p_shader_types, List<String> *r_options, String &r_call_hint) {
 
 	clear();
 
@@ -3541,7 +3805,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Map<S
 	nodes = NULL;
 
 	shader = alloc_node<ShaderNode>();
-	Error err = _parse_shader(p_functions, p_render_modes);
+	Error err = _parse_shader(p_functions, p_render_modes, p_shader_types);
 
 	switch (completion_type) {
 

+ 18 - 3
servers/visual/shader_language.h

@@ -130,6 +130,9 @@ public:
 		TK_PERIOD,
 		TK_UNIFORM,
 		TK_VARYING,
+		TK_ARG_IN,
+		TK_ARG_OUT,
+		TK_ARG_INOUT,
 		TK_RENDER_MODE,
 		TK_HINT_WHITE_TEXTURE,
 		TK_HINT_BLACK_TEXTURE,
@@ -139,6 +142,7 @@ public:
 		TK_HINT_BLACK_ALBEDO_TEXTURE,
 		TK_HINT_COLOR,
 		TK_HINT_RANGE,
+		TK_SHADER_TYPE,
 		TK_CURSOR,
 		TK_ERROR,
 		TK_EOF,
@@ -227,6 +231,7 @@ public:
 		OP_POST_DECREMENT,
 		OP_CALL,
 		OP_CONSTRUCT,
+		OP_INDEX,
 		OP_MAX
 	};
 
@@ -242,6 +247,13 @@ public:
 
 	};
 
+	enum ArgumentQualifier {
+		ARGUMENT_QUALIFIER_IN,
+		ARGUMENT_QUALIFIER_OUT,
+		ARGUMENT_QUALIFIER_INOUT,
+
+	};
+
 	struct Node {
 
 		Node *next;
@@ -363,6 +375,7 @@ public:
 
 		struct Argument {
 
+			ArgumentQualifier qualifier;
 			StringName name;
 			DataType type;
 			DataPrecision precision;
@@ -577,14 +590,16 @@ private:
 
 	Error _parse_block(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false);
 
-	Error _parse_shader(const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes);
+	Error _parse_shader(const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes, const Set<String> &p_shader_types);
 
 public:
 	//static void get_keyword_list(ShaderType p_type,List<String> *p_keywords);
 
 	void clear();
-	Error compile(const String &p_code, const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes);
-	Error complete(const String &p_code, const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes, List<String> *r_options, String &r_call_hint);
+
+	static String get_shader_type(const String &p_code);
+	Error compile(const String &p_code, const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes, const Set<String> &p_shader_types);
+	Error complete(const String &p_code, const Map<StringName, Map<StringName, DataType> > &p_functions, const Set<String> &p_render_modes, const Set<String> &p_shader_types, List<String> *r_options, String &r_call_hint);
 
 	String get_error_text();
 	int get_error_line();

+ 19 - 4
servers/visual/shader_types.cpp

@@ -38,6 +38,10 @@ const Set<String> &ShaderTypes::get_modes(VS::ShaderMode p_mode) {
 	return shader_modes[p_mode].modes;
 }
 
+const Set<String> &ShaderTypes::get_types() {
+	return shader_types;
+}
+
 ShaderTypes *ShaderTypes::singleton = NULL;
 
 ShaderTypes::ShaderTypes() {
@@ -61,11 +65,14 @@ ShaderTypes::ShaderTypes() {
 	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["COLOR"] = ShaderLanguage::TYPE_VEC4;
 	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["INSTANCE_ID"] = ShaderLanguage::TYPE_INT;
+	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["INSTANCE_CUSTOM"] = ShaderLanguage::TYPE_VEC4;
 
 	//builtins
 	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4;
 	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["INV_CAMERA_MATRIX"] = ShaderLanguage::TYPE_MAT4;
+	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["CAMERA_MATRIX"] = ShaderLanguage::TYPE_MAT4;
 	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4;
+	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4;
 	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["TIME"] = ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["VIEWPORT_SIZE"] = ShaderLanguage::TYPE_VEC2;
 
@@ -122,7 +129,7 @@ ShaderTypes::ShaderTypes() {
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("unshaded");
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("ontop");
 
-	shader_modes[VS::SHADER_SPATIAL].modes.insert("skip_transform");
+	shader_modes[VS::SHADER_SPATIAL].modes.insert("skip_default_transform");
 
 	/************ CANVAS ITEM **************************/
 
@@ -136,6 +143,7 @@ ShaderTypes::ShaderTypes() {
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4;
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["EXTRA_MATRIX"] = ShaderLanguage::TYPE_MAT4;
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["TIME"] = ShaderLanguage::TYPE_FLOAT;
+	shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["PARTICLE_CUSTOM"] = ShaderLanguage::TYPE_VEC4;
 
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SRC_COLOR"] = ShaderLanguage::TYPE_VEC4;
 	shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["POSITION"] = ShaderLanguage::TYPE_VEC2;
@@ -189,14 +197,21 @@ ShaderTypes::ShaderTypes() {
 	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["RESTART"] = ShaderLanguage::TYPE_BOOL;
 	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
 	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
-	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["TIME"] = ShaderLanguage::TYPE_FLOAT;
+	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["TIME"] = ShaderLanguage::TYPE_VEC4;
 	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["LIFETIME"] = ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["DELTA"] = ShaderLanguage::TYPE_FLOAT;
-	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["SEED"] = ShaderLanguage::TYPE_BOOL;
-	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["ORIGIN"] = ShaderLanguage::TYPE_MAT4;
+	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["NUMBER"] = ShaderLanguage::TYPE_UINT;
 	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["INDEX"] = ShaderLanguage::TYPE_INT;
+	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["SEED"] = ShaderLanguage::TYPE_UINT;
+	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["GRAVITY"] = ShaderLanguage::TYPE_VEC3;
+	shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["EMISSION_TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
 
 	shader_modes[VS::SHADER_PARTICLES].modes.insert("billboard");
 	shader_modes[VS::SHADER_PARTICLES].modes.insert("disable_force");
 	shader_modes[VS::SHADER_PARTICLES].modes.insert("disable_velocity");
+	shader_modes[VS::SHADER_PARTICLES].modes.insert("keep_data");
+
+	shader_types.insert("spatial");
+	shader_types.insert("canvas_item");
+	shader_types.insert("particles");
 }

+ 3 - 0
servers/visual/shader_types.h

@@ -43,11 +43,14 @@ class ShaderTypes {
 
 	static ShaderTypes *singleton;
 
+	Set<String> shader_types;
+
 public:
 	static ShaderTypes *get_singleton() { return singleton; }
 
 	const Map<StringName, Map<StringName, ShaderLanguage::DataType> > &get_functions(VS::ShaderMode p_mode);
 	const Set<String> &get_modes(VS::ShaderMode p_mode);
+	const Set<String> &get_types();
 
 	ShaderTypes();
 };

+ 18 - 16
servers/visual/visual_server_raster.cpp

@@ -38,6 +38,8 @@
 
 // careful, these may run in different threads than the visual server
 
+int VisualServerRaster::changes = 0;
+
 /* CURSOR */
 void VisualServerRaster::cursor_set_rotation(float p_rotation, int p_cursor) {
 }
@@ -391,33 +393,33 @@ RID VisualServerRaster::fixed_material_create() {
 	return rasterizer->fixed_material_create();
 }
 
-void VisualServerRaster::fixed_material_set_flag(RID p_material, FixedSpatialMaterialFlags p_flag, bool p_enabled) {
+void VisualServerRaster::fixed_material_set_flag(RID p_material, SpatialMaterialFlags p_flag, bool p_enabled) {
 
 	rasterizer->fixed_material_set_flag(p_material,p_flag,p_enabled);
 }
 
-bool VisualServerRaster::fixed_material_get_flag(RID p_material, FixedSpatialMaterialFlags p_flag) const {
+bool VisualServerRaster::fixed_material_get_flag(RID p_material, SpatialMaterialFlags p_flag) const {
 
 	return rasterizer->fixed_material_get_flag(p_material,p_flag);
 }
 
-void VisualServerRaster::fixed_material_set_param(RID p_material, FixedSpatialMaterialParam p_parameter, const Variant& p_value) {
+void VisualServerRaster::fixed_material_set_param(RID p_material, SpatialMaterialParam p_parameter, const Variant& p_value) {
 	VS_CHANGED;
 	rasterizer->fixed_material_set_parameter(p_material,p_parameter,p_value);
 }
 
-Variant VisualServerRaster::fixed_material_get_param(RID p_material,FixedSpatialMaterialParam p_parameter) const {
+Variant VisualServerRaster::fixed_material_get_param(RID p_material,SpatialMaterialParam p_parameter) const {
 
 	return rasterizer->fixed_material_get_parameter(p_material,p_parameter);
 }
 
 
-void VisualServerRaster::fixed_material_set_texture(RID p_material,FixedSpatialMaterialParam p_parameter, RID p_texture) {
+void VisualServerRaster::fixed_material_set_texture(RID p_material,SpatialMaterialParam p_parameter, RID p_texture) {
 	VS_CHANGED;
 	rasterizer->fixed_material_set_texture(p_material,p_parameter,p_texture);
 }
 
-RID VisualServerRaster::fixed_material_get_texture(RID p_material,FixedSpatialMaterialParam p_parameter) const {
+RID VisualServerRaster::fixed_material_get_texture(RID p_material,SpatialMaterialParam p_parameter) const {
 
 	return rasterizer->fixed_material_get_texture(p_material,p_parameter);
 }
@@ -425,12 +427,12 @@ RID VisualServerRaster::fixed_material_get_texture(RID p_material,FixedSpatialMa
 
 
 
-void VisualServerRaster::fixed_material_set_texcoord_mode(RID p_material,FixedSpatialMaterialParam p_parameter, FixedSpatialMaterialTexCoordMode p_mode) {
+void VisualServerRaster::fixed_material_set_texcoord_mode(RID p_material,SpatialMaterialParam p_parameter, SpatialMaterialTexCoordMode p_mode) {
 	VS_CHANGED;
 	rasterizer->fixed_material_set_texcoord_mode(p_material,p_parameter,p_mode);
 }
 
-VS::FixedSpatialMaterialTexCoordMode VisualServerRaster::fixed_material_get_texcoord_mode(RID p_material,FixedSpatialMaterialParam p_parameter) const {
+VS::SpatialMaterialTexCoordMode VisualServerRaster::fixed_material_get_texcoord_mode(RID p_material,SpatialMaterialParam p_parameter) const {
 
 	return rasterizer->fixed_material_get_texcoord_mode(p_material,p_parameter);
 }
@@ -457,14 +459,14 @@ Transform VisualServerRaster::fixed_material_get_uv_transform(RID p_material) co
 	return rasterizer->fixed_material_get_uv_transform(p_material);
 }
 
-void VisualServerRaster::fixed_material_set_light_shader(RID p_material,FixedSpatialMaterialLightShader p_shader) {
+void VisualServerRaster::fixed_material_set_light_shader(RID p_material,SpatialMaterialLightShader p_shader) {
 
 	VS_CHANGED;
 	rasterizer->fixed_material_set_light_shader(p_material,p_shader);
 
 }
 
-VisualServerRaster::FixedSpatialMaterialLightShader VisualServerRaster::fixed_material_get_light_shader(RID p_material) const{
+VisualServerRaster::SpatialMaterialLightShader VisualServerRaster::fixed_material_get_light_shader(RID p_material) const{
 
 	return rasterizer->fixed_material_get_light_shader(p_material);
 }
@@ -4521,7 +4523,7 @@ void VisualServerRaster::canvas_occluder_polygon_set_cull_mode(RID p_occluder_po
 
 RID VisualServerRaster::canvas_item_material_create() {
 
-	Rasterizer::CanvasItemMaterial *material = memnew( Rasterizer::CanvasItemMaterial );
+	Rasterizer::ShaderMaterial *material = memnew( Rasterizer::ShaderMaterial );
 	return canvas_item_material_owner.make_rid(material);
 
 }
@@ -4529,7 +4531,7 @@ RID VisualServerRaster::canvas_item_material_create() {
 void VisualServerRaster::canvas_item_material_set_shader(RID p_material, RID p_shader){
 
 	VS_CHANGED;
-	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+	Rasterizer::ShaderMaterial *material = canvas_item_material_owner.get( p_material );
 	ERR_FAIL_COND(!material);
 	material->shader=p_shader;
 
@@ -4537,7 +4539,7 @@ void VisualServerRaster::canvas_item_material_set_shader(RID p_material, RID p_s
 void VisualServerRaster::canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value){
 
 	VS_CHANGED;
-	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+	Rasterizer::ShaderMaterial *material = canvas_item_material_owner.get( p_material );
 	ERR_FAIL_COND(!material);
 	if (p_value.get_type()==Variant::NIL)
 		material->shader_param.erase(p_param);
@@ -4547,7 +4549,7 @@ void VisualServerRaster::canvas_item_material_set_shader_param(RID p_material, c
 
 }
 Variant VisualServerRaster::canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const{
-	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+	Rasterizer::ShaderMaterial *material = canvas_item_material_owner.get( p_material );
 	ERR_FAIL_COND_V(!material,Variant());
 	if (!material->shader_param.has(p_param)) {
 		ERR_FAIL_COND_V(!material->shader.is_valid(),Variant());
@@ -4560,7 +4562,7 @@ Variant VisualServerRaster::canvas_item_material_get_shader_param(RID p_material
 void VisualServerRaster::canvas_item_material_set_shading_mode(RID p_material, CanvasItemShadingMode p_mode) {
 
 	VS_CHANGED;
-	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+	Rasterizer::ShaderMaterial *material = canvas_item_material_owner.get( p_material );
 	ERR_FAIL_COND(!material);
 	material->shading_mode=p_mode;
 
@@ -4869,7 +4871,7 @@ void VisualServerRaster::free( RID p_rid ) {
 
 	} else if (canvas_item_material_owner.owns(p_rid)) {
 
-		Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get(p_rid);
+		Rasterizer::ShaderMaterial *material = canvas_item_material_owner.get(p_rid);
 		ERR_FAIL_COND(!material);
 		for(Set<Rasterizer::CanvasItem*>::Element *E=material->owners.front();E;E=E->next()) {
 

+ 7 - 12
servers/visual/visual_server_raster.h

@@ -56,7 +56,7 @@ class VisualServerRaster : public VisualServer {
 
 	};
 
-	int changes;
+	static int changes;
 	bool draw_extra_frame;
 	RID test_cube;
 
@@ -376,7 +376,7 @@ class VisualServerRaster : public VisualServer {
 
 
 
-	mutable RID_Owner<Rasterizer::CanvasItemMaterial> canvas_item_material_owner;
+	mutable RID_Owner<Rasterizer::ShaderMaterial> canvas_item_material_owner;
 
 
 
@@ -575,6 +575,8 @@ class VisualServerRaster : public VisualServer {
 #endif
 
 public:
+	_FORCE_INLINE_ static void redraw_request() { changes++; }
+
 #define DISPLAY_CHANGED changes++;
 
 #define BIND0R(m_r, m_name) \
@@ -647,10 +649,7 @@ public:
 
 	/* SHADER API */
 
-	BIND1R(RID, shader_create, ShaderMode)
-
-	BIND2(shader_set_mode, RID, ShaderMode)
-	BIND1RC(ShaderMode, shader_get_mode, RID)
+	BIND0R(RID, shader_create)
 
 	BIND2(shader_set_code, RID, const String &)
 	BIND1RC(String, shader_get_code, RID)
@@ -855,16 +854,12 @@ public:
 	BIND2(particles_set_gravity, RID, const Vector3 &)
 	BIND2(particles_set_use_local_coordinates, RID, bool)
 	BIND2(particles_set_process_material, RID, RID)
-
-	BIND2(particles_set_emission_shape, RID, VS::ParticlesEmissionShape)
-	BIND2(particles_set_emission_sphere_radius, RID, float)
-	BIND2(particles_set_emission_box_extents, RID, const Vector3 &)
-	BIND2(particles_set_emission_points, RID, const PoolVector<Vector3> &)
+	BIND2(particles_set_fixed_fps, RID, int)
+	BIND2(particles_set_fractional_delta, RID, bool)
 
 	BIND2(particles_set_draw_order, RID, VS::ParticlesDrawOrder)
 
 	BIND2(particles_set_draw_passes, RID, int)
-	BIND3(particles_set_draw_pass_material, RID, int, RID)
 	BIND3(particles_set_draw_pass_mesh, RID, int, RID)
 
 	BIND1R(Rect3, particles_get_current_aabb, RID);

+ 20 - 16
servers/visual/visual_server_scene.cpp

@@ -29,6 +29,7 @@
 #include "visual_server_scene.h"
 #include "os/os.h"
 #include "visual_server_global.h"
+#include "visual_server_raster.h"
 /* CAMERA API */
 
 RID VisualServerScene::camera_create() {
@@ -609,7 +610,8 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
 			} break;
 			case VS::INSTANCE_MESH:
 			case VS::INSTANCE_MULTIMESH:
-			case VS::INSTANCE_IMMEDIATE: {
+			case VS::INSTANCE_IMMEDIATE:
+			case VS::INSTANCE_PARTICLES: {
 
 				InstanceGeometryData *geom = memnew(InstanceGeometryData);
 				instance->base_data = geom;
@@ -975,16 +977,6 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF
 
 	switch (p_flags) {
 
-		case VS::INSTANCE_FLAG_BILLBOARD: {
-
-			instance->billboard = p_enabled;
-
-		} break;
-		case VS::INSTANCE_FLAG_BILLBOARD_FIX_Y: {
-
-			instance->billboard_y = p_enabled;
-
-		} break;
 		case VS::INSTANCE_FLAG_CAST_SHADOW: {
 			if (p_enabled == true) {
 				instance->cast_shadows = VS::SHADOW_CASTING_SETTING_ON;
@@ -994,11 +986,6 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF
 
 			instance->base_material_changed(); // to actually compute if shadows are visible or not
 
-		} break;
-		case VS::INSTANCE_FLAG_DEPH_SCALE: {
-
-			instance->depth_scale = p_enabled;
-
 		} break;
 		case VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS: {
 
@@ -1050,6 +1037,11 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
 		reflection_probe->reflection_dirty = true;
 	}
 
+	if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
+
+		VSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
+	}
+
 	if (p_instance->aabb.has_no_surface())
 		return;
 
@@ -1235,6 +1227,11 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
 			new_aabb = VSG::storage->immediate_get_aabb(p_instance->base);
 
 		} break;
+		case VisualServer::INSTANCE_PARTICLES: {
+
+			new_aabb = VSG::storage->particles_get_aabb(p_instance->base);
+
+		} break;
 #if 0
 
 		case VisualServer::INSTANCE_PARTICLES: {
@@ -1914,6 +1911,13 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform, const Cam
 
 			InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(ins->base_data);
 
+			if (ins->base_type == VS::INSTANCE_PARTICLES) {
+				//particles visible? process them
+				VSG::storage->particles_request_process(ins->base);
+				//particles visible? request redraw
+				VisualServerRaster::redraw_request();
+			}
+
 			if (geom->lighting_dirty) {
 				int l = 0;
 				//only called when lights AABB enter/exit this geometry

+ 4 - 27
servers/visual_server.h

@@ -153,10 +153,7 @@ public:
 		SHADER_MAX
 	};
 
-	virtual RID shader_create(ShaderMode p_mode = SHADER_SPATIAL) = 0;
-
-	virtual void shader_set_mode(RID p_shader, ShaderMode p_mode) = 0;
-	virtual ShaderMode shader_get_mode(RID p_shader) const = 0;
+	virtual RID shader_create() = 0;
 
 	virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
 	virtual String shader_get_code(RID p_shader) const = 0;
@@ -485,19 +482,8 @@ public:
 	virtual void particles_set_gravity(RID p_particles, const Vector3 &p_gravity) = 0;
 	virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
 	virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
-
-	enum ParticlesEmissionShape {
-		PARTICLES_EMSSION_POINT,
-		PARTICLES_EMSSION_SPHERE,
-		PARTICLES_EMSSION_BOX,
-		PARTICLES_EMSSION_POINTS,
-		PARTICLES_EMSSION_SEGMENTS,
-	};
-
-	virtual void particles_set_emission_shape(RID p_particles, ParticlesEmissionShape) = 0;
-	virtual void particles_set_emission_sphere_radius(RID p_particles, float p_radius) = 0;
-	virtual void particles_set_emission_box_extents(RID p_particles, const Vector3 &p_extents) = 0;
-	virtual void particles_set_emission_points(RID p_particles, const PoolVector<Vector3> &p_points) = 0;
+	virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
+	virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
 
 	enum ParticlesDrawOrder {
 		PARTICLES_DRAW_ORDER_INDEX,
@@ -507,13 +493,7 @@ public:
 
 	virtual void particles_set_draw_order(RID p_particles, ParticlesDrawOrder p_order) = 0;
 
-	enum ParticlesDrawPassMode {
-		PARTICLES_DRAW_PASS_MODE_QUAD,
-		PARTICLES_DRAW_PASS_MODE_MESH
-	};
-
 	virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0;
-	virtual void particles_set_draw_pass_material(RID p_particles, int p_pass, RID p_material) = 0;
 	virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0;
 
 	virtual Rect3 particles_get_current_aabb(RID p_particles) = 0;
@@ -689,7 +669,7 @@ public:
 		INSTANCE_MAX,
 		/*INSTANCE_BAKED_LIGHT_SAMPLER,*/
 
-		INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE)
+		INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES)
 	};
 
 	virtual RID instance_create2(RID p_base, RID p_scenario);
@@ -718,10 +698,7 @@ public:
 	virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const = 0;
 
 	enum InstanceFlags {
-		INSTANCE_FLAG_BILLBOARD,
-		INSTANCE_FLAG_BILLBOARD_FIX_Y,
 		INSTANCE_FLAG_CAST_SHADOW,
-		INSTANCE_FLAG_DEPH_SCALE,
 		INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,
 		INSTANCE_FLAG_USE_BAKED_LIGHT,
 		INSTANCE_FLAG_MAX

Some files were not shown because too many files changed in this diff