浏览代码

support for 2D shadow casters

Added support for 2D shadow casters.

*DANGER* Shaders in CanvasItem CHANGED, if you are using shader in a
CanvasItem and pull this, you will lose them. Shaders now work through a
2D material system similar to 3D. If you don't want to lose the 2D
shader code, save the shader as a .shd, then create a material in
CanvasItem and re-assign the shader.
Juan Linietsky 10 年之前
父节点
当前提交
a1f715a4da
共有 43 个文件被更改,包括 2583 次插入268 次删除
  1. 10 0
      core/io/resource_format_binary.cpp
  2. 5 0
      core/io/resource_format_xml.cpp
  3. 18 1
      core/math/camera_matrix.cpp
  4. 3 0
      core/variant_op.cpp
  5. 二进制
      demos/3d/kinematic_char/cubelib.res
  6. 二进制
      demos/3d/kinematic_char/level.scn
  7. 0 1
      drivers/SCsub
  8. 571 27
      drivers/gles2/rasterizer_gles2.cpp
  9. 59 3
      drivers/gles2/rasterizer_gles2.h
  10. 1 0
      drivers/gles2/shaders/SCsub
  11. 113 10
      drivers/gles2/shaders/canvas.glsl
  12. 62 0
      drivers/gles2/shaders/canvas_shadow.glsl
  13. 17 3
      drivers/windows/file_access_windows.cpp
  14. 4 1
      modules/gdscript/gd_script.cpp
  15. 8 0
      platform/android/audio_driver_opensl.cpp
  16. 1 1
      platform/android/os_android.cpp
  17. 2 2
      platform/windows/detect.py
  18. 207 102
      scene/2d/canvas_item.cpp
  19. 41 18
      scene/2d/canvas_item.h
  20. 41 8
      scene/2d/light_2d.cpp
  21. 8 0
      scene/2d/light_2d.h
  22. 201 0
      scene/2d/light_occluder_2d.cpp
  23. 73 0
      scene/2d/light_occluder_2d.h
  24. 3 3
      scene/3d/camera.cpp
  25. 15 0
      scene/3d/visual_instance.cpp
  26. 4 0
      scene/3d/visual_instance.h
  27. 4 0
      scene/register_scene_types.cpp
  28. 1 0
      scene/scene_string_names.cpp
  29. 1 0
      scene/scene_string_names.h
  30. 58 9
      servers/visual/rasterizer.h
  31. 333 44
      servers/visual/visual_server_raster.cpp
  32. 46 15
      servers/visual/visual_server_raster.h
  33. 21 9
      servers/visual/visual_server_wrap_mt.h
  34. 25 8
      servers/visual_server.h
  35. 2 0
      tools/editor/editor_node.cpp
  36. 二进制
      tools/editor/icons/icon_canvas_item_material.png
  37. 二进制
      tools/editor/icons/icon_canvas_modulate.png
  38. 二进制
      tools/editor/icons/icon_light_occluder_2d.png
  39. 二进制
      tools/editor/icons/icon_occluder_polygon_2d.png
  40. 1 0
      tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp
  41. 500 0
      tools/editor/plugins/light_occluder_2d_editor_plugin.cpp
  42. 87 0
      tools/editor/plugins/light_occluder_2d_editor_plugin.h
  43. 37 3
      tools/editor/property_editor.cpp

+ 10 - 0
core/io/resource_format_binary.cpp

@@ -1778,6 +1778,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
 	f->store_32(VERSION_MINOR);
 	f->store_32(FORMAT_VERSION);
 
+	if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
+		f->close();
+		return ERR_CANT_CREATE;
+	}
+
 	//f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
 	save_unicode_string(p_resource->get_type());
 	uint64_t md_at = f->get_pos();
@@ -1910,6 +1915,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
 
 	f->store_buffer((const uint8_t*)"RSRC",4); //magic at end
 
+	if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
+		f->close();
+		return ERR_CANT_CREATE;
+	}
+
 	f->close();
 
 

+ 5 - 0
core/io/resource_format_xml.cpp

@@ -2592,6 +2592,11 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
 	}
 
 	exit_tag("resource_file");
+	if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
+		f->close();
+		return ERR_CANT_CREATE;
+	}
+
 	f->close();
 	//memdelete(f);
 

+ 18 - 1
core/math/camera_matrix.cpp

@@ -121,7 +121,7 @@ void CameraMatrix::set_orthogonal(float p_size, float p_aspect, float p_znear, f
 
 
 void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, float p_top, float p_near, float p_far) {
-
+#if 0
 	///@TODO, give a check to this. I'm not sure if it's working.
 	set_identity();
 
@@ -133,10 +133,27 @@ void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, floa
 	matrix[2][3]=-(2*p_far*p_near) / (p_far-p_near);
 	matrix[3][2]=-1;
 	matrix[3][3]=0;
+#else
+	float *te = &matrix[0][0];
+	float x = 2 * p_near / ( p_right - p_left );
+	float y = 2 * p_near / ( p_top - p_bottom );
+
+	float a = ( p_right + p_left ) / ( p_right - p_left );
+	float b = ( p_top + p_bottom ) / ( p_top - p_bottom );
+	float c = - ( p_far + p_near ) / ( p_far - p_near );
+	float d = - 2 * p_far * p_near / ( p_far - p_near );
+
+	te[0] = x;	te[4] = 0;	te[8] = a;	te[12] = 0;
+	te[1] = 0;	te[5] = y;	te[9] = b;	te[13] = 0;
+	te[2] = 0;	te[6] = 0;	te[10] = c;	te[14] = d;
+	te[3] = 0;	te[7] = 0;	te[11] = - 1;	te[15] = 0;
+
+#endif
 
 }
 
 
+
 float CameraMatrix::get_z_far() const {
 	
 	const float * matrix = (const float*)this->matrix;			

+ 3 - 0
core/variant_op.cpp

@@ -552,6 +552,9 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
 					if (p_b.type==MATRIX32) {
 						_RETURN( *p_a._data._matrix32 * *p_b._data._matrix32 );
 					};
+					if (p_b.type==VECTOR2) {
+						_RETURN( p_a._data._matrix32->xform( *(const Vector2*)p_b._data._mem) );
+					};
 					r_valid=false;
 					return;
 				} break;

二进制
demos/3d/kinematic_char/cubelib.res


二进制
demos/3d/kinematic_char/level.scn


+ 0 - 1
drivers/SCsub

@@ -10,7 +10,6 @@ SConscript('alsa/SCsub');
 SConscript('pulseaudio/SCsub');
 SConscript('windows/SCsub');
 SConscript('gles2/SCsub');
-SConscript('gles1/SCsub');
 SConscript('gl_context/SCsub');
 SConscript('openssl/SCsub');
 

+ 571 - 27
drivers/gles2/rasterizer_gles2.cpp

@@ -971,7 +971,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
 
 
 
-	if ((!texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) {
+	if (!(texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) {
 		texture->has_alpha=true;
 	}
 
@@ -2525,7 +2525,7 @@ Error RasterizerGLES2::_surface_set_arrays(Surface *p_surface, uint8_t *p_mem,ui
 void RasterizerGLES2::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) {
 
 	ERR_EXPLAIN("OpenGL Rasterizer does not support custom surfaces. Running on wrong platform?");
-	ERR_FAIL_V();
+	ERR_FAIL();
 }
 
 Array RasterizerGLES2::mesh_get_surface_arrays(RID p_mesh,int p_surface) const {
@@ -4116,6 +4116,10 @@ void RasterizerGLES2::begin_frame() {
 	shadow_filter=ShadowFilterTechnique(int(Globals::get_singleton()->get("rasterizer/shadow_filter")));
 #endif
 
+	canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF5,shadow_filter==SHADOW_FILTER_PCF5);
+	canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF13,shadow_filter==SHADOW_FILTER_PCF13);
+	canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_ESM,shadow_filter==SHADOW_FILTER_ESM);
+
 	window_size = Size2( OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height );
 
 	double time = (OS::get_singleton()->get_ticks_usec()/1000); // get msec
@@ -7874,7 +7878,8 @@ void RasterizerGLES2::canvas_begin() {
 	canvas_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
 	canvas_texscreen_used=false;
 	uses_texpixel_size=false;
-	canvas_last_shader=RID();
+
+	canvas_last_material=NULL;
 
 }
 
@@ -8364,6 +8369,476 @@ void RasterizerGLES2::canvas_set_transform(const Matrix32& p_transform) {
 	//canvas_transform = Variant(p_transform);
 }
 
+RID RasterizerGLES2::canvas_light_occluder_create() {
+
+	CanvasOccluder *co = memnew( CanvasOccluder );
+	co->index_id=0;
+	co->vertex_id=0;
+	co->len=0;
+
+	return canvas_occluder_owner.make_rid(co);
+}
+
+void RasterizerGLES2::canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines) {
+
+	CanvasOccluder *co = canvas_occluder_owner.get(p_occluder);
+	ERR_FAIL_COND(!co);
+
+	co->lines=p_lines;
+
+	if (p_lines.size()!=co->len) {
+
+		if (co->index_id)
+			glDeleteBuffers(1,&co->index_id);
+		if (co->vertex_id)
+			glDeleteBuffers(1,&co->vertex_id);
+
+		co->index_id=0;
+		co->vertex_id=0;
+		co->len=0;
+
+	}
+
+	if (p_lines.size()) {
+
+
+
+		DVector<float> geometry;
+		DVector<uint16_t> indices;
+		int lc = p_lines.size();
+
+		geometry.resize(lc*6);
+		indices.resize(lc*3);
+
+		DVector<float>::Write vw=geometry.write();
+		DVector<uint16_t>::Write iw=indices.write();
+
+
+		DVector<Vector2>::Read lr=p_lines.read();
+
+		const int POLY_HEIGHT = 16384;
+
+		for(int i=0;i<lc/2;i++) {
+
+			vw[i*12+0]=lr[i*2+0].x;
+			vw[i*12+1]=lr[i*2+0].y;
+			vw[i*12+2]=POLY_HEIGHT;
+
+			vw[i*12+3]=lr[i*2+1].x;
+			vw[i*12+4]=lr[i*2+1].y;
+			vw[i*12+5]=POLY_HEIGHT;
+
+			vw[i*12+6]=lr[i*2+1].x;
+			vw[i*12+7]=lr[i*2+1].y;
+			vw[i*12+8]=-POLY_HEIGHT;
+
+			vw[i*12+9]=lr[i*2+0].x;
+			vw[i*12+10]=lr[i*2+0].y;
+			vw[i*12+11]=-POLY_HEIGHT;
+
+			iw[i*6+0]=i*4+0;
+			iw[i*6+1]=i*4+1;
+			iw[i*6+2]=i*4+2;
+
+			iw[i*6+3]=i*4+2;
+			iw[i*6+4]=i*4+3;
+			iw[i*6+5]=i*4+0;
+
+		}
+
+		//if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
+
+
+		if (!co->vertex_id) {
+			glGenBuffers(1,&co->vertex_id);
+			glBindBuffer(GL_ARRAY_BUFFER,co->vertex_id);
+			glBufferData(GL_ARRAY_BUFFER,lc*6*sizeof(real_t),vw.ptr(),GL_STATIC_DRAW);
+		} else {
+
+			glBindBuffer(GL_ARRAY_BUFFER,co->vertex_id);
+			glBufferSubData(GL_ARRAY_BUFFER,0,lc*6*sizeof(real_t),vw.ptr());
+
+		}
+
+		glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+		if (!co->index_id) {
+
+			glGenBuffers(1,&co->index_id);
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,co->index_id);
+			glBufferData(GL_ELEMENT_ARRAY_BUFFER,lc*3*sizeof(uint16_t),iw.ptr(),GL_STATIC_DRAW);
+		} else {
+
+
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,co->index_id);
+			glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,lc*3*sizeof(uint16_t),iw.ptr());
+		}
+
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
+
+		co->len=lc;
+
+	}
+
+
+
+}
+
+RID RasterizerGLES2::canvas_light_shadow_buffer_create(int p_width) {
+
+	CanvasLightShadow *cls = memnew( CanvasLightShadow );
+	if (p_width>max_texture_size)
+		p_width=max_texture_size;
+
+	cls->size=p_width;
+	glActiveTexture(GL_TEXTURE0);
+
+	glGenFramebuffers(1, &cls->fbo);
+	glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
+
+	// Create a render buffer
+	glGenRenderbuffers(1, &cls->rbo);
+	glBindRenderbuffer(GL_RENDERBUFFER, cls->rbo);
+
+	// Create a texture for storing the depth
+	glGenTextures(1, &cls->depth);
+	glBindTexture(GL_TEXTURE_2D, cls->depth);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	// Remove artifact on the edges of the shadowmap
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	cls->height=16;
+
+	//print_line("ERROR? "+itos(glGetError()));
+	if ( read_depth_supported ) {
+
+		// We'll use a depth texture to store the depths in the shadow map
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, cls->size, cls->height, 0,
+			     GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+
+#ifdef GLEW_ENABLED
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#endif
+
+		// Attach the depth texture to FBO depth attachment point
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+				       GL_TEXTURE_2D, cls->depth, 0);
+
+#ifdef GLEW_ENABLED
+		glDrawBuffer(GL_NONE);
+#endif
+	} else {
+		// We'll use a RGBA texture into which we pack the depth info
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0,
+			     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+		// Attach the RGBA texture to FBO color attachment point
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+				       GL_TEXTURE_2D, cls->depth, 0);
+
+		// Allocate 16-bit depth buffer
+		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height);
+
+		// Attach the render buffer as depth buffer - will be ignored
+		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+					  GL_RENDERBUFFER, cls->rbo);
+
+
+	}
+
+	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+	//printf("errnum: %x\n",status);
+#ifdef GLEW_ENABLED
+	if (read_depth_supported) {
+		glDrawBuffer(GL_BACK);
+	}
+#endif
+	glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer);
+	DEBUG_TEST_ERROR("2D Shadow Buffer Init");
+	ERR_FAIL_COND_V( status != GL_FRAMEBUFFER_COMPLETE, RID() );
+
+#ifdef GLEW_ENABLED
+	if (read_depth_supported) {
+		glDrawBuffer(GL_BACK);
+	}
+#endif
+
+	return canvas_light_shadow_owner.make_rid(cls);
+}
+
+void RasterizerGLES2::canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache) {
+
+	CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_buffer);
+	ERR_FAIL_COND(!cls);
+
+
+	glDisable(GL_BLEND);
+	glDisable(GL_SCISSOR_TEST);
+	glDisable(GL_DITHER);
+	glDisable(GL_CULL_FACE);
+	glDepthFunc(GL_LEQUAL);
+	glEnable(GL_DEPTH_TEST);
+	glDepthMask(true);
+
+	glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
+
+	if (!use_rgba_shadowmaps)
+		glColorMask(0, 0, 0, 0);
+
+	glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+	canvas_shadow_shader.bind();
+
+	const int vp_height = 10;
+
+	glViewport(0, 0, cls->size,cls->height);
+	_glClearDepth(1.0f);
+	glClearColor(1,1,1,1);
+	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+
+	VS::CanvasOccluderPolygonCullMode cull=VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+
+
+	for(int i=0;i<4;i++) {
+
+		//make sure it remains orthogonal, makes easy to read angle later
+
+		Transform light;
+		light.origin[0]=p_light_xform[2][0];
+		light.origin[1]=p_light_xform[2][1];
+		light.basis[0][0]=p_light_xform[0][0];
+		light.basis[0][1]=p_light_xform[1][0];
+		light.basis[1][0]=p_light_xform[0][1];
+		light.basis[1][1]=p_light_xform[1][1];
+
+		//light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
+
+	///	p_near=1;
+		CameraMatrix projection;
+		{
+			real_t fov =  90;
+			real_t near = p_near;
+			real_t far = p_far;
+			real_t aspect = 1.0;
+
+			real_t ymax = near * Math::tan( Math::deg2rad( fov * 0.5 ) );
+			real_t ymin = - ymax;
+			real_t xmin = ymin * aspect;
+			real_t xmax = ymax * aspect;
+
+			projection.set_frustum( xmin, xmax, ymin, ymax, near, far );
+		}
+
+		Vector3 cam_target=Matrix3(Vector3(0,0,Math_PI*2*(i/4.0))).xform(Vector3(0,1,0));
+		projection = projection * CameraMatrix(Transform().looking_at(cam_target,Vector3(0,0,-1)).affine_inverse());
+
+		//print_line("near: "+rtos(p_near));
+		//print_line("far: "+rtos(p_far));
+		//projection.set_perspective(60,size/float(vp_height),p_near,p_far);
+
+	//	CameraMatrix light_mat = projection * CameraMatrix(camera);
+
+		canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::PROJECTION_MATRIX,projection);
+		canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::LIGHT_MATRIX,light);
+
+		if (i==0)
+			*p_xform_cache=projection;
+
+		glViewport(0, (cls->height/4)*i, cls->size,cls->height/4);
+
+		CanvasLightOccluderInstance *instance=p_occluders;
+
+		while(instance) {
+
+			CanvasOccluder *cc = canvas_occluder_owner.get(instance->polygon_buffer);
+			if (!cc || cc->len==0 || !(p_light_mask&instance->light_mask)) {
+
+				instance=instance->next;
+				continue;
+			}
+
+			canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::WORLD_MATRIX,instance->xform_cache);
+			if (cull!=instance->cull_cache) {
+
+				cull=instance->cull_cache;
+				switch(cull) {
+					case VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: {
+
+						glDisable(GL_CULL_FACE);
+
+					} break;
+					case VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: {
+
+						glEnable(GL_CULL_FACE);
+						glCullFace(GL_FRONT);
+					} break;
+					case VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: {
+
+						glEnable(GL_CULL_FACE);
+						glCullFace(GL_BACK);
+
+					} break;
+				}
+			}
+/*
+			if (i==0) {
+				for(int i=0;i<cc->lines.size();i++) {
+					Vector2 p = instance->xform_cache.xform(cc->lines.get(i));
+					Plane pp(Vector3(p.x,p.y,0),1);
+					pp.normal = light.xform(pp.normal);
+					pp = projection.xform4(pp);
+					print_line(itos(i)+": "+pp.normal/pp.d);
+					//pp=light_mat.xform4(pp);
+					//print_line(itos(i)+": "+pp.normal/pp.d);
+				}
+			}
+*/
+			glBindBuffer(GL_ARRAY_BUFFER,cc->vertex_id);
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,cc->index_id);
+			glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0);
+			glDrawElements(GL_TRIANGLES,cc->len*3,GL_UNSIGNED_SHORT,0);
+
+
+			instance=instance->next;
+		}
+
+
+	}
+
+	glDisableVertexAttribArray(VS::ARRAY_VERTEX);
+	glBindBuffer(GL_ARRAY_BUFFER,0);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
+
+	if (shadow_filter==SHADOW_FILTER_ESM) {
+		//blur the buffer
+#if 0
+	//this is ignord, it did not make any difference..
+		if (read_depth_supported) {
+			glDepthFunc(GL_ALWAYS);
+		} else {
+			glDisable(GL_DEPTH_TEST);
+			glDepthMask(false);
+		}
+		glDisable(GL_CULL_FACE);
+		glViewport(0, 0, cls->size,cls->height);
+
+		int passes=1;
+		CanvasLightShadow *blur = canvas_light_shadow_owner.get(canvas_shadow_blur);
+
+		copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,true);
+		copy_shader.bind();
+		copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SCALE,1);
+		copy_shader.set_uniform(CopyShaderGLES2::BLUR_MAGNITUDE,1);
+		glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0);
+
+		for(int i=0;i<passes;i++) {
+
+			glBindFramebuffer(GL_FRAMEBUFFER, blur->fbo);
+			glActiveTexture(GL_TEXTURE0);
+
+			if (read_depth_supported)
+				glBindTexture(GL_TEXTURE_2D,cls->depth);
+			else
+				glBindTexture(GL_TEXTURE_2D,cls->rgba);
+
+
+			{
+				Vector2 src_sb_uv[4]={
+					Vector2( 0, 1),
+					Vector2( 1, 1),
+					Vector2( 1, 0),
+					Vector2( 0, 0)
+				};
+				static const Vector2 dst_pos[4]={
+					Vector2(-1, 1),
+					Vector2( 1, 1),
+					Vector2( 1,-1),
+					Vector2(-1,-1)
+				};
+
+
+
+				copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Vector2(1.0,1.0)/cls->size);
+				_draw_gui_primitive(4,dst_pos,NULL,src_sb_uv);
+			}
+
+			glActiveTexture(GL_TEXTURE0);
+			if (read_depth_supported)
+				glBindTexture(GL_TEXTURE_2D,blur->depth);
+			else
+				glBindTexture(GL_TEXTURE_2D,blur->rgba);
+
+			glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
+
+			{
+				float hlimit = float(cls->size) / blur->size;
+				//hlimit*=2.0;
+				Vector2 src_sb_uv[4]={
+					Vector2( 0, 1),
+					Vector2( hlimit, 1),
+					Vector2( hlimit, 0),
+					Vector2( 0, 0)
+				};
+				static const Vector2 dst_pos[4]={
+					Vector2(-1, 1),
+					Vector2( 1, 1),
+					Vector2( 1,-1),
+					Vector2(-1,-1)
+				};
+
+
+				copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Vector2(1.0,1.0)/blur->size);
+				_draw_gui_primitive(4,dst_pos,NULL,src_sb_uv);
+			}
+
+		}
+		copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,false);
+		glDepthFunc(GL_LEQUAL);
+#endif
+	}
+
+	glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer);
+	glColorMask(1, 1, 1, 1);
+
+
+
+}
+
+
+void RasterizerGLES2::canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow) {
+
+	CanvasLight* light=p_lights_with_shadow;
+
+	canvas_begin(); //reset
+
+	int h = 10;
+	int w = viewport.width;
+	int ofs = h;
+	while(light) {
+
+		if (light->shadow_buffer.is_valid()) {
+
+			CanvasLightShadow * sb = canvas_light_shadow_owner.get(light->shadow_buffer);
+			if (sb) {
+				glActiveTexture(GL_TEXTURE0);
+				if (read_depth_supported)
+					glBindTexture(GL_TEXTURE_2D,sb->depth);
+				else
+					glBindTexture(GL_TEXTURE_2D,sb->rgba);
+				_draw_textured_quad(Rect2(h,ofs,w-h*2,h),Rect2(0,0,sb->size,10),Size2(sb->size,10),false,false);
+				ofs+=h*2;
+
+			}
+		}
+
+		light=light->shadows_next_ptr;
+	}
+
+}
+
 void RasterizerGLES2::_canvas_normal_set_flip(const Vector2& p_flip) {
 
 	if (p_flip==normal_flip)
@@ -8508,14 +8983,14 @@ void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem
 
 }
 
-void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItem *shader_owner,Shader* shader) {
+void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* shader) {
 
 	if (canvas_shader.bind())
 		rebind_texpixel_size=true;
 
-	if (shader_owner->shader_version!=shader->version) {
+	if (material->shader_version!=shader->version) {
 		//todo optimize uniforms
-		shader_owner->shader_version=shader->version;
+		material->shader_version=shader->version;
 	}
 
 	if (shader->has_texscreen && framebuffer.active) {
@@ -8558,14 +9033,14 @@ void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItem *shader_owner,
 
 }
 
-void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItem *shader_owner,Shader* shader) {
+void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* shader) {
 
 	//this can be optimized..
 	int tex_id=1;
 	int idx=0;
 	for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
 
-		Map<StringName,Variant>::Element *F=shader_owner->shader_param.find(E->key());
+		Map<StringName,Variant>::Element *F=material->shader_param.find(E->key());
 
 		if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) {
 
@@ -8623,6 +9098,8 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 	canvas_modulate=p_modulate;
 	canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
 
+	bool reset_modulate=false;
+
 	while(p_item_list) {
 
 		CanvasItem *ci=p_item_list;
@@ -8632,12 +9109,13 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 				draw_viewport_func(ci->vp_render->owner,ci->vp_render->udata,ci->vp_render->rect);
 			}
 			memdelete(ci->vp_render);
-			ci->vp_render=NULL;
-			canvas_last_shader=RID();
+			ci->vp_render=NULL;			
+			canvas_last_material=NULL;
 			canvas_use_modulate=p_modulate!=Color(1,1,1,1);
 			canvas_modulate=p_modulate;
 			canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
 			rebind_shader=true;
+			reset_modulate=true;
 
 
 		}
@@ -8660,13 +9138,14 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 
 
 		//begin rect
-		CanvasItem *shader_owner = ci->shader_owner?ci->shader_owner:ci;
+		CanvasItem *material_owner = ci->material_owner?ci->material_owner:ci;
+		CanvasItemMaterial *material = material_owner->material;
 
-		if (shader_owner->shader!=canvas_last_shader || rebind_shader) {
+		if (material!=canvas_last_material || rebind_shader) {
 
 			Shader *shader = NULL;
-			if (shader_owner->shader.is_valid()) {
-				shader = this->shader_owner.get(shader_owner->shader);
+			if (material && material->shader.is_valid()) {
+				shader = shader_owner.get(material->shader);
 				if (shader && !shader->valid) {
 					shader=NULL;
 				}
@@ -8676,7 +9155,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 
 			if (shader) {
 				canvas_shader.set_custom_shader(shader->custom_code_id);
-				_canvas_item_setup_shader_params(shader_owner,shader);
+				_canvas_item_setup_shader_params(material,shader);
 			} else {
 				shader_cache=NULL;
 				canvas_shader.set_custom_shader(0);
@@ -8688,16 +9167,26 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 
 			canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform);
 			if (canvas_use_modulate)
-				canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
-			canvas_last_shader=shader_owner->shader;
+				reset_modulate=true;
+			canvas_last_material=material;
 			rebind_shader=false;
 		}
 
-		if (shader_cache) {
+		if (material && shader_cache) {
+
+			_canvas_item_setup_shader_uniforms(material,shader_cache);
+		}
 
-			_canvas_item_setup_shader_uniforms(shader_owner,shader_cache);
+		if (material && material->unshaded) {
+			canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,Color(1,1,1,1));
+			reset_modulate=true;
+		} else if (reset_modulate) {
+			canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
+			reset_modulate=false;
 		}
 
+
+
 		canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
 		canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32());
 
@@ -8747,7 +9236,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 
 		_canvas_item_render_commands<false>(ci,current_clip,reclip);
 
-		if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light) {
+		if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && (!material || !material->unshaded)) {
 
 			CanvasLight *light = p_light;
 			bool light_used=false;
@@ -8785,13 +9274,15 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 						normal_flip=Vector2(1,1);
 
 					}
+					canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,light->shadow_buffer.is_valid());
+
 					bool light_rebind = canvas_shader.bind();
 
 					if (light_rebind) {
 
-						if (shader_owner && shader_cache) {
-							_canvas_item_setup_shader_params(shader_owner,shader_cache);
-							_canvas_item_setup_shader_uniforms(shader_owner,shader_cache);
+						if (material && shader_cache) {
+							_canvas_item_setup_shader_params(material,shader_cache);
+							_canvas_item_setup_shader_uniforms(material,shader_cache);
 						}
 
 						canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
@@ -8800,6 +9291,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 						if (canvas_use_modulate)
 							canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
 						canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,Vector2(1,1));
+						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOWPIXEL_SIZE,1.0/light->shadow_buffer_size);
 
 
 					}
@@ -8808,6 +9300,23 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS,light->light_shader_pos);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,light->color);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height);
+					if (light->shadow_buffer.is_valid()) {
+
+						CanvasLightShadow *cls = canvas_light_shadow_owner.get(light->shadow_buffer);
+						glActiveTexture(GL_TEXTURE0+max_texture_units-3);
+						if (read_depth_supported)
+							glBindTexture(GL_TEXTURE_2D,cls->depth);
+						else
+							glBindTexture(GL_TEXTURE_2D,cls->rgba);
+
+						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_TEXTURE,max_texture_units-3);
+						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX,light->shadow_matrix_cache);
+						canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse());
+						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult);
+
+					}
+
+
 					glActiveTexture(GL_TEXTURE0+max_texture_units-2);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_TEXTURE,max_texture_units-2);
 					Texture *t = texture_owner.get(light->texture);
@@ -8831,12 +9340,13 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 
 				canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,false);
 				canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
+				canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,false);
 
 				canvas_shader.bind();
 
-				if (shader_owner && shader_cache) {
-					_canvas_item_setup_shader_params(shader_owner,shader_cache);
-					_canvas_item_setup_shader_uniforms(shader_owner,shader_cache);
+				if (material && shader_cache) {
+					_canvas_item_setup_shader_params(material,shader_cache);
+					_canvas_item_setup_shader_uniforms(material,shader_cache);
 				}
 
 				canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
@@ -9067,6 +9577,11 @@ bool RasterizerGLES2::is_environment(const RID& p_rid) const {
 }
 bool RasterizerGLES2::is_shader(const RID& p_rid) const {
 
+	return shader_owner.owns(p_rid);
+}
+
+bool RasterizerGLES2::is_canvas_light_occluder(const RID& p_rid) const {
+
 	return false;
 }
 
@@ -9244,7 +9759,30 @@ void RasterizerGLES2::free(const RID& p_rid) {
 		glDeleteTextures(1,&sampled_light->texture);
 		sampled_light_owner.free(p_rid);
 		memdelete( sampled_light );
+	} else if (canvas_occluder_owner.owns(p_rid)) {
 
+
+		CanvasOccluder *co = canvas_occluder_owner.get(p_rid);
+		if (co->index_id)
+			glDeleteBuffers(1,&co->index_id);
+		if (co->vertex_id)
+			glDeleteBuffers(1,&co->vertex_id);
+
+		canvas_occluder_owner.free(p_rid);
+		memdelete(co);
+
+	} else if (canvas_light_shadow_owner.owns(p_rid)) {
+
+		CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid);
+		glDeleteFramebuffers(1,&cls->fbo);
+		glDeleteRenderbuffers(1,&cls->rbo);
+		glDeleteTextures(1,&cls->depth);
+		if (!read_depth_supported) {
+			glDeleteTextures(1,&cls->rgba);
+		}
+
+		canvas_light_shadow_owner.free(p_rid);
+		memdelete(cls);
 	};
 }
 
@@ -9779,10 +10317,12 @@ void RasterizerGLES2::init() {
 	material_shader.init();
 	canvas_shader.init();
 	copy_shader.init();
+	canvas_shadow_shader.init();
 
 #ifdef GLEW_ENABLED
 	material_shader.set_conditional(MaterialShaderGLES2::USE_GLES_OVER_GL,true);
 	canvas_shader.set_conditional(CanvasShaderGLES2::USE_GLES_OVER_GL,true);
+	canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_GLES_OVER_GL,true);
 	copy_shader.set_conditional(CopyShaderGLES2::USE_GLES_OVER_GL,true);
 #endif
 
@@ -9923,8 +10463,11 @@ void RasterizerGLES2::init() {
 
 
 	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
+	glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max_texture_size);
 	//read_depth_supported=false;
 
+	canvas_shadow_blur = canvas_light_shadow_buffer_create(max_texture_size);
+
 	{
 		//shadowmaps
 		OS::VideoMode vm=OS::get_singleton()->get_video_mode();
@@ -9946,6 +10489,7 @@ void RasterizerGLES2::init() {
 
 		//material_shader
 		material_shader.set_conditional(MaterialShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps);
+		canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps);
 
 	}
 
@@ -9978,7 +10522,7 @@ void RasterizerGLES2::init() {
 
 void RasterizerGLES2::finish() {
 
-
+	free(canvas_shadow_blur);
 }
 
 int RasterizerGLES2::get_render_info(VS::RenderInfo p_info) {

+ 59 - 3
drivers/gles2/rasterizer_gles2.h

@@ -51,6 +51,7 @@
 
 #include "drivers/gles2/shaders/material.glsl.h"
 #include "drivers/gles2/shaders/canvas.glsl.h"
+#include "drivers/gles2/shaders/canvas_shadow.glsl.h"
 #include "drivers/gles2/shaders/blur.glsl.h"
 #include "drivers/gles2/shaders/copy.glsl.h"
 #include "drivers/gles2/shader_compiler_gles2.h"
@@ -816,6 +817,7 @@ class RasterizerGLES2 : public Rasterizer {
 	bool current_depth_mask;
 	VS::MaterialBlendMode current_blend_mode;
 	bool use_fast_texture_filter;
+	int max_texture_size;
 
 	bool fragment_lighting;
 	RID shadow_material;
@@ -1160,6 +1162,7 @@ class RasterizerGLES2 : public Rasterizer {
 	void _process_glow_and_bloom();
 	//void _update_blur_buffer();
 
+
 	/*********/
 	/* FRAME */
 	/*********/
@@ -1178,6 +1181,45 @@ class RasterizerGLES2 : public Rasterizer {
 	} _rinfo;
 
 
+	/*******************/
+	/* CANVAS OCCLUDER */
+	/*******************/
+
+
+	struct CanvasOccluder {
+
+		GLuint vertex_id; // 0 means, unconfigured
+		GLuint index_id; // 0 means, unconfigured
+		DVector<Vector2> lines;
+		int len;
+	};
+
+	RID_Owner<CanvasOccluder> canvas_occluder_owner;
+
+	/***********************/
+	/* CANVAS LIGHT SHADOW */
+	/***********************/
+
+
+	struct CanvasLightShadow {
+
+		int size;
+		int height;
+		GLuint fbo;
+		GLuint rbo;
+		GLuint depth;
+		GLuint rgba; //for older devices
+
+		GLuint blur;
+
+	};
+
+	RID_Owner<CanvasLightShadow> canvas_light_shadow_owner;
+
+	RID canvas_shadow_blur;
+
+	/* ETC */
+
 	RenderTarget *current_rt;
 	bool current_rt_transparent;
 	bool current_rt_vflip;
@@ -1192,7 +1234,7 @@ class RasterizerGLES2 : public Rasterizer {
 	bool uses_texpixel_size;
 	bool rebind_texpixel_size;
 	Transform canvas_transform;
-	RID canvas_last_shader;
+	CanvasItemMaterial *canvas_last_material;
 	bool canvas_texscreen_used;
 	Vector2 normal_flip;
 	_FORCE_INLINE_ void _canvas_normal_set_flip(const Vector2& p_flip);
@@ -1227,10 +1269,12 @@ class RasterizerGLES2 : public Rasterizer {
 	VS::ScenarioDebugMode current_debug;
 	RID overdraw_material;
 
+
 	mutable MaterialShaderGLES2 material_shader;
 	mutable CanvasShaderGLES2 canvas_shader;
 	BlurShaderGLES2 blur_shader;
 	CopyShaderGLES2 copy_shader;
+	mutable CanvasShadowShaderGLES2 canvas_shadow_shader;
 
 	mutable ShaderCompilerGLES2 shader_precompiler;
 
@@ -1254,8 +1298,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(CanvasItem *shader_owner,Shader* p_shader);
-	_FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItem *shader_owner,Shader* p_shader);
+	_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);
 public:
 
 	/* TEXTURE API */
@@ -1572,7 +1616,17 @@ public:
 	virtual void canvas_set_transform(const Matrix32& p_transform);
 
 	virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light);
+	virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow);
 
+	/* CANVAS LIGHT SHADOW */
+
+	//buffer
+	virtual RID canvas_light_shadow_buffer_create(int p_width);
+	virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache);
+
+	//occluder
+	virtual RID canvas_light_occluder_create();
+	virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines);
 
 	/* ENVIRONMENT */
 
@@ -1611,6 +1665,8 @@ public:
 	virtual bool is_environment(const RID& p_rid) const;
 	virtual bool is_shader(const RID& p_rid) const;
 
+	virtual bool is_canvas_light_occluder(const RID& p_rid) const;
+
 	virtual void free(const RID& p_rid);
 
 	virtual void init();

+ 1 - 0
drivers/gles2/shaders/SCsub

@@ -3,6 +3,7 @@ Import('env')
 if env['BUILDERS'].has_key('GLSL120GLES'):
 	env.GLSL120GLES('material.glsl');
 	env.GLSL120GLES('canvas.glsl');
+	env.GLSL120GLES('canvas_shadow.glsl');
 	env.GLSL120GLES('blur.glsl');
 	env.GLSL120GLES('copy.glsl');
 

+ 113 - 10
drivers/gles2/shaders/canvas.glsl

@@ -34,6 +34,10 @@ varying vec4 local_rot;
 uniform vec2 normal_flip;
 #endif
 
+#ifdef USE_SHADOWS
+highp varying vec2 pos;
+#endif
+
 #endif
 
 #if defined(ENABLE_VAR1_INTERP)
@@ -63,6 +67,8 @@ VERTEX_SHADER_CODE
         outvec = modelview_matrix * outvec;
 #endif
 
+
+
 #ifdef USE_PIXEL_SNAP
 
 	outvec.xy=floor(outvec.xy+0.5);
@@ -75,6 +81,9 @@ VERTEX_SHADER_CODE
 
 	light_uv_interp.xy = (light_matrix * outvec).xy;
 	light_uv_interp.zw = outvec.xy-light_pos;
+#ifdef USE_SHADOWS
+	pos=outvec.xy;
+#endif
 
 #if defined(NORMAL_USED)
 	local_rot.xy=normalize( (modelview_matrix * ( extra_matrix * vec4(1.0,0.0,0.0,0.0) )).xy  )*normal_flip.x;
@@ -154,6 +163,15 @@ varying vec4 local_rot;
 uniform sampler2D shadow_texture;
 uniform float shadow_attenuation;
 
+uniform highp mat4 shadow_matrix;
+uniform highp mat4 light_local_matrix;
+highp varying vec2 pos;
+uniform float shadowpixel_size;
+
+#ifdef SHADOW_ESM
+uniform float shadow_esm_multiplier;
+#endif
+
 #endif
 
 #endif
@@ -173,10 +191,6 @@ void main() {
 	vec3 normal = vec3(0,0,1);
 #endif
 
-#ifdef USE_MODULATE
-
-	color*=modulate;
-#endif
 
 	color *= texture2D( texture,  uv_interp );
 #if defined(ENABLE_SCREEN_UV)
@@ -191,6 +205,12 @@ FRAGMENT_SHADER_CODE
 	color = vec4(vec3(enc32),1.0);
 #endif
 
+#ifdef USE_MODULATE
+
+	color*=modulate;
+#endif
+
+
 #ifdef USE_LIGHTING
 
 #if defined(NORMAL_USED)
@@ -201,13 +221,96 @@ FRAGMENT_SHADER_CODE
 
 	vec4 light = texture2D(light_texture,light_uv_interp.xy) * light_color;
 #ifdef USE_SHADOWS
-	//this might not be that great on mobile?
-	float light_dist = length(light_texture.zw);
-	float light_angle = atan2(light_texture.x,light_texture.z) + 1.0 * 0.5;
-	float shadow_dist = texture2D(shadow_texture,vec2(light_angle,0));
-	if (light_dist>shadow_dist) {
-		light*=shadow_attenuation;
+
+
+	vec2 lpos = (light_local_matrix * vec4(pos,0.0,1.0)).xy;
+	float angle_to_light = -atan(lpos.x,lpos.y);
+	float PI = 3.14159265358979323846264;
+	/*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays
+	float ang*/
+
+	float su,sz;
+
+	float abs_angle = abs(angle_to_light);
+	vec2 point;
+	float sh;
+	if (abs_angle<45.0*PI/180.0) {
+		point = lpos;
+		sh=0+(1.0/8.0);
+	} else if (abs_angle>135.0*PI/180.0) {
+		point = -lpos;
+		sh = 0.5+(1.0/8.0);
+	} else if (angle_to_light>0) {
+
+		point = vec2(lpos.y,-lpos.x);
+		sh = 0.25+(1.0/8.0);
+	} else {
+
+		point = vec2(-lpos.y,lpos.x);
+		sh = 0.75+(1.0/8.0);
+
+	}
+
+
+	vec4 s = shadow_matrix * vec4(point,0.0,1.0);
+	s.xyz/=s.w;
+	su=s.x*0.5+0.5;
+	sz=s.z*0.5+0.5;
+
+	float shadow_attenuation;
+
+#ifdef SHADOW_PCF5
+
+	shadow_attenuation=0.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*2.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*2.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation/=5.0;
+
+#endif
+
+#ifdef SHADOW_PCF13
+
+	shadow_attenuation += texture2D(shadow_texture,vec2(su,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*2.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*3.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*4.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*5.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*6.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*2.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*3.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*4.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*5.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*6.0,sh)).z<sz?0.0:1.0;
+	shadow_attenuation/=13.0;
+
+#endif
+
+#ifdef SHADOW_ESM
+
+
+	{
+		float unnormalized = su/shadowpixel_size;
+		float fractional = fract(unnormalized);
+		unnormalized = floor(unnormalized);
+		float zc = texture2D(shadow_texture,vec2((unnormalized-0.5)*shadowpixel_size,sh)).z;
+		float zn = texture2D(shadow_texture,vec2((unnormalized+0.5)*shadowpixel_size,sh)).z;
+		float z = mix(zc,zn,fractional);
+		shadow_attenuation=clamp(exp(shadow_esm_multiplier* ( z - sz )),0.0,1.0);
 	}
+
+#endif
+
+#if !defined(SHADOW_PCF5) && !defined(SHADOW_PCF13) && !defined(SHADOW_ESM)
+
+	shadow_attenuation = texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0;
+
+#endif
+
+	light*=shadow_attenuation;
 //use shadows
 #endif
 

+ 62 - 0
drivers/gles2/shaders/canvas_shadow.glsl

@@ -0,0 +1,62 @@
+[vertex]
+
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
+#endif
+
+uniform highp mat4 projection_matrix;
+uniform highp mat4 light_matrix;
+uniform highp mat4 world_matrix;
+
+attribute highp vec3 vertex; // attrib:0
+
+#ifndef USE_DEPTH_SHADOWS
+
+varying vec4 position_interp;
+
+#endif
+
+
+void main() {
+
+	gl_Position = projection_matrix * (light_matrix * (world_matrix *  vec4(vertex,1.0)));
+
+#ifndef USE_DEPTH_SHADOWS
+	position_interp = gl_Position;
+#endif
+
+}
+
+[fragment]
+
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
+#endif
+
+#ifndef USE_DEPTH_SHADOWS
+
+varying vec4 position_interp;
+
+#endif
+
+void main() {
+
+#ifdef USE_DEPTH_SHADOWS
+
+#else
+	highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias;
+	highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
+	comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
+	gl_FragColor = comp;
+#endif
+
+}
+

+ 17 - 3
drivers/windows/file_access_windows.cpp

@@ -28,14 +28,18 @@
 /*************************************************************************/
 #ifdef WINDOWS_ENABLED
 
+#include <Windows.h>
+#include "Shlwapi.h"
 #include "file_access_windows.h"
 
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <wchar.h>
 #include <tchar.h>
 #include "print_string.h"
 
+
 #ifdef _MSC_VER
  #define S_ISREG(m) ((m)&_S_IFREG)
 #endif
@@ -111,10 +115,20 @@ void FileAccessWindows::close() {
 
 		//unlink(save_path.utf8().get_data());
 		//print_line("renaming..");
-		_wunlink(save_path.c_str()); //unlink if exists
-		int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str());
+		//_wunlink(save_path.c_str()); //unlink if exists
+		//int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str());
+
+
+		bool rename_error;
+		if (!PathFileExistsW(save_path.c_str())) {
+			//creating new file
+			rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str())!=0;
+		} else {
+			//atomic replace for existing file
+			rename_error = !ReplaceFileW(save_path.c_str(), (save_path+".tmp").c_str(), NULL, 2|4, NULL, NULL);
+		}
 		save_path="";
-		ERR_FAIL_COND( rename_error != 0);
+		ERR_FAIL_COND( rename_error );
 	}
 
 

+ 4 - 1
modules/gdscript/gd_script.cpp

@@ -2696,7 +2696,10 @@ Error ResourceFormatSaverGDScript::save(const String &p_path,const RES& p_resour
 	}
 
 	file->store_string(source);
-
+	if (file->get_error()!=OK && file->get_error()!=ERR_FILE_EOF) {
+		memdelete(file);
+		return ERR_CANT_CREATE;
+	}
 	file->close();
 	memdelete(file);
 	return OK;

+ 8 - 0
platform/android/audio_driver_opensl.cpp

@@ -396,6 +396,14 @@ void AudioDriverOpenSL::finish(){
 void AudioDriverOpenSL::set_pause(bool p_pause) {
 
 	pause=p_pause;
+
+	if (active) {
+		if (pause) {
+			(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED);
+		} else {
+			(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
+		}
+	}
 }
 
 

+ 1 - 1
platform/android/os_android.cpp

@@ -151,7 +151,7 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_
 	sample_manager = memnew( SampleManagerMallocSW );
 	audio_server = memnew( AudioServerSW(sample_manager) );
 
-	audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+	audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,true);
 	audio_server->init();
 
 	spatial_sound_server = memnew( SpatialSoundServerSW );

+ 2 - 2
platform/windows/detect.py

@@ -115,7 +115,7 @@ def configure(env):
 		env.Append(CCFLAGS=['/DGLES2_ENABLED'])
 
 		env.Append(CCFLAGS=['/DGLEW_ENABLED'])
-		LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI', 'wsock32', 'shell32','advapi32']
+		LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI','Shlwapi', 'wsock32', 'shell32','advapi32']
 		env.Append(LINKFLAGS=[p+env["LIBSUFFIX"] for p in LIBS])
 		
 		env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
@@ -229,7 +229,7 @@ def configure(env):
 		env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
 		env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
 		env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLEW_ENABLED'])
-		env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','wsock32','kernel32'])
+		env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','shlwapi','wsock32','kernel32'])
 
 		if (env["bits"]=="32" and env["mingw64_for_32"]!="yes"):
 #			env.Append(LIBS=['gcc_s'])

+ 207 - 102
scene/2d/canvas_item.cpp

@@ -36,6 +36,192 @@
 #include "scene/resources/texture.h"
 #include "scene/resources/style_box.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 (p_name==SceneStringNames::get_singleton()->shader_unshaded) {
+		set_unshaded(p_value);
+		print_line("set unshaded");
+		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()->canvas_item_material_set_shader_param(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 (p_name==SceneStringNames::get_singleton()->shader_unshaded) {
+
+
+		r_ret=unshaded;
+		return true;
+	} else {
+
+		if (shader.is_valid()) {
+
+			StringName pr = shader->remap_param(p_name);
+			if (pr) {
+				r_ret=VisualServer::get_singleton()->canvas_item_material_get_shader_param(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" ) );
+	p_list->push_back( PropertyInfo( Variant::BOOL, "shader/unshaded") );
+
+	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);
+#ifdef TOOLS_ENABLED
+
+	if (shader.is_valid()) {
+		shader->disconnect("changed",this,"_shader_changed");
+	}
+#endif
+	shader=p_shader;
+
+#ifdef TOOLS_ENABLED
+
+	if (shader.is_valid()) {
+		shader->connect("changed",this,"_shader_changed");
+	}
+#endif
+
+	RID rid;
+	if (shader.is_valid())
+		rid=shader->get_rid();
+
+	VS::get_singleton()->canvas_item_material_set_shader(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()->canvas_item_material_set_shader_param(material,p_param,p_value);
+}
+
+Variant CanvasItemMaterial::get_shader_param(const StringName& p_param) const{
+
+	return VS::get_singleton()->canvas_item_material_get_shader_param(material,p_param);
+}
+
+void CanvasItemMaterial::_shader_changed() {
+
+
+}
+
+RID CanvasItemMaterial::get_rid() const {
+
+	return material;
+}
+
+void CanvasItemMaterial::set_unshaded(bool p_unshaded) {
+
+	unshaded=p_unshaded;
+	VS::get_singleton()->canvas_item_material_set_unshaded(material,p_unshaded);
+}
+
+bool CanvasItemMaterial::is_unshaded() const{
+
+	return unshaded;
+}
+
+void CanvasItemMaterial::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_shader","shader:Shader"),&CanvasItemMaterial::set_shader);
+	ObjectTypeDB::bind_method(_MD("get_shader:Shader"),&CanvasItemMaterial::get_shader);
+	ObjectTypeDB::bind_method(_MD("set_shader_param","param","value"),&CanvasItemMaterial::set_shader_param);
+	ObjectTypeDB::bind_method(_MD("get_shader_param","param"),&CanvasItemMaterial::get_shader_param);
+	ObjectTypeDB::bind_method(_MD("set_unshaded","unshaded"),&CanvasItemMaterial::set_unshaded);
+	ObjectTypeDB::bind_method(_MD("is_unshaded"),&CanvasItemMaterial::is_unshaded);
+
+}
+
+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() {
+
+	material=VS::get_singleton()->canvas_item_material_create();
+	unshaded=false;
+}
+
+CanvasItemMaterial::~CanvasItemMaterial(){
+
+	VS::get_singleton()->free(material);
+}
+
+
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////
+
+
+
 bool CanvasItem::is_visible() const {
 
 	if (!is_inside_tree())
@@ -730,111 +916,35 @@ bool CanvasItem::is_draw_behind_parent_enabled() const{
 	return behind;
 }
 
-void CanvasItem::set_shader(const Ref<Shader>& p_shader) {
-
-	ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM);
-
-#ifdef TOOLS_ENABLED
-
-	if (shader.is_valid()) {
-		shader->disconnect("changed",this,"_shader_changed");
-	}
-#endif
-	shader=p_shader;
-
-#ifdef TOOLS_ENABLED
+void CanvasItem::set_material(const Ref<CanvasItemMaterial>& p_material) {
 
-	if (shader.is_valid()) {
-		shader->connect("changed",this,"_shader_changed");
-	}
-#endif
 
+	material=p_material;
 	RID rid;
-	if (shader.is_valid())
-		rid=shader->get_rid();
-	VS::get_singleton()->canvas_item_set_shader(canvas_item,rid);
-	_change_notify(); //properties for shader exposed
-}
-
-void CanvasItem::set_use_parent_shader(bool p_use_parent_shader) {
-
-	use_parent_shader=p_use_parent_shader;
-	VS::get_singleton()->canvas_item_set_use_parent_shader(canvas_item,p_use_parent_shader);
+	if (material.is_valid())
+		rid=material->get_rid();
+	VS::get_singleton()->canvas_item_set_material(canvas_item,rid);
+	_change_notify(); //properties for material exposed
 }
 
-bool CanvasItem::get_use_parent_shader() const{
+void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
 
-	return use_parent_shader;
+	use_parent_material=p_use_parent_material;
+	VS::get_singleton()->canvas_item_set_use_parent_material(canvas_item,p_use_parent_material);
 }
 
-Ref<Shader> CanvasItem::get_shader() const{
+bool CanvasItem::get_use_parent_material() const{
 
-	return shader;
+	return use_parent_material;
 }
 
-void CanvasItem::set_shader_param(const StringName& p_param,const Variant& p_value) {
+Ref<CanvasItemMaterial> CanvasItem::get_material() const{
 
-	VS::get_singleton()->canvas_item_set_shader_param(canvas_item,p_param,p_value);
+	return material;
 }
 
-Variant CanvasItem::get_shader_param(const StringName& p_param) const {
-
-	return VS::get_singleton()->canvas_item_get_shader_param(canvas_item,p_param);
-}
-
-bool CanvasItem::_set(const StringName& p_name, const Variant& p_value) {
-
-	if (shader.is_valid()) {
-		StringName pr = shader->remap_param(p_name);
-		if (pr) {
-			set_shader_param(pr,p_value);
-			return true;
-		}
-	}
-	return false;
-}
 
-bool CanvasItem::_get(const StringName& p_name,Variant &r_ret) const{
 
-	if (shader.is_valid()) {
-		StringName pr = shader->remap_param(p_name);
-		if (pr) {
-			r_ret=get_shader_param(pr);
-			return true;
-		}
-	}
-	return false;
-
-}
-void CanvasItem::_get_property_list( List<PropertyInfo> *p_list) const{
-
-	if (shader.is_valid()) {
-		shader->get_param_list(p_list);
-	}
-}
-
-#ifdef TOOLS_ENABLED
-void CanvasItem::_shader_changed() {
-
-	_change_notify();
-}
-#endif
-
-void CanvasItem::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
-
-	if (p_idx==0 && shader.is_valid() && (p_function.operator String()=="get_shader_param" || p_function.operator String()=="set_shader_param")) {
-
-		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/","")+"\"");
-		}
-
-		return;
-	}
-
-	Node::get_argument_options(p_function,p_idx,r_options);
-}
 
 
 void CanvasItem::_bind_methods() {
@@ -880,9 +990,6 @@ void CanvasItem::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("_set_on_top","on_top"),&CanvasItem::_set_on_top);
 	ObjectTypeDB::bind_method(_MD("_is_on_top"),&CanvasItem::_is_on_top);
-#ifdef TOOLS_ENABLED
-	ObjectTypeDB::bind_method(_MD("_shader_changed"),&CanvasItem::_shader_changed);
-#endif
 	//ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
 
 	ObjectTypeDB::bind_method(_MD("draw_line","from","to","color","width"),&CanvasItem::draw_line,DEFVAL(1.0));
@@ -901,20 +1008,18 @@ void CanvasItem::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("draw_set_transform","pos","rot","scale"),&CanvasItem::draw_set_transform);
 	ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
 	ObjectTypeDB::bind_method(_MD("get_global_transform"),&CanvasItem::get_global_transform);
+	ObjectTypeDB::bind_method(_MD("get_global_transform_with_canvas"),&CanvasItem::get_global_transform_with_canvas);
 	ObjectTypeDB::bind_method(_MD("get_viewport_transform"),&CanvasItem::get_viewport_transform);
 	ObjectTypeDB::bind_method(_MD("get_viewport_rect"),&CanvasItem::get_viewport_rect);
 	ObjectTypeDB::bind_method(_MD("get_canvas"),&CanvasItem::get_canvas);
 	ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d);
 	//ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport);
 
-	ObjectTypeDB::bind_method(_MD("set_shader","shader"),&CanvasItem::set_shader);
-	ObjectTypeDB::bind_method(_MD("get_shader"),&CanvasItem::get_shader);
-	ObjectTypeDB::bind_method(_MD("set_use_parent_shader","enable"),&CanvasItem::set_use_parent_shader);
-	ObjectTypeDB::bind_method(_MD("get_use_parent_shader"),&CanvasItem::get_use_parent_shader);
-
-	ObjectTypeDB::bind_method(_MD("set_shader_param","param","value"),&CanvasItem::set_shader_param);
-	ObjectTypeDB::bind_method(_MD("get_shader_param","param"),&CanvasItem::get_shader_param);
+	ObjectTypeDB::bind_method(_MD("set_material","material:CanvasItemMaterial"),&CanvasItem::set_material);
+	ObjectTypeDB::bind_method(_MD("get_material:CanvasItemMaterial"),&CanvasItem::get_material);
 
+	ObjectTypeDB::bind_method(_MD("set_use_parent_material","enable"),&CanvasItem::set_use_parent_material);
+	ObjectTypeDB::bind_method(_MD("get_use_parent_material"),&CanvasItem::get_use_parent_material);
 
 	BIND_VMETHOD(MethodInfo("_draw"));
 
@@ -926,8 +1031,8 @@ void CanvasItem::_bind_methods() {
 
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,PMAlpha"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") );
-	ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"shader/shader",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph"), _SCS("set_shader"),_SCS("get_shader") );
-	ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"shader/use_parent"), _SCS("set_use_parent_shader"),_SCS("get_use_parent_shader") );
+	ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"material/material",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial"), _SCS("set_material"),_SCS("get_material") );
+	ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"material/use_parent"), _SCS("set_use_parent_material"),_SCS("get_use_parent_material") );
 	//exporting these two things doesn't really make much sense i think
 	//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") );
 	//ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled"));
@@ -1004,7 +1109,7 @@ CanvasItem::CanvasItem() : xform_change(this) {
 	block_transform_notify=false;
 //	viewport=NULL;
 	canvas_layer=NULL;
-	use_parent_shader=false;
+	use_parent_material=false;
 	global_invalid=true;
 	light_mask=1;
 

+ 41 - 18
scene/2d/canvas_item.h

@@ -40,6 +40,41 @@ class Font;
 
 class StyleBox;
 
+class CanvasItemMaterial : public Resource{
+
+	OBJ_TYPE(CanvasItemMaterial,Resource);
+	RID material;
+	Ref<Shader> shader;
+	bool unshaded;
+
+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;
+
+	void _shader_changed();
+	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;
+
+	void set_unshaded(bool p_unshaded);
+	bool is_unshaded() const;
+
+	virtual RID get_rid() const;
+	CanvasItemMaterial();
+	~CanvasItemMaterial();
+};
+
+
 class CanvasItem : public Node {
 
 	OBJ_TYPE( CanvasItem, Node );
@@ -81,9 +116,9 @@ private:
 	bool drawing;
 	bool block_transform_notify;
 	bool behind;
-	bool use_parent_shader;
+	bool use_parent_material;
 
-	Ref<Shader> shader;
+	Ref<CanvasItemMaterial> material;
 
 	mutable Matrix32 global_transform;
 	mutable bool global_invalid;
@@ -104,9 +139,6 @@ private:
 	void _queue_sort_children();
 	void _sort_children();
 
-#ifdef TOOLS_ENABLED
-	void _shader_changed();
-#endif
 	void _notify_transform(CanvasItem *p_node);
 
 	void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); }
@@ -114,11 +146,6 @@ private:
 
 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;
-
-
 	_FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); }
 
 	void item_rect_changed();
@@ -216,16 +243,12 @@ public:
 	RID get_canvas() const;
 	Ref<World2D> get_world_2d() const;
 
-	void set_shader(const Ref<Shader>& p_shader);
-	Ref<Shader> get_shader() const;
+	void set_material(const Ref<CanvasItemMaterial>& p_material);
+	Ref<CanvasItemMaterial> get_material() const;
 
-	void set_use_parent_shader(bool p_use_parent_shader);
-	bool get_use_parent_shader() const;
+	void set_use_parent_material(bool p_use_parent_material);
+	bool get_use_parent_material() const;
 
-	void set_shader_param(const StringName& p_param,const Variant& p_value);
-	Variant get_shader_param(const StringName& p_param) const;
-
-	void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
 
 	CanvasItem();
 	~CanvasItem();

+ 41 - 8
scene/2d/light_2d.cpp

@@ -170,6 +170,29 @@ bool Light2D::is_shadow_enabled() const {
 	return shadow;
 }
 
+void Light2D::set_shadow_buffer_size( int p_size ) {
+
+	shadow_buffer_size=p_size;
+	VS::get_singleton()->canvas_light_set_shadow_buffer_size(canvas_light,shadow_buffer_size);
+}
+
+int Light2D::get_shadow_buffer_size() const {
+
+	return shadow_buffer_size;
+}
+
+void Light2D::set_shadow_esm_multiplier( float p_multiplier) {
+
+	shadow_esm_multiplier=p_multiplier;
+	VS::get_singleton()->canvas_light_set_shadow_esm_multiplier(canvas_light,p_multiplier);
+}
+
+float Light2D::get_shadow_esm_multiplier() const{
+
+	return shadow_esm_multiplier;
+}
+
+
 void Light2D::_notification(int p_what) {
 
 	if (p_what==NOTIFICATION_ENTER_TREE) {
@@ -229,18 +252,26 @@ void Light2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_shadow_enabled","enabled"),&Light2D::set_shadow_enabled);
 	ObjectTypeDB::bind_method(_MD("is_shadow_enabled"),&Light2D::is_shadow_enabled);
 
+	ObjectTypeDB::bind_method(_MD("set_shadow_buffer_size","size"),&Light2D::set_shadow_buffer_size);
+	ObjectTypeDB::bind_method(_MD("get_shadow_buffer_size"),&Light2D::get_shadow_buffer_size);
+
+	ObjectTypeDB::bind_method(_MD("set_shadow_esm_multiplier","multiplier"),&Light2D::set_shadow_esm_multiplier);
+	ObjectTypeDB::bind_method(_MD("get_shadow_esm_multiplier"),&Light2D::get_shadow_esm_multiplier);
+
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
 	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
-	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"texture_offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset"));
+	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset"));
 	ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
-	ADD_PROPERTY( PropertyInfo(Variant::REAL,"height"),_SCS("set_height"),_SCS("get_height"));
-	ADD_PROPERTY( PropertyInfo(Variant::INT,"z_range_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min"));
-	ADD_PROPERTY( PropertyInfo(Variant::INT,"z_range_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max"));
-	ADD_PROPERTY( PropertyInfo(Variant::INT,"layer_range_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min"));
-	ADD_PROPERTY( PropertyInfo(Variant::INT,"layer_range_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max"));
-	ADD_PROPERTY( PropertyInfo(Variant::INT,"item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask"));
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"subtract"),_SCS("set_subtract_mode"),_SCS("get_subtract_mode"));
-	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow_enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height"),_SCS("set_height"),_SCS("get_height"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask"));
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow/enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/buffer_size",PROPERTY_HINT_RANGE,"32,16384,1"),_SCS("set_shadow_buffer_size"),_SCS("get_shadow_buffer_size"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"shadow/esm_multiplier",PROPERTY_HINT_RANGE,"1,4096,0.1"),_SCS("set_shadow_esm_multiplier"),_SCS("get_shadow_esm_multiplier"));
 
 
 }
@@ -258,6 +289,8 @@ Light2D::Light2D() {
 	layer_max=0;
 	item_mask=1;
 	subtract_mode=false;
+	shadow_buffer_size=2048;
+	shadow_esm_multiplier=80;
 
 }
 

+ 8 - 0
scene/2d/light_2d.h

@@ -17,6 +17,8 @@ private:
 	int layer_min;
 	int layer_max;
 	int item_mask;
+	int shadow_buffer_size;
+	float shadow_esm_multiplier;
 	bool subtract_mode;
 	Ref<Texture> texture;
 	Vector2 texture_offset;
@@ -68,6 +70,12 @@ public:
 	void set_shadow_enabled( bool p_enabled);
 	bool is_shadow_enabled() const;
 
+	void set_shadow_buffer_size( int p_size );
+	int get_shadow_buffer_size() const;
+
+	void set_shadow_esm_multiplier( float p_multiplier);
+	float get_shadow_esm_multiplier() const;
+
 	virtual Rect2 get_item_rect() const;
 
 	Light2D();

+ 201 - 0
scene/2d/light_occluder_2d.cpp

@@ -0,0 +1,201 @@
+#include "light_occluder_2d.h"
+
+
+void OccluderPolygon2D::set_polygon(const DVector<Vector2>& p_polygon) {
+
+	polygon=p_polygon;
+	VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,p_polygon,closed);
+	emit_changed();
+}
+
+DVector<Vector2> OccluderPolygon2D::get_polygon() const{
+
+	return polygon;
+}
+
+void OccluderPolygon2D::set_closed(bool p_closed) {
+
+	if (closed==p_closed)
+		return;
+	closed=p_closed;
+	VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,polygon,closed);
+	emit_changed();
+}
+
+bool OccluderPolygon2D::is_closed() const{
+
+	return closed;
+}
+
+void OccluderPolygon2D::set_cull_mode(CullMode p_mode){
+
+	cull=p_mode;
+	VS::get_singleton()->canvas_occluder_polygon_set_cull_mode(occ_polygon,VS::CanvasOccluderPolygonCullMode(p_mode));
+}
+
+OccluderPolygon2D::CullMode OccluderPolygon2D::get_cull_mode() const{
+
+	return cull;
+}
+
+
+RID OccluderPolygon2D::get_rid() const {
+
+	return occ_polygon;
+}
+
+void OccluderPolygon2D::_bind_methods() {
+
+
+	ObjectTypeDB::bind_method(_MD("set_closed","closed"),&OccluderPolygon2D::set_closed);
+	ObjectTypeDB::bind_method(_MD("is_closed"),&OccluderPolygon2D::is_closed);
+
+	ObjectTypeDB::bind_method(_MD("set_cull_mode","cull_mode"),&OccluderPolygon2D::set_cull_mode);
+	ObjectTypeDB::bind_method(_MD("get_cull_mode"),&OccluderPolygon2D::get_cull_mode);
+
+	ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&OccluderPolygon2D::set_polygon);
+	ObjectTypeDB::bind_method(_MD("get_polygon"),&OccluderPolygon2D::get_polygon);
+
+	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon"));
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"closed"),_SCS("set_closed"),_SCS("is_closed"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mode",PROPERTY_HINT_ENUM,"Disabled,ClockWise,CounterClockWise"),_SCS("set_cull_mode"),_SCS("get_cull_mode"));
+
+	BIND_CONSTANT(CULL_DISABLED);
+	BIND_CONSTANT(CULL_CLOCKWISE);
+	BIND_CONSTANT(CULL_COUNTER_CLOCKWISE);
+}
+
+
+OccluderPolygon2D::OccluderPolygon2D() {
+
+	occ_polygon=VS::get_singleton()->canvas_occluder_polygon_create();
+	closed=true;
+	cull=CULL_DISABLED;
+}
+
+OccluderPolygon2D::~OccluderPolygon2D() {
+
+	VS::get_singleton()->free(occ_polygon);
+}
+
+#ifdef DEBUG_ENABLED
+void LightOccluder2D::_poly_changed() {
+
+	update();
+}
+#endif
+
+
+void LightOccluder2D::_notification(int p_what) {
+
+	if (p_what==NOTIFICATION_ENTER_CANVAS) {
+
+		VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,get_canvas());
+		VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform());
+
+	}
+	if (p_what==NOTIFICATION_TRANSFORM_CHANGED) {
+
+		VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform());
+	}
+
+	if (p_what==NOTIFICATION_DRAW) {
+
+		if (get_tree()->is_editor_hint()) {
+
+			if (occluder_polygon.is_valid()) {
+
+				DVector<Vector2> poly = occluder_polygon->get_polygon();
+
+				if (poly.size()) {
+					if (occluder_polygon->is_closed()) {
+						Vector<Color> color;
+						color.push_back(Color(0,0,0,0.6));
+						draw_polygon(Variant(poly),color);
+					} else {
+
+						int ps=poly.size();
+						DVector<Vector2>::Read r = poly.read();
+						for(int i=0;i<ps-1;i++) {
+
+							draw_line(r[i],r[i+1],Color(0,0,0,0.6),3);
+						}
+					}
+				}
+			}
+		}
+	}
+
+
+	if (p_what==NOTIFICATION_EXIT_CANVAS) {
+
+		VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,RID());
+	}
+
+
+}
+
+void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon) {
+
+#ifdef DEBUG_ENABLED
+	if (occluder_polygon.is_valid())
+		occluder_polygon->disconnect("changed",this,"_poly_changed");
+#endif
+	occluder_polygon=p_polygon;
+
+	if (occluder_polygon.is_valid())
+		VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,occluder_polygon->get_rid());
+	else
+		VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,RID());
+
+#ifdef DEBUG_ENABLED
+	if (occluder_polygon.is_valid())
+		occluder_polygon->connect("changed",this,"_poly_changed");
+	update();
+#endif
+
+}
+
+Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const {
+
+	return occluder_polygon;
+}
+
+void LightOccluder2D::set_occluder_light_mask(int p_mask) {
+
+	mask=p_mask;
+	VS::get_singleton()->canvas_light_occluder_set_light_mask(occluder,mask);
+}
+
+int LightOccluder2D::get_occluder_light_mask() const{
+
+	return mask;
+}
+
+void LightOccluder2D::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_occluder_polygon","polygon:OccluderPolygon2D"),&LightOccluder2D::set_occluder_polygon);
+	ObjectTypeDB::bind_method(_MD("get_occluder_polygon:OccluderPolygon2D"),&LightOccluder2D::get_occluder_polygon);
+
+	ObjectTypeDB::bind_method(_MD("set_occluder_light_mask","mask"),&LightOccluder2D::set_occluder_light_mask);
+	ObjectTypeDB::bind_method(_MD("get_occluder_light_mask"),&LightOccluder2D::get_occluder_light_mask);
+
+#ifdef DEBUG_ENABLED
+	ObjectTypeDB::bind_method("_poly_changed",&LightOccluder2D::_poly_changed);
+#endif
+
+	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"occluder",PROPERTY_HINT_RESOURCE_TYPE,"OccluderPolygon2D"),_SCS("set_occluder_polygon"),_SCS("get_occluder_polygon"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"light_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_occluder_light_mask"),_SCS("get_occluder_light_mask"));
+}
+
+LightOccluder2D::LightOccluder2D() {
+
+	occluder=VS::get_singleton()->canvas_light_occluder_create();
+	mask=1;
+}
+
+LightOccluder2D::~LightOccluder2D() {
+
+	VS::get_singleton()->free(occluder);
+}
+

+ 73 - 0
scene/2d/light_occluder_2d.h

@@ -0,0 +1,73 @@
+#ifndef LIGHTOCCLUDER2D_H
+#define LIGHTOCCLUDER2D_H
+
+#include "scene/2d/node_2d.h"
+
+class OccluderPolygon2D : public Resource {
+
+	OBJ_TYPE(OccluderPolygon2D,Resource);
+public:
+
+	enum CullMode {
+		CULL_DISABLED,
+		CULL_CLOCKWISE,
+		CULL_COUNTER_CLOCKWISE
+	};
+private:
+
+
+	RID occ_polygon;
+	DVector<Vector2> polygon;
+	bool closed;
+	CullMode cull;
+
+protected:
+
+	static void _bind_methods();
+public:
+
+	void set_polygon(const DVector<Vector2>& p_polygon);
+	DVector<Vector2> get_polygon() const;
+
+	void set_closed(bool p_closed);
+	bool is_closed() const;
+
+	void set_cull_mode(CullMode p_mode);
+	CullMode get_cull_mode() const;
+
+	virtual RID get_rid() const;
+	OccluderPolygon2D();
+	~OccluderPolygon2D();
+
+};
+
+VARIANT_ENUM_CAST(OccluderPolygon2D::CullMode);
+
+class LightOccluder2D : public Node2D {
+	OBJ_TYPE(LightOccluder2D,Node2D);
+
+	RID occluder;
+	bool enabled;
+	int mask;
+	Ref<OccluderPolygon2D> occluder_polygon;
+
+#ifdef DEBUG_ENABLED
+	void _poly_changed();
+#endif
+
+protected:
+	void _notification(int p_what);
+	static void _bind_methods();
+public:
+
+	void set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon);
+	Ref<OccluderPolygon2D> get_occluder_polygon() const;
+
+	void set_occluder_light_mask(int p_mask);
+	int get_occluder_light_mask() const;
+
+	LightOccluder2D();
+	~LightOccluder2D();
+};
+
+#endif // LIGHTOCCLUDER2D_H

+ 3 - 3
scene/3d/camera.cpp

@@ -152,11 +152,11 @@ void Camera::_get_property_list( List<PropertyInfo> *p_list) const {
 	
 		case PROJECTION_PERSPECTIVE: {
 		
-			p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_NOEDITOR) );
+			p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_NOEDITOR) );
 			if (keep_aspect==KEEP_WIDTH)
-				p_list->push_back( PropertyInfo( Variant::REAL, "fovx" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_EDITOR) );
+				p_list->push_back( PropertyInfo( Variant::REAL, "fovx" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_EDITOR) );
 			else
-				p_list->push_back( PropertyInfo( Variant::REAL, "fovy" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_EDITOR) );
+				p_list->push_back( PropertyInfo( Variant::REAL, "fovy" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_EDITOR) );
 
 			
 		} break;

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

@@ -310,6 +310,17 @@ int GeometryInstance::get_baked_light_texture_id() const{
 	return baked_light_texture_id;
 }
 
+void GeometryInstance::set_extra_cull_margin(float p_margin) {
+
+	ERR_FAIL_COND(p_margin<0);
+	extra_cull_margin=p_margin;
+	VS::get_singleton()->instance_set_extra_visibility_margin(get_instance(),extra_cull_margin);
+}
+
+float GeometryInstance::get_extra_cull_margin() const{
+
+	return extra_cull_margin;
+}
 
 void GeometryInstance::_bind_methods() {
 
@@ -328,6 +339,9 @@ void GeometryInstance::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id);
 	ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id);
 
+	ObjectTypeDB::bind_method(_MD("set_extra_cull_margin","margin"), &GeometryInstance::set_extra_cull_margin);
+	ObjectTypeDB::bind_method(_MD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
+
 	ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed);
 
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE);
@@ -336,6 +350,7 @@ void GeometryInstance::_bind_methods() {
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/receive_shadows"), _SCS("set_flag"), _SCS("get_flag"),FLAG_RECEIVE_SHADOWS);
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_begin",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_begin"), _SCS("get_draw_range_begin"));
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_end",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_end"), _SCS("get_draw_range_end"));
+	ADD_PROPERTY( PropertyInfo( Variant::REAL, "geometry/extra_cull_margin",PROPERTY_HINT_RANGE,"0,16384,0"), _SCS("set_extra_cull_margin"), _SCS("get_extra_cull_margin"));
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE);

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

@@ -108,6 +108,7 @@ private:
 	void _find_baked_light();
 	BakedLightInstance *baked_light_instance;
 	int baked_light_texture_id;
+	float extra_cull_margin;
 
 	void _baked_light_changed();
 	void _update_visibility();
@@ -132,6 +133,9 @@ public:
 	void set_baked_light_texture_id(int p_id);
 	int get_baked_light_texture_id() const;
 
+	void set_extra_cull_margin(float p_margin);
+	float get_extra_cull_margin() const;
+
 	GeometryInstance();
 };
 

+ 4 - 0
scene/register_scene_types.cpp

@@ -80,6 +80,7 @@
 #include "scene/2d/particles_2d.h"
 #include "scene/2d/path_2d.h"
 #include "scene/2d/light_2d.h"
+#include "scene/2d/light_occluder_2d.h"
 
 #include "scene/2d/canvas_item.h"
 #include "scene/2d/sprite.h"
@@ -454,6 +455,7 @@ void register_scene_types() {
 	//ObjectTypeDB::set_type_enabled("BodyVolumeCylinder",false);
 	//ObjectTypeDB::set_type_enabled("BodyVolumeConvexPolygon",false);
 
+	ObjectTypeDB::register_type<CanvasItemMaterial>();
 	ObjectTypeDB::register_virtual_type<CanvasItem>();
 	ObjectTypeDB::register_type<Node2D>();
 	ObjectTypeDB::register_type<Particles2D>();
@@ -476,6 +478,8 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<VisibilityEnabler2D>();
 	ObjectTypeDB::register_type<Polygon2D>();
 	ObjectTypeDB::register_type<Light2D>();
+	ObjectTypeDB::register_type<LightOccluder2D>();
+	ObjectTypeDB::register_type<OccluderPolygon2D>();
 	ObjectTypeDB::register_type<YSort>();
 
 	ObjectTypeDB::set_type_enabled("CollisionShape2D",false);

+ 1 - 0
scene/scene_string_names.cpp

@@ -41,6 +41,7 @@ SceneStringNames::SceneStringNames() {
 	visibility_changed=StaticCString::create("visibility_changed");
 	input_event=StaticCString::create("input_event");
 	shader_shader=StaticCString::create("shader/shader");
+	shader_unshaded=StaticCString::create("shader/unshaded");
 	enter_tree=StaticCString::create("enter_tree");
 	exit_tree=StaticCString::create("exit_tree");
 	item_rect_changed=StaticCString::create("item_rect_changed");

+ 1 - 0
scene/scene_string_names.h

@@ -56,6 +56,7 @@ public:
 	StringName _input_event;
 	StringName item_rect_changed;
 	StringName shader_shader;
+	StringName shader_unshaded;
 	StringName enter_tree;
 	StringName exit_tree;
 	StringName size_flags_changed;

+ 58 - 9
servers/visual/rasterizer.h

@@ -572,8 +572,8 @@ public:
 	struct CanvasLight {
 
 
+
 		bool enabled;
-		bool shadow;
 		Color color;
 		Matrix32 xform;
 		float height;
@@ -586,21 +586,26 @@ public:
 		RID texture;
 		Vector2 texture_offset;
 		RID canvas;
+		RID shadow_buffer;
+		int shadow_buffer_size;
+		float shadow_esm_mult;
 
 
 		void *texture_cache; // implementation dependent
 		Rect2 rect_cache;
 		Matrix32 xform_cache;
+		float radius_cache; //used for shadow far plane
+		CameraMatrix shadow_matrix_cache;
 
 		Matrix32 light_shader_xform;
 		Vector2 light_shader_pos;
 
+		CanvasLight *shadows_next_ptr;
 		CanvasLight *filter_next_ptr;
 		CanvasLight *next_ptr;
 
 		CanvasLight() {
-			enabled=true;
-			shadow=false;
+			enabled=true;			
 			color=Color(1,1,1);
 			height=0;
 			z_min=-1024;
@@ -612,9 +617,24 @@ public:
 			texture_cache=NULL;
 			next_ptr=NULL;
 			filter_next_ptr=NULL;
+			shadow_buffer_size=2048;
+			shadow_esm_mult=80;
+
 		}
 	};
 
+	struct CanvasItem;
+
+	struct CanvasItemMaterial  {
+
+		RID shader;
+		Map<StringName,Variant> shader_param;
+		uint32_t shader_version;
+		Set<CanvasItem*> owners;
+		bool unshaded;
+
+		CanvasItemMaterial() {unshaded=false; shader_version=0; }
+	};
 
 	struct CanvasItem {
 
@@ -744,16 +764,14 @@ public:
 		mutable bool rect_dirty;
 		mutable Rect2 rect;
 		CanvasItem*next;
-		RID shader;
-		Map<StringName,Variant> shader_param;
-		uint32_t shader_version;
+		CanvasItemMaterial* material;
 
 
 		float final_opacity;
 		Matrix32 final_transform;
 		Rect2 final_clip_rect;
 		CanvasItem* final_clip_owner;
-		CanvasItem* shader_owner;
+		CanvasItem* material_owner;
 		ViewportRender *vp_render;
 
 		Rect2 global_rect_cache;
@@ -881,8 +899,8 @@ public:
 			return rect;
 		}
 
-		void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL;  shader_owner=NULL;}
-		CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1;  blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; shader_version=0; shader_owner=NULL;}
+		void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL;  material_owner=NULL;}
+		CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1;  blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; material_owner=NULL; material=NULL; }
 		virtual ~CanvasItem() { clear(); }
 	};
 
@@ -905,7 +923,36 @@ public:
 	virtual void canvas_set_transform(const Matrix32& p_transform)=0;
 
 	virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light)=0;
+	virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow)=0;
+	/* LIGHT SHADOW MAPPING */
+
+	virtual RID canvas_light_occluder_create()=0;
+	virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines)=0;
+
+
+	virtual RID canvas_light_shadow_buffer_create(int p_width)=0;
 
+	struct CanvasLightOccluderInstance {
+
+
+		bool enabled;
+		RID canvas;
+		RID polygon;
+		RID polygon_buffer;
+		Rect2 aabb_cache;
+		Matrix32 xform;
+		Matrix32 xform_cache;
+		int light_mask;
+		VS::CanvasOccluderPolygonCullMode cull_cache;
+
+		CanvasLightOccluderInstance *next;
+
+		CanvasLightOccluderInstance() { enabled=true; next=NULL; light_mask=1; cull_cache=VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; }
+	};
+
+
+
+	virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache)=0;
 
 	/* ENVIRONMENT */
 	
@@ -945,6 +992,8 @@ public:
 	virtual bool is_environment(const RID& p_rid) const=0;
 	virtual bool is_shader(const RID& p_rid) const=0;
 
+	virtual bool is_canvas_light_occluder(const RID& p_rid) const=0;
+
 	virtual void free(const RID& p_rid)=0;
 
 	virtual void init()=0;

+ 333 - 44
servers/visual/visual_server_raster.cpp

@@ -3765,55 +3765,32 @@ void VisualServerRaster::canvas_item_set_z_as_relative_to_parent(RID p_item, boo
 
 }
 
-void VisualServerRaster::canvas_item_set_use_parent_shader(RID p_item, bool p_enable) {
+void VisualServerRaster::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {
 
 	VS_CHANGED;
 	CanvasItem *canvas_item = canvas_item_owner.get( p_item );
 	ERR_FAIL_COND(!canvas_item);
-	canvas_item->use_parent_shader=p_enable;
+	canvas_item->use_parent_material=p_enable;
 
 }
 
-void VisualServerRaster::canvas_item_set_shader(RID p_item, RID p_shader) {
+void VisualServerRaster::canvas_item_set_material(RID p_item, RID p_material) {
 
 	VS_CHANGED;
 	CanvasItem *canvas_item = canvas_item_owner.get( p_item );
 	ERR_FAIL_COND(!canvas_item);
-	canvas_item->shader=p_shader;
-}
-
-RID VisualServerRaster::canvas_item_get_shader(RID p_item) const{
-
-	CanvasItem *canvas_item = canvas_item_owner.get( p_item );
-	ERR_FAIL_COND_V(!canvas_item,RID());
-	return canvas_item->shader;
 
-}
+	if (canvas_item->material)
+		canvas_item->material->owners.erase(canvas_item);
 
-void VisualServerRaster::canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value){
+	canvas_item->material=NULL;
 
-	VS_CHANGED;
-	CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item );
-	ERR_FAIL_COND(!canvas_item);
-	if (p_value.get_type()==Variant::NIL)
-		canvas_item->shader_param.erase(p_param);
-	else
-		canvas_item->shader_param[p_param]=p_value;
-
-}
-Variant VisualServerRaster::canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const{
-
-	CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item );
-	ERR_FAIL_COND_V(!canvas_item,Variant());
-	if (!canvas_item->shader_param.has(p_param)) {
-		ERR_FAIL_COND_V(!canvas_item->shader.is_valid(),Variant());
-		return rasterizer->shader_get_default_param(canvas_item->shader,p_param);
+	if (canvas_item_material_owner.owns(p_material)) {
+		canvas_item->material=canvas_item_material_owner.get(p_material);
+		canvas_item->material->owners.insert(canvas_item);
 	}
-
-	return canvas_item->shader_param[p_param];
 }
 
-
 void VisualServerRaster::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) {
 
 	VS_CHANGED;
@@ -3989,19 +3966,41 @@ void VisualServerRaster::canvas_light_set_shadow_enabled(RID p_light, bool p_ena
 
 	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
 	ERR_FAIL_COND(!clight);
-	clight->shadow=p_enabled;
+
+	if (clight->shadow_buffer.is_valid()==p_enabled)
+		return;
+	if (p_enabled) {
+		clight->shadow_buffer=rasterizer->canvas_light_shadow_buffer_create(clight->shadow_buffer_size);
+	} else {
+		rasterizer->free(clight->shadow_buffer);
+		clight->shadow_buffer=RID();
+
+	}
 
 }
+
 void VisualServerRaster::canvas_light_set_shadow_buffer_size(RID p_light, int p_size){
 
 	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
 	ERR_FAIL_COND(!clight);
 
+	ERR_FAIL_COND(p_size<32 || p_size>16384);
+
+	clight->shadow_buffer_size=nearest_power_of_2(p_size);
+
+
+	if (clight->shadow_buffer.is_valid()) {
+		rasterizer->free(clight->shadow_buffer);
+		clight->shadow_buffer=rasterizer->canvas_light_shadow_buffer_create(clight->shadow_buffer_size);
+	}
+
 }
-void VisualServerRaster::canvas_light_set_shadow_filter(RID p_light, int p_size){
+
+void VisualServerRaster::canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier) {
 
 	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
 	ERR_FAIL_COND(!clight);
+	clight->shadow_esm_mult=p_multiplier;
 
 }
 
@@ -4009,26 +4008,217 @@ void VisualServerRaster::canvas_light_set_shadow_filter(RID p_light, int p_size)
 
 RID VisualServerRaster::canvas_light_occluder_create() {
 
-	return RID();
+	Rasterizer::CanvasLightOccluderInstance *occluder = memnew( Rasterizer::CanvasLightOccluderInstance );
+
+	return canvas_light_occluder_owner.make_rid( occluder );
+
 }
 
 void VisualServerRaster::canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas) {
 
+	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+	ERR_FAIL_COND(!occluder);
+
+	if (occluder->canvas.is_valid()) {
+
+		Canvas *canvas = canvas_owner.get(occluder->canvas);
+		canvas->occluders.erase(occluder);
+	}
+
+	if (!canvas_owner.owns(p_canvas))
+		p_canvas=RID();
+
+	occluder->canvas=p_canvas;
 
+	if (occluder->canvas.is_valid()) {
+
+		Canvas *canvas = canvas_owner.get(occluder->canvas);
+		canvas->occluders.insert(occluder);
+	}
 }
 
 void VisualServerRaster::canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled){
 
+	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+	ERR_FAIL_COND(!occluder);
+
+	occluder->enabled=p_enabled;
 
 }
 
-void VisualServerRaster::canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape){
+void VisualServerRaster::canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon) {
+
+	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+	ERR_FAIL_COND(!occluder);
+
+	if (occluder->polygon.is_valid()) {
+		CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon);
+		if (occluder_poly) {
+			occluder_poly->owners.erase(occluder);
+		}
+	}
 
+	occluder->polygon=p_polygon;
+	occluder->polygon_buffer=RID();
+
+	if (occluder->polygon.is_valid()) {
+		CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon);
+		if (!occluder_poly)
+			occluder->polygon=RID();
+		ERR_FAIL_COND(!occluder_poly);
+		occluder_poly->owners.insert(occluder);
+		occluder->polygon_buffer=occluder_poly->occluder;
+		occluder->aabb_cache=occluder_poly->aabb;
+		occluder->cull_cache=occluder_poly->cull_mode;
+	}
 
 }
 
 
 
+
+void VisualServerRaster::canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform) {
+
+	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+	ERR_FAIL_COND(!occluder);
+
+	occluder->xform=p_xform;
+
+}
+
+void VisualServerRaster::canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask) {
+
+	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
+	ERR_FAIL_COND(!occluder);
+
+	occluder->light_mask=p_mask;
+
+}
+
+
+RID VisualServerRaster::canvas_occluder_polygon_create() {
+
+	CanvasLightOccluderPolygon * occluder_poly = memnew( CanvasLightOccluderPolygon );
+	occluder_poly->occluder=rasterizer->canvas_light_occluder_create();
+	return canvas_light_occluder_polygon_owner.make_rid(occluder_poly);
+
+}
+
+void VisualServerRaster::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const DVector<Vector2>& p_shape, bool p_close){
+
+	if (p_shape.size()<3) {
+		canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon,p_shape);
+		return;
+	}
+
+	DVector<Vector2> lines;
+	int lc = p_shape.size()*2;
+
+	lines.resize(lc-(p_close?0:2));
+	{
+		DVector<Vector2>::Write w = lines.write();
+		DVector<Vector2>::Read r = p_shape.read();
+
+		int max=lc/2;
+		if (!p_close) {
+			max--;
+		}
+		for(int i=0;i<max;i++) {
+
+			Vector2 a = r[i];
+			Vector2 b = r[(i+1)%(lc/2)];
+			w[i*2+0]=a;
+			w[i*2+1]=b;
+		}
+
+	}
+
+	canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon,lines);
+}
+
+void VisualServerRaster::canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape) {
+
+	CanvasLightOccluderPolygon * occluder_poly = canvas_light_occluder_polygon_owner.get(p_occluder_polygon);
+	ERR_FAIL_COND(!occluder_poly);
+	ERR_FAIL_COND(p_shape.size()&1);
+
+	int lc = p_shape.size();
+	occluder_poly->aabb=Rect2();
+	{
+		DVector<Vector2>::Read r = p_shape.read();
+		for(int i=0;i<lc;i++) {
+			if (i==0)
+				occluder_poly->aabb.pos=r[i];
+			else
+				occluder_poly->aabb.expand_to(r[i]);
+		}
+	}
+
+	rasterizer->canvas_light_occluder_set_polylines(occluder_poly->occluder,p_shape);
+	for( Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=occluder_poly->owners.front();E;E=E->next()) {
+		E->get()->aabb_cache=occluder_poly->aabb;
+	}
+}
+
+void VisualServerRaster::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode) {
+
+	CanvasLightOccluderPolygon * occluder_poly = canvas_light_occluder_polygon_owner.get(p_occluder_polygon);
+	ERR_FAIL_COND(!occluder_poly);
+	occluder_poly->cull_mode=p_mode;
+	for( Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=occluder_poly->owners.front();E;E=E->next()) {
+		E->get()->cull_cache=p_mode;
+	}
+
+}
+
+RID VisualServerRaster::canvas_item_material_create() {
+
+	Rasterizer::CanvasItemMaterial *material = memnew( Rasterizer::CanvasItemMaterial );
+	return canvas_item_material_owner.make_rid(material);
+
+}
+
+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 );
+	ERR_FAIL_COND(!material);
+	material->shader=p_shader;
+
+}
+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 );
+	ERR_FAIL_COND(!material);
+	if (p_value.get_type()==Variant::NIL)
+		material->shader_param.erase(p_param);
+	else
+		material->shader_param[p_param]=p_value;
+
+
+}
+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 );
+	ERR_FAIL_COND_V(!material,Variant());
+	if (!material->shader_param.has(p_param)) {
+		ERR_FAIL_COND_V(!material->shader.is_valid(),Variant());
+		return rasterizer->shader_get_default_param(material->shader,p_param);
+	}
+
+	return material->shader_param[p_param];
+}
+
+void VisualServerRaster::canvas_item_material_set_unshaded(RID p_material, bool p_unshaded){
+
+	VS_CHANGED;
+	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material );
+	ERR_FAIL_COND(!material);
+	material->unshaded=p_unshaded;
+
+}
+
+
 /******** CANVAS *********/
 
 
@@ -4285,6 +4475,10 @@ void VisualServerRaster::free( RID p_rid ) {
 			E->get()->canvas=RID();
 		}
 
+		for (Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=canvas->occluders.front();E;E=E->next()) {
+
+			E->get()->canvas=RID();
+		}
 
 		canvas_owner.free( p_rid );
 		
@@ -4314,10 +4508,26 @@ void VisualServerRaster::free( RID p_rid ) {
 			canvas_item->child_items[i]->parent=RID();
 		}
 
+		if (canvas_item->material) {
+			canvas_item->material->owners.erase(canvas_item);
+		}
+
 		canvas_item_owner.free( p_rid );
 		
 		memdelete( canvas_item );
 
+	} else if (canvas_item_material_owner.owns(p_rid)) {
+
+		Rasterizer::CanvasItemMaterial *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()) {
+
+			E->get()->material=NULL;
+		}
+
+		canvas_item_material_owner.free(p_rid);
+		memdelete(material);
+
 	} else if (canvas_light_owner.owns(p_rid)) {
 
 		Rasterizer::CanvasLight *canvas_light = canvas_light_owner.get(p_rid);
@@ -4329,9 +4539,44 @@ void VisualServerRaster::free( RID p_rid ) {
 				canvas->lights.erase(canvas_light);
 		}
 
+		if (canvas_light->shadow_buffer.is_valid())
+			rasterizer->free(canvas_light->shadow_buffer);
+
 		canvas_light_owner.free( p_rid );
 		memdelete( canvas_light );
 
+	} else if (canvas_light_occluder_owner.owns(p_rid)) {
+
+		Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_rid);
+		ERR_FAIL_COND(!occluder);
+
+		if (occluder->polygon.is_valid()) {
+
+			CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(occluder->polygon);
+			if (occluder_poly) {
+				occluder_poly->owners.erase(occluder);
+			}
+
+		}
+
+		canvas_light_occluder_owner.free( p_rid );
+		memdelete(occluder);
+
+	} else if (canvas_light_occluder_polygon_owner.owns(p_rid)) {
+
+		CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_rid);
+		ERR_FAIL_COND(!occluder_poly);
+		rasterizer->free(occluder_poly->occluder);
+
+		while(occluder_poly->owners.size()) {
+
+			occluder_poly->owners.front()->get()->polygon=RID();
+			occluder_poly->owners.erase( occluder_poly->owners.front() );
+		}
+
+		canvas_light_occluder_polygon_owner.free( p_rid );
+		memdelete(occluder_poly);
+
 	} else if (scenario_owner.owns(p_rid)) {
 		
 		Scenario *scenario=scenario_owner.get(p_rid);
@@ -6410,7 +6655,7 @@ void VisualServerRaster::_render_canvas_item_viewport(VisualServer* p_self,void
 
 }
 
-void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_shader_owner) {
+void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_material_owner) {
 
 	CanvasItem *ci = p_canvas_item;
 
@@ -6455,11 +6700,11 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 		ci->vp_render=NULL;
 	}
 
-	if (ci->use_parent_shader && p_shader_owner)
-		ci->shader_owner=p_shader_owner;
+	if (ci->use_parent_material && p_material_owner)
+		ci->material_owner=p_material_owner;
 	else {
-		p_shader_owner=ci;
-		ci->shader_owner=NULL;
+		p_material_owner=ci;
+		ci->material_owner=NULL;
 	}
 
 
@@ -6493,7 +6738,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 
 		if (child_items[i]->ontop)
 			continue;
-		_render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_shader_owner);
+		_render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_material_owner);
 	}
 
 
@@ -6524,7 +6769,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 
 		if (!child_items[i]->ontop)
 			continue;
-		_render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_shader_owner);
+		_render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_material_owner);
 	}
 
 }
@@ -6658,6 +6903,8 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 
 		Rect2 clip_rect(0,0,viewport_rect.width,viewport_rect.height);
 		Rasterizer::CanvasLight *lights=NULL;
+		Rasterizer::CanvasLight *lights_with_shadow=NULL;
+		Rect2 shadow_rect;
 
 		for (Map<RID,Viewport::CanvasData>::Element *E=p_viewport->canvas_map.front();E;E=E->next()) {
 
@@ -6676,6 +6923,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 					cl->rect_cache=Rect2(-offset+cl->texture_offset,tsize);
 					cl->xform_cache=xf * cl->xform;
 
+
 					if (clip_rect.intersects_transformed(cl->xform_cache,cl->rect_cache)) {
 						cl->filter_next_ptr=lights;
 						lights=cl;
@@ -6685,16 +6933,55 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 						scale.elements[2]=cl->rect_cache.pos;
 						cl->light_shader_xform = (cl->xform_cache * scale).affine_inverse();
 						cl->light_shader_pos=cl->xform_cache[2];
+						if (cl->shadow_buffer.is_valid()) {
+							cl->shadows_next_ptr=lights_with_shadow;
+							if (lights_with_shadow==NULL) {
+								shadow_rect = cl->xform_cache.xform(cl->rect_cache);
+							} else {
+								shadow_rect=shadow_rect.merge( cl->xform_cache.xform(cl->rect_cache) );
+							}
+							lights_with_shadow=cl;
+							cl->radius_cache=cl->rect_cache.size.length();
+
+						}
 					}
+				}
+			}
+
+			canvas_map[ Viewport::CanvasKey( E->key(), E->get().layer) ]=&E->get();
 
+		}
+
+		if (lights_with_shadow) {
+			//update shadows if any
+
+			Rasterizer::CanvasLightOccluderInstance * occluders=NULL;
+
+			//make list of occluders
+			for (Map<RID,Viewport::CanvasData>::Element *E=p_viewport->canvas_map.front();E;E=E->next()) {
+
+				Matrix32 xf = p_viewport->global_transform * E->get().transform;
 
+				for(Set<Rasterizer::CanvasLightOccluderInstance*>::Element *F=E->get().canvas->occluders.front();F;F=F->next()) {
 
+					F->get()->xform_cache = xf * F->get()->xform;
+					if (shadow_rect.intersects_transformed(F->get()->xform_cache,F->get()->aabb_cache)) {
 
+						F->get()->next=occluders;
+						occluders=F->get();
+
+					}
 				}
 			}
+			//update the light shadowmaps with them
+			Rasterizer::CanvasLight *light=lights_with_shadow;
+			while(light) {
 
-			canvas_map[ Viewport::CanvasKey( E->key(), E->get().layer) ]=&E->get();
+				rasterizer->canvas_light_shadow_buffer_update(light->shadow_buffer,light->xform_cache.affine_inverse(),light->item_mask,light->radius_cache/1000.0,light->radius_cache*1.1,occluders,&light->shadow_matrix_cache);
+				light=light->shadows_next_ptr;
+			}
 
+			rasterizer->set_viewport(viewport_rect); //must reset viewport afterwards
 		}
 
 		for (Map<Viewport::CanvasKey,Viewport::CanvasData*>::Element *E=canvas_map.front();E;E=E->next()) {
@@ -6719,6 +7006,8 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 			i++;
 
 		}
+
+		rasterizer->canvas_debug_viewport_shadows(lights_with_shadow);
 	}
 
 	//capture

+ 46 - 15
servers/visual/visual_server_raster.h

@@ -371,7 +371,7 @@ class VisualServerRaster : public VisualServer {
 
 
 
-
+	mutable RID_Owner<Rasterizer::CanvasItemMaterial> canvas_item_material_owner;
 
 	struct CanvasItem : public Rasterizer::CanvasItem {
 
@@ -384,7 +384,7 @@ class VisualServerRaster : public VisualServer {
 		bool sort_y;
 		float opacity;
 		float self_opacity;
-		bool use_parent_shader;
+		bool use_parent_material;
 
 
 		Vector<CanvasItem*> child_items;
@@ -396,7 +396,7 @@ class VisualServerRaster : public VisualServer {
 			opacity=1;
 			self_opacity=1;
 			sort_y=false;
-			use_parent_shader=false;
+			use_parent_material=false;
 			z_relative=true;
 		}
 	};
@@ -410,6 +410,24 @@ class VisualServerRaster : public VisualServer {
 		}
 	};
 
+	struct CanvasLightOccluder;
+
+	struct CanvasLightOccluderPolygon {
+
+		bool active;
+		Rect2 aabb;
+		CanvasOccluderPolygonCullMode cull_mode;
+		RID occluder;
+		Set<Rasterizer::CanvasLightOccluderInstance*> owners;
+
+		CanvasLightOccluderPolygon() { active=false; cull_mode=CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; }
+	};
+
+
+	RID_Owner<CanvasLightOccluderPolygon> canvas_light_occluder_polygon_owner;
+
+	RID_Owner<Rasterizer::CanvasLightOccluderInstance> canvas_light_occluder_owner;
+
 	struct CanvasLight;
 
 	struct Canvas {
@@ -422,6 +440,7 @@ class VisualServerRaster : public VisualServer {
 		};
 
 		Set<Rasterizer::CanvasLight*> lights;
+		Set<Rasterizer::CanvasLightOccluderInstance*> occluders;
 
 		Vector<ChildItem> child_items;
 		Color modulate;
@@ -610,7 +629,7 @@ class VisualServerRaster : public VisualServer {
 	void _render_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario);
 	static void _render_canvas_item_viewport(VisualServer* p_self,void *p_vp,const Rect2& p_rect);
 	void _render_canvas_item_tree(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, const Color &p_modulate, Rasterizer::CanvasLight *p_lights);
-	void _render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_shader_owner);
+	void _render_canvas_item(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, float p_opacity, int p_z, Rasterizer::CanvasItem **z_list, Rasterizer::CanvasItem **z_last_list, CanvasItem *p_canvas_clip, CanvasItem *p_material_owner);
 	void _render_canvas(Canvas *p_canvas, const Matrix32 &p_transform, Rasterizer::CanvasLight *p_lights);
 	Vector<Vector3> _camera_generate_endpoints(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);
 	Vector<Plane> _camera_generate_orthogonal_planes(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);
@@ -1131,15 +1150,8 @@ public:
 	virtual void canvas_item_set_z(RID p_item, int p_z);
 	virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable);
 
-	virtual void canvas_item_set_shader(RID p_item, RID p_shader);
-	virtual RID canvas_item_get_shader(RID p_item) const;
-
-	virtual void canvas_item_set_use_parent_shader(RID p_item, bool p_enable);
-
-
-
-	virtual void canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value);
-	virtual Variant canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const;
+	virtual void canvas_item_set_material(RID p_item, RID p_material);
+	virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
 
 	virtual RID canvas_light_create();
 	virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas);
@@ -1156,17 +1168,36 @@ public:
 	virtual void canvas_light_set_subtract_mode(RID p_light, bool p_enable);
 	virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled);
 	virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size);
-	virtual void canvas_light_set_shadow_filter(RID p_light, int p_size);
+	virtual void canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier);
 
 
 	virtual RID canvas_light_occluder_create();
 	virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas);
 	virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled);
-	virtual void canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape);
+	virtual void canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon);
+	virtual void canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform);
+	virtual void canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask);
+
+
+	virtual RID canvas_occluder_polygon_create();
+	virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon,const DVector<Vector2>& p_shape,bool p_close);
+	virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape);
+	virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode);
+
+
 
 	virtual void canvas_item_clear(RID p_item);
 	virtual void canvas_item_raise(RID p_item);
 
+	/* CANVAS ITEM MATERIAL */
+
+	virtual RID canvas_item_material_create();
+	virtual void canvas_item_material_set_shader(RID p_material, RID p_shader);
+	virtual void canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value);
+	virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const;
+	virtual void canvas_item_material_set_unshaded(RID p_material, bool p_unshaded);
+
+
 	/* CURSOR */
 	virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0); // radians
 	virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor=0);

+ 21 - 9
servers/visual/visual_server_wrap_mt.h

@@ -1139,14 +1139,9 @@ public:
 	FUNC2(canvas_item_set_z,RID,int);
 	FUNC2(canvas_item_set_z_as_relative_to_parent,RID,bool);
 
-	FUNC2(canvas_item_set_shader,RID, RID );
-	FUNC1RC(RID,canvas_item_get_shader,RID );
+	FUNC2(canvas_item_set_material,RID, RID );
 
-	FUNC2(canvas_item_set_use_parent_shader,RID, bool );
-
-
-	FUNC3(canvas_item_set_shader_param,RID,const StringName&,const Variant&);
-	FUNC2RC(Variant,canvas_item_get_shader_param,RID,const StringName&);
+	FUNC2(canvas_item_set_use_parent_material,RID, bool );
 
 	FUNC1(canvas_item_clear,RID);
 	FUNC1(canvas_item_raise,RID);
@@ -1167,14 +1162,31 @@ public:
 	FUNC2(canvas_light_set_subtract_mode,RID,bool);
 	FUNC2(canvas_light_set_shadow_enabled,RID,bool);
 	FUNC2(canvas_light_set_shadow_buffer_size,RID,int);
-	FUNC2(canvas_light_set_shadow_filter,RID,int);
+	FUNC2(canvas_light_set_shadow_esm_multiplier,RID,float);
+
 
 	/* CANVAS OCCLUDER */
 
 	FUNC0R(RID,canvas_light_occluder_create);
 	FUNC2(canvas_light_occluder_attach_to_canvas,RID,RID);
 	FUNC2(canvas_light_occluder_set_enabled,RID,bool);
-	FUNC2(canvas_light_occluder_set_shape,RID,const DVector<Vector2>&);
+	FUNC2(canvas_light_occluder_set_polygon,RID,RID);
+	FUNC2(canvas_light_occluder_set_transform,RID,const Matrix32&);
+	FUNC2(canvas_light_occluder_set_light_mask,RID,int);
+
+
+	FUNC0R(RID,canvas_occluder_polygon_create);
+	FUNC3(canvas_occluder_polygon_set_shape,RID,const DVector<Vector2>&,bool);
+	FUNC2(canvas_occluder_polygon_set_shape_as_lines,RID,const DVector<Vector2>&);
+	FUNC2(canvas_occluder_polygon_set_cull_mode,RID,CanvasOccluderPolygonCullMode);
+
+	/* CANVAS MATERIAL */
+
+	FUNC0R(RID,canvas_item_material_create);
+	FUNC2(canvas_item_material_set_shader,RID,RID);
+	FUNC3(canvas_item_material_set_shader_param,RID,const StringName&,const Variant&);
+	FUNC2RC(Variant,canvas_item_material_get_shader_param,RID,const StringName&);
+	FUNC2(canvas_item_material_set_unshaded,RID,bool);
 
 	/* CURSOR */
 	FUNC2(cursor_set_rotation,float , int ); // radians

+ 25 - 8
servers/visual_server.h

@@ -998,13 +998,9 @@ public:
 	virtual void canvas_item_clear(RID p_item)=0;
 	virtual void canvas_item_raise(RID p_item)=0;
 
-	virtual void canvas_item_set_shader(RID p_item, RID p_shader)=0;
-	virtual RID canvas_item_get_shader(RID p_item) const=0;
+	virtual void canvas_item_set_material(RID p_item, RID p_material)=0;
 
-	virtual void canvas_item_set_use_parent_shader(RID p_item, bool p_enable)=0;
-
-	virtual void canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value)=0;
-	virtual Variant canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const=0;
+	virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable)=0;
 
 	virtual RID canvas_light_create()=0;
 	virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas)=0;
@@ -1021,13 +1017,34 @@ public:
 	virtual void canvas_light_set_subtract_mode(RID p_light, bool p_enable)=0;
 	virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled)=0;
 	virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size)=0;
-	virtual void canvas_light_set_shadow_filter(RID p_light, int p_size)=0;
+	virtual void canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier)=0;
+
 
 
 	virtual RID canvas_light_occluder_create()=0;
 	virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas)=0;
 	virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled)=0;
-	virtual void canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape)=0;
+	virtual void canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon)=0;
+	virtual void canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform)=0;
+	virtual void canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask)=0;
+
+	virtual RID canvas_occluder_polygon_create()=0;
+	virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon,const DVector<Vector2>& p_shape,bool p_closed)=0;
+	virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape)=0;
+	enum CanvasOccluderPolygonCullMode {
+		CANVAS_OCCLUDER_POLYGON_CULL_DISABLED,
+		CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE,
+		CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE,
+	};
+	virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode)=0;
+
+	/* CANVAS ITEM MATERIAL */
+
+	virtual RID canvas_item_material_create()=0;
+	virtual void canvas_item_material_set_shader(RID p_material, RID p_shader)=0;
+	virtual void canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value)=0;
+	virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const=0;
+	virtual void canvas_item_material_set_unshaded(RID p_material, bool p_unshaded)=0;
 
 	/* CURSOR */
 	virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0)=0; // radians

+ 2 - 0
tools/editor/editor_node.cpp

@@ -90,6 +90,7 @@
 #include "plugins/baked_light_editor_plugin.h"
 #include "plugins/polygon_2d_editor_plugin.h"
 #include "plugins/navigation_polygon_editor_plugin.h"
+#include "plugins/light_occluder_2d_editor_plugin.h"
 // end
 #include "tools/editor/io_plugins/editor_texture_import_plugin.h"
 #include "tools/editor/io_plugins/editor_scene_import_plugin.h"
@@ -4115,6 +4116,7 @@ EditorNode::EditorNode() {
 	add_editor_plugin( memnew( PathEditorPlugin(this) ) );
 	add_editor_plugin( memnew( BakedLightEditorPlugin(this) ) );
 	add_editor_plugin( memnew( Polygon2DEditorPlugin(this) ) );
+	add_editor_plugin( memnew( LightOccluder2DEditorPlugin(this) ) );
 	add_editor_plugin( memnew( NavigationPolygonEditorPlugin(this) ) );
 
 	for(int i=0;i<EditorPlugins::get_plugin_count();i++)

二进制
tools/editor/icons/icon_canvas_item_material.png


二进制
tools/editor/icons/icon_canvas_modulate.png


二进制
tools/editor/icons/icon_light_occluder_2d.png


二进制
tools/editor/icons/icon_occluder_polygon_2d.png


+ 1 - 0
tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp

@@ -4,6 +4,7 @@
 #include "os/file_access.h"
 #include "tools/editor/editor_settings.h"
 
+
 void CollisionPolygon2DEditor::_notification(int p_what) {
 
 	switch(p_what) {

+ 500 - 0
tools/editor/plugins/light_occluder_2d_editor_plugin.cpp

@@ -0,0 +1,500 @@
+#include "light_occluder_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "os/file_access.h"
+#include "tools/editor/editor_settings.h"
+
+void LightOccluder2DEditor::_notification(int p_what) {
+
+	switch(p_what) {
+
+		case NOTIFICATION_READY: {
+
+			button_create->set_icon( get_icon("Edit","EditorIcons"));
+			button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
+			button_edit->set_pressed(true);
+			get_tree()->connect("node_removed",this,"_node_removed");
+			create_poly->connect("confirmed",this,"_create_poly");
+
+		} break;
+		case NOTIFICATION_FIXED_PROCESS: {
+
+
+		} break;
+	}
+
+}
+void LightOccluder2DEditor::_node_removed(Node *p_node) {
+
+	if(p_node==node) {
+		node=NULL;
+		hide();
+		canvas_item_editor->get_viewport_control()->update();
+	}
+
+}
+
+
+Vector2 LightOccluder2DEditor::snap_point(const Vector2& p_point) const {
+
+	if (canvas_item_editor->is_snap_active()) {
+
+		return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap());
+
+	} else {
+		return p_point;
+	}
+}
+
+void LightOccluder2DEditor::_menu_option(int p_option) {
+
+	switch(p_option) {
+
+		case MODE_CREATE: {
+
+			mode=MODE_CREATE;
+			button_create->set_pressed(true);
+			button_edit->set_pressed(false);
+		} break;
+		case MODE_EDIT: {
+
+			mode=MODE_EDIT;
+			button_create->set_pressed(false);
+			button_edit->set_pressed(true);
+		} break;
+
+	}
+}
+
+void LightOccluder2DEditor::_wip_close(bool p_closed) {
+
+	undo_redo->create_action("Create Poly");
+	undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",node->get_occluder_polygon()->get_polygon());
+	undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",wip);
+	undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_closed",node->get_occluder_polygon()->is_closed());
+	undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_closed",p_closed);
+
+	undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+	undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+	undo_redo->commit_action();
+	wip.clear();
+	wip_active=false;
+	mode=MODE_EDIT;
+	button_edit->set_pressed(true);
+	button_create->set_pressed(false);
+	edited_point=-1;
+}
+
+bool LightOccluder2DEditor::forward_input_event(const InputEvent& p_event) {
+
+
+	if (!node)
+		return false;
+
+	if (node->get_occluder_polygon().is_null()) {
+		if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
+			create_poly->set_text("No OccluderPolygon2D resource on this node.\nCreate and assign one?");
+			create_poly->popup_centered_minsize();
+		}
+		return false;
+	}
+	switch(p_event.type) {
+
+		case InputEvent::MOUSE_BUTTON: {
+
+			const InputEventMouseButton &mb=p_event.mouse_button;
+
+			Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+
+			Vector2 gpoint = Point2(mb.x,mb.y);
+			Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+			cpoint=snap_point(cpoint);
+			cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
+
+			Vector<Vector2> poly = Variant(node->get_occluder_polygon()->get_polygon());
+
+			//first check if a point is to be added (segment split)
+			real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);
+
+			switch(mode) {
+
+
+				case MODE_CREATE: {
+
+					if (mb.button_index==BUTTON_LEFT && mb.pressed) {
+
+
+						if (!wip_active) {
+
+							wip.clear();
+							wip.push_back( cpoint );
+							wip_active=true;
+							edited_point_pos=cpoint;
+							canvas_item_editor->get_viewport_control()->update();
+							edited_point=1;
+							return true;
+						} else {
+
+
+							if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
+								//wip closed
+								_wip_close(true);
+
+								return true;
+							} else if (wip.size()>1 && xform.xform(wip[wip.size()-1]).distance_to(gpoint)<grab_treshold) {
+									//wip closed
+									_wip_close(false);
+									return true;
+
+							} else {
+
+								wip.push_back( cpoint );
+								edited_point=wip.size();
+								canvas_item_editor->get_viewport_control()->update();
+								return true;
+
+								//add wip point
+							}
+						}
+					} else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) {
+						_wip_close(true);
+					}
+
+
+
+				} break;
+
+				case MODE_EDIT: {
+
+					if (mb.button_index==BUTTON_LEFT) {
+						if (mb.pressed) {
+
+							if (mb.mod.control) {
+
+
+								if (poly.size() < 3) {
+
+									undo_redo->create_action("Edit Poly");
+									undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+									poly.push_back(cpoint);
+									undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+									undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+									undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+									undo_redo->commit_action();
+									return true;
+								}
+
+								//search edges
+								int closest_idx=-1;
+								Vector2 closest_pos;
+								real_t closest_dist=1e10;
+								for(int i=0;i<poly.size();i++) {
+
+									Vector2 points[2] ={ xform.xform(poly[i]),
+										xform.xform(poly[(i+1)%poly.size()]) };
+
+									Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
+									if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2)
+										continue; //not valid to reuse point
+
+									real_t d = cp.distance_to(gpoint);
+									if (d<closest_dist && d<grab_treshold) {
+										closest_dist=d;
+										closest_pos=cp;
+										closest_idx=i;
+									}
+
+
+								}
+
+								if (closest_idx>=0) {
+
+									pre_move_edit=poly;
+									poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos));
+									edited_point=closest_idx+1;
+									edited_point_pos=xform.affine_inverse().xform(closest_pos);
+									node->get_occluder_polygon()->set_polygon(Variant(poly));
+									canvas_item_editor->get_viewport_control()->update();
+									return true;
+								}
+							} else {
+
+								//look for points to move
+
+								int closest_idx=-1;
+								Vector2 closest_pos;
+								real_t closest_dist=1e10;
+								for(int i=0;i<poly.size();i++) {
+
+									Vector2 cp =xform.xform(poly[i]);
+
+									real_t d = cp.distance_to(gpoint);
+									if (d<closest_dist && d<grab_treshold) {
+										closest_dist=d;
+										closest_pos=cp;
+										closest_idx=i;
+									}
+
+								}
+
+								if (closest_idx>=0) {
+
+									pre_move_edit=poly;
+									edited_point=closest_idx;
+									edited_point_pos=xform.affine_inverse().xform(closest_pos);
+									canvas_item_editor->get_viewport_control()->update();
+									return true;
+								}
+							}
+						} else {
+
+							if (edited_point!=-1) {
+
+								//apply
+
+								ERR_FAIL_INDEX_V(edited_point,poly.size(),false);
+								poly[edited_point]=edited_point_pos;
+								undo_redo->create_action("Edit Poly");
+								undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+								undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",pre_move_edit);
+								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+								undo_redo->commit_action();
+
+								edited_point=-1;
+								return true;
+							}
+						}
+					} if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) {
+
+
+
+						int closest_idx=-1;
+						Vector2 closest_pos;
+						real_t closest_dist=1e10;
+						for(int i=0;i<poly.size();i++) {
+
+							Vector2 cp =xform.xform(poly[i]);
+
+							real_t d = cp.distance_to(gpoint);
+							if (d<closest_dist && d<grab_treshold) {
+								closest_dist=d;
+								closest_pos=cp;
+								closest_idx=i;
+							}
+
+						}
+
+						if (closest_idx>=0) {
+
+
+							undo_redo->create_action("Edit Poly (Remove Point)");
+							undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+							poly.remove(closest_idx);
+							undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
+							undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
+							undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
+							undo_redo->commit_action();
+							return true;
+						}
+
+					}
+
+
+
+				} break;
+			}
+
+
+
+		} break;
+		case InputEvent::MOUSE_MOTION: {
+
+			const InputEventMouseMotion &mm=p_event.mouse_motion;
+
+			if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {
+
+				Vector2 gpoint = Point2(mm.x,mm.y);
+				Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
+				cpoint=snap_point(cpoint);
+				edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
+
+				canvas_item_editor->get_viewport_control()->update();
+
+			}
+
+		} break;
+	}
+
+	return false;
+}
+void LightOccluder2DEditor::_canvas_draw() {
+
+	if (!node || !node->get_occluder_polygon().is_valid())
+		return;
+
+	Control *vpc = canvas_item_editor->get_viewport_control();
+
+	Vector<Vector2> poly;
+
+	if (wip_active)
+		poly=wip;
+	else
+		poly=Variant(node->get_occluder_polygon()->get_polygon());
+
+
+	Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+	Ref<Texture> handle= get_icon("EditorHandle","EditorIcons");
+
+	int len = poly.size();
+
+	for(int i=0;i<poly.size();i++) {
+
+
+		Vector2 p,p2;
+		p = i==edited_point ? edited_point_pos : poly[i];
+		if ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point))
+			p2=edited_point_pos;
+		else
+			p2 = poly[(i+1)%poly.size()];
+
+		Vector2 point = xform.xform(p);
+		Vector2 next_point = xform.xform(p2);
+
+		Color col=Color(1,0.3,0.1,0.8);
+
+		if (i==poly.size()-1 && (!node->get_occluder_polygon()->is_closed() || wip_active)) {
+
+		} else {
+			vpc->draw_line(point,next_point,col,2);
+		}
+		vpc->draw_texture(handle,point-handle->get_size()*0.5);
+	}
+}
+
+
+
+void LightOccluder2DEditor::edit(Node *p_collision_polygon) {
+
+	if (!canvas_item_editor) {
+		canvas_item_editor=CanvasItemEditor::get_singleton();
+	}
+
+	if (p_collision_polygon) {
+
+		node=p_collision_polygon->cast_to<LightOccluder2D>();
+		if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+			canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw");
+		wip.clear();
+		wip_active=false;
+		edited_point=-1;
+
+	} else {
+		node=NULL;
+
+		if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
+			canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw");
+
+	}
+
+}
+
+void LightOccluder2DEditor::_create_poly()  {
+
+	undo_redo->create_action("Create Occluder Polygon");
+	undo_redo->add_do_method(node,"set_occluder_polygon",Ref<OccluderPolygon2D>(memnew( OccluderPolygon2D)));
+	undo_redo->add_undo_method(node,"set_occluder_polygon",Variant(REF()));
+	undo_redo->commit_action();
+}
+
+void LightOccluder2DEditor::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("_menu_option"),&LightOccluder2DEditor::_menu_option);
+	ObjectTypeDB::bind_method(_MD("_canvas_draw"),&LightOccluder2DEditor::_canvas_draw);
+	ObjectTypeDB::bind_method(_MD("_node_removed"),&LightOccluder2DEditor::_node_removed);
+	ObjectTypeDB::bind_method(_MD("_create_poly"),&LightOccluder2DEditor::_create_poly);
+
+}
+
+
+LightOccluder2DEditor::LightOccluder2DEditor(EditorNode *p_editor) {
+
+	canvas_item_editor=NULL;
+	editor=p_editor;
+	undo_redo = editor->get_undo_redo();
+
+	add_child( memnew( VSeparator ));
+	button_create = memnew( ToolButton );
+	add_child(button_create);
+	button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE));
+	button_create->set_toggle_mode(true);
+	button_create->set_tooltip("Create a new polygon from scratch");
+
+	button_edit = memnew( ToolButton );
+	add_child(button_edit);
+	button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT));
+	button_edit->set_toggle_mode(true);
+	button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point.");
+
+	create_poly = memnew( ConfirmationDialog );
+	add_child(create_poly);
+	create_poly->get_ok()->set_text("Create");
+
+
+	//add_constant_override("separation",0);
+
+#if 0
+	options = memnew( MenuButton );
+	add_child(options);
+	options->set_area_as_parent_rect();
+	options->set_text("Polygon");
+	//options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE);
+	options->get_popup()->connect("item_pressed", this,"_menu_option");
+#endif
+
+	mode = MODE_EDIT;
+	wip_active=false;
+
+}
+
+
+void LightOccluder2DEditorPlugin::edit(Object *p_object) {
+
+	collision_polygon_editor->edit(p_object->cast_to<Node>());
+}
+
+bool LightOccluder2DEditorPlugin::handles(Object *p_object) const {
+
+	return p_object->is_type("LightOccluder2D");
+}
+
+void LightOccluder2DEditorPlugin::make_visible(bool p_visible) {
+
+	if (p_visible) {
+		collision_polygon_editor->show();
+	} else {
+
+		collision_polygon_editor->hide();
+		collision_polygon_editor->edit(NULL);
+	}
+
+}
+
+LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin(EditorNode *p_node) {
+
+	editor=p_node;
+	collision_polygon_editor = memnew( LightOccluder2DEditor(p_node) );
+	CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+
+	collision_polygon_editor->hide();
+
+
+
+}
+
+
+LightOccluder2DEditorPlugin::~LightOccluder2DEditorPlugin()
+{
+}
+

+ 87 - 0
tools/editor/plugins/light_occluder_2d_editor_plugin.h

@@ -0,0 +1,87 @@
+#ifndef LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H
+#define LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H
+
+
+
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/2d/light_occluder_2d.h"
+#include "scene/gui/tool_button.h"
+#include "scene/gui/button_group.h"
+
+/**
+	@author Juan Linietsky <[email protected]>
+*/
+class CanvasItemEditor;
+
+class LightOccluder2DEditor : public HBoxContainer {
+
+	OBJ_TYPE(LightOccluder2DEditor, HBoxContainer );
+
+	UndoRedo *undo_redo;
+	enum Mode {
+
+		MODE_CREATE,
+		MODE_EDIT,
+
+	};
+
+	Mode mode;
+
+	ToolButton *button_create;
+	ToolButton *button_edit;
+
+	CanvasItemEditor *canvas_item_editor;
+	EditorNode *editor;
+	Panel *panel;
+	LightOccluder2D *node;
+	MenuButton *options;
+
+	int edited_point;
+	Vector2 edited_point_pos;
+	Vector<Vector2> pre_move_edit;
+	Vector<Vector2> wip;
+	bool wip_active;
+
+	ConfirmationDialog *create_poly;
+
+	void _wip_close(bool p_closed);
+	void _canvas_draw();
+	void _menu_option(int p_option);
+	void _create_poly();
+
+protected:
+	void _notification(int p_what);
+	void _node_removed(Node *p_node);
+	static void _bind_methods();
+public:
+
+	Vector2 snap_point(const Vector2& p_point) const;
+	bool forward_input_event(const InputEvent& p_event);
+	void edit(Node *p_collision_polygon);
+	LightOccluder2DEditor(EditorNode *p_editor);
+};
+
+class LightOccluder2DEditorPlugin : public EditorPlugin {
+
+	OBJ_TYPE( LightOccluder2DEditorPlugin, EditorPlugin );
+
+	LightOccluder2DEditor *collision_polygon_editor;
+	EditorNode *editor;
+
+public:
+
+	virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); }
+
+	virtual String get_name() const { return "LightOccluder2D"; }
+	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);
+
+	LightOccluder2DEditorPlugin(EditorNode *p_node);
+	~LightOccluder2DEditorPlugin();
+
+};
+
+#endif // LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H

+ 37 - 3
tools/editor/property_editor.cpp

@@ -1857,8 +1857,33 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
 				} else {
 					p_item->set_text(1,"<"+res->get_type()+">");
 				};
+
+				if (has_icon(res->get_type(),"EditorIcons")) {
+
+					p_item->set_icon(1,get_icon(res->get_type(),"EditorIcons"));
+				} else {
+
+					Dictionary d = p_item->get_metadata(0);
+					int hint=d.has("hint")?d["hint"].operator int():-1;
+					String hint_text=d.has("hint_text")?d["hint_text"]:"";
+					if (hint==PROPERTY_HINT_RESOURCE_TYPE) {
+
+						if (has_icon(hint_text,"EditorIcons")) {
+
+							p_item->set_icon(1,get_icon(hint_text,"EditorIcons"));
+
+						} else {
+							p_item->set_icon(1,get_icon("Object","EditorIcons"));
+
+						}
+					}
+				}
+
+
+
 			}
 
+
 		} break;
 		default: {};
 	}
@@ -2529,7 +2554,10 @@ void PropertyEditor::update_tree() {
 				item->set_editable( 1, !read_only );
 				item->add_button(1,get_icon("EditResource","EditorIcons"));
 				String type;
+				if (p.hint==PROPERTY_HINT_RESOURCE_TYPE)
+					type=p.hint_string;
 				bool notnil=false;
+
 				if (obj->get( p.name ).get_type() == Variant::NIL || obj->get( p.name ).operator RefPtr().is_null()) {
 					item->set_text(1,"<null>");
 
@@ -2553,12 +2581,18 @@ void PropertyEditor::update_tree() {
 					};
 					notnil=true;
 
+					if (has_icon(res->get_type(),"EditorIcons")) {
+						type=res->get_type();
+					}
 				}
 
-				if (p.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+
+				if (type!=String()) {
+					if (type.find(",")!=-1)
+						type=type.get_slice(",",0);
 					//printf("prop %s , type %s\n",p.name.ascii().get_data(),p.hint_string.ascii().get_data());
-					if (has_icon(p.hint_string,"EditorIcons"))
-						item->set_icon( 0, get_icon(p.hint_string,"EditorIcons") );
+					if (has_icon(type,"EditorIcons"))
+						item->set_icon( 0, get_icon(type,"EditorIcons") );
 					else
 						item->set_icon( 0, get_icon("Object","EditorIcons") );
 				}