瀏覽代碼

Merge remote-tracking branch 'upstream/master' into x11-window-management

hurikhan 10 年之前
父節點
當前提交
87be945d49
共有 100 個文件被更改,包括 4540 次插入686 次删除
  1. 4 0
      SConstruct
  2. 10 0
      core/io/resource_format_binary.cpp
  3. 5 0
      core/io/resource_format_xml.cpp
  4. 54 2
      core/list.h
  5. 18 1
      core/math/camera_matrix.cpp
  6. 160 2
      core/math/math_2d.h
  7. 8 0
      core/object.cpp
  8. 1 0
      core/object.h
  9. 2 2
      core/variant_call.cpp
  10. 3 0
      core/variant_op.cpp
  11. 二進制
      demos/2d/navpoly/navigation2.scn
  12. 二進制
      demos/3d/kinematic_char/cubelib.res
  13. 二進制
      demos/3d/kinematic_char/level.scn
  14. 2 1
      doc/base/classes.xml
  15. 0 1
      drivers/SCsub
  16. 803 70
      drivers/gles2/rasterizer_gles2.cpp
  17. 69 3
      drivers/gles2/rasterizer_gles2.h
  18. 6 1
      drivers/gles2/shader_compiler_gles2.cpp
  19. 1 0
      drivers/gles2/shaders/SCsub
  20. 161 16
      drivers/gles2/shaders/canvas.glsl
  21. 62 0
      drivers/gles2/shaders/canvas_shadow.glsl
  22. 17 3
      drivers/windows/file_access_windows.cpp
  23. 8 0
      methods.py
  24. 4 1
      modules/gdscript/gd_script.cpp
  25. 5 2
      modules/gdscript/gd_tokenizer.cpp
  26. 2 1
      modules/gridmap/grid_map.cpp
  27. 2 1
      platform/android/AndroidManifest.xml.template
  28. 2 0
      platform/android/SCsub
  29. 8 0
      platform/android/audio_driver_opensl.cpp
  30. 88 25
      platform/android/java_glue.cpp
  31. 1 1
      platform/android/os_android.cpp
  32. 1 9
      platform/bb10/SCsub
  33. 9 21
      platform/bb10/bar/bar-descriptor.xml
  34. 0 2
      platform/bb10/detect.py
  35. 33 46
      platform/bb10/export/export.cpp
  36. 1 1
      platform/bb10/os_bb10.cpp
  37. 2 0
      platform/iphone/gl_view.h
  38. 52 0
      platform/iphone/gl_view.mm
  39. 1 1
      platform/osx/os_osx.mm
  40. 2 2
      platform/windows/detect.py
  41. 8 3
      platform/windows/os_windows.cpp
  42. 2 3
      platform/winrt/os_winrt.cpp
  43. 11 0
      scene/2d/camera_2d.cpp
  44. 95 94
      scene/2d/camera_2d.h
  45. 226 106
      scene/2d/canvas_item.cpp
  46. 47 20
      scene/2d/canvas_item.h
  47. 46 0
      scene/2d/canvas_modulate.cpp
  48. 23 0
      scene/2d/canvas_modulate.h
  49. 300 0
      scene/2d/light_2d.cpp
  50. 86 0
      scene/2d/light_2d.h
  51. 201 0
      scene/2d/light_occluder_2d.cpp
  52. 73 0
      scene/2d/light_occluder_2d.h
  53. 38 1
      scene/2d/navigation2d.cpp
  54. 1 0
      scene/2d/navigation2d.h
  55. 37 19
      scene/2d/tile_map.cpp
  56. 3 1
      scene/2d/tile_map.h
  57. 3 3
      scene/3d/camera.cpp
  58. 15 0
      scene/3d/visual_instance.cpp
  59. 4 0
      scene/3d/visual_instance.h
  60. 2 0
      scene/gui/control.cpp
  61. 1 1
      scene/gui/popup_menu.h
  62. 24 0
      scene/main/viewport.cpp
  63. 5 0
      scene/main/viewport.h
  64. 8 0
      scene/register_scene_types.cpp
  65. 30 29
      scene/resources/texture.cpp
  66. 12 13
      scene/resources/texture.h
  67. 1 0
      scene/scene_string_names.cpp
  68. 1 0
      scene/scene_string_names.h
  69. 109 9
      servers/visual/rasterizer.h
  70. 1 1
      servers/visual/rasterizer_dummy.cpp
  71. 1 1
      servers/visual/rasterizer_dummy.h
  72. 3 1
      servers/visual/shader_language.cpp
  73. 554 61
      servers/visual/visual_server_raster.cpp
  74. 69 33
      servers/visual/visual_server_raster.h
  75. 32 14
      servers/visual/visual_server_wrap_mt.h
  76. 4 2
      servers/visual_server.cpp
  77. 36 22
      servers/visual_server.h
  78. 1 1
      tools/collada/collada.cpp
  79. 18 0
      tools/collada/collada.h
  80. 28 2
      tools/editor/editor_import_export.cpp
  81. 2 1
      tools/editor/editor_import_export.h
  82. 2 0
      tools/editor/editor_node.cpp
  83. 二進制
      tools/editor/icons/icon_canvas_item_material.png
  84. 二進制
      tools/editor/icons/icon_canvas_modulate.png
  85. 二進制
      tools/editor/icons/icon_light_2d.png
  86. 二進制
      tools/editor/icons/icon_light_occluder_2d.png
  87. 二進制
      tools/editor/icons/icon_occluder_polygon_2d.png
  88. 二進制
      tools/editor/icons/icon_rotate_0.png
  89. 二進制
      tools/editor/icons/icon_rotate_180.png
  90. 二進制
      tools/editor/icons/icon_rotate_270.png
  91. 二進制
      tools/editor/icons/icon_rotate_90.png
  92. 二進制
      tools/editor/icons/icon_transpose.png
  93. 7 4
      tools/editor/io_plugins/editor_import_collada.cpp
  94. 1 0
      tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp
  95. 500 0
      tools/editor/plugins/light_occluder_2d_editor_plugin.cpp
  96. 87 0
      tools/editor/plugins/light_occluder_2d_editor_plugin.h
  97. 127 19
      tools/editor/plugins/tile_map_editor_plugin.cpp
  98. 10 3
      tools/editor/plugins/tile_map_editor_plugin.h
  99. 37 3
      tools/editor/property_editor.cpp
  100. 1 1
      tools/editor/scene_tree_dock.cpp

+ 4 - 0
SConstruct

@@ -67,12 +67,16 @@ env_base.android_source_modules=[]
 env_base.android_source_files=[]
 env_base.android_module_libraries=[]
 env_base.android_manifest_chunk=""
+env_base.android_permission_chunk=""
+env_base.android_appattributes_chunk=""
 env_base.disabled_modules=[]
 
 env_base.__class__.android_module_source = methods.android_module_source
 env_base.__class__.android_module_library = methods.android_module_library
 env_base.__class__.android_module_file = methods.android_module_file
 env_base.__class__.android_module_manifest = methods.android_module_manifest
+env_base.__class__.android_module_permission = methods.android_module_permission
+env_base.__class__.android_module_attribute = methods.android_module_attribute
 env_base.__class__.disable_module = methods.disable_module
 
 env_base.__class__.add_source_files = methods.add_source_files

+ 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);
 

+ 54 - 2
core/list.h

@@ -30,7 +30,7 @@
 #define GLOBALS_LIST_H
 
 #include "os/memory.h"
-
+#include "sort.h"
 
 /**
  * Generic Templatized Linked List Implementation.
@@ -551,7 +551,7 @@ public:
 	}
 			
 	template<class C>
-	void sort_custom() {
+	void sort_custom_inplace() {
 
 		if(size()<2)
 			return;
@@ -603,6 +603,58 @@ public:
 		_data->last=to;
 	}
 
+	template<class C>
+	struct AuxiliaryComparator {
+
+		C compare;
+		_FORCE_INLINE_ bool operator()(const Element *a,const Element* b) const {
+
+			return compare(a->value,b->value);
+		}
+	};
+
+	template<class C>
+	void sort_custom() {
+
+		//this version uses auxiliary memory for speed.
+		//if you don't want to use auxiliary memory, use the in_place version
+
+		int s = size();
+		if(s<2)
+			return;
+
+
+		Element **aux_buffer = memnew_arr(Element*,s);
+
+		int idx=0;
+		for(Element *E=front();E;E=E->next_ptr) {
+
+			aux_buffer[idx]=E;
+			idx++;
+		}
+
+		SortArray<Element*,AuxiliaryComparator<C> > sort;
+		sort.sort(aux_buffer,s);
+
+		_data->first=aux_buffer[0];
+		aux_buffer[0]->prev_ptr=NULL;
+		aux_buffer[0]->next_ptr=aux_buffer[1];
+
+		_data->last=aux_buffer[s-1];
+		aux_buffer[s-1]->prev_ptr=aux_buffer[s-2];
+		aux_buffer[s-1]->next_ptr=NULL;
+
+		for(int i=1;i<s-1;i++) {
+
+			aux_buffer[i]->prev_ptr=aux_buffer[i-1];
+			aux_buffer[i]->next_ptr=aux_buffer[i+1];
+
+		}
+
+		memdelete_arr(aux_buffer);
+	}
+
+
 	/**
 	 * copy constructor for the list
 	 */

+ 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;			

+ 160 - 2
core/math/math_2d.h

@@ -159,8 +159,8 @@ struct Vector2 {
 	
 	operator String() const { return String::num(x)+","+String::num(y); }
 	
-	inline Vector2(float p_x,float p_y) { x=p_x; y=p_y; }
-	inline Vector2() { x=0; y=0; }
+	_FORCE_INLINE_ Vector2(float p_x,float p_y) { x=p_x; y=p_y; }
+	_FORCE_INLINE_ Vector2() { x=0; y=0; }
 };
 
 _FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2& p_vec) const {
@@ -198,6 +198,8 @@ Vector2 Vector2::linear_interpolate(const Vector2& p_a, const Vector2& p_b,float
 typedef Vector2 Size2;
 typedef Vector2 Point2;
 
+struct Matrix32;
+
 
 struct Rect2 {
 	
@@ -224,6 +226,8 @@ struct Rect2 {
 		return true;
 	}
 
+	_FORCE_INLINE_ bool intersects_transformed(const Matrix32& p_xform, const Rect2& p_rect) const;
+
 	bool intersects_segment(const Point2& p_from, const Point2& p_to, Point2* r_pos=NULL, Point2* r_normal=NULL) const;
 
 	inline bool encloses(const Rect2& p_rect) const {
@@ -597,6 +601,160 @@ struct Matrix32 {
 
 };
 
+bool Rect2::intersects_transformed(const Matrix32& p_xform, const Rect2& p_rect) const {
+
+	//SAT intersection between local and transformed rect2
+
+	Vector2 xf_points[4]={
+		p_xform.xform(p_rect.pos),
+		p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y)),
+		p_xform.xform(Vector2(p_rect.pos.x,p_rect.pos.y+p_rect.size.y)),
+		p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y+p_rect.size.y)),
+	};
+
+	real_t low_limit;
+
+	//base rect2 first (faster)
+
+	if (xf_points[0].y>pos.y)
+		goto next1;
+	if (xf_points[1].y>pos.y)
+		goto next1;
+	if (xf_points[2].y>pos.y)
+		goto next1;
+	if (xf_points[3].y>pos.y)
+		goto next1;
+
+	return false;
+
+	next1:
+
+	low_limit=pos.y+size.y;
+
+	if (xf_points[0].y<low_limit)
+		goto next2;
+	if (xf_points[1].y<low_limit)
+		goto next2;
+	if (xf_points[2].y<low_limit)
+		goto next2;
+	if (xf_points[3].y<low_limit)
+		goto next2;
+
+	return false;
+
+	next2:
+
+	if (xf_points[0].x>pos.x)
+		goto next3;
+	if (xf_points[1].x>pos.x)
+		goto next3;
+	if (xf_points[2].x>pos.x)
+		goto next3;
+	if (xf_points[3].x>pos.x)
+		goto next3;
+
+	return false;
+
+	next3:
+
+	low_limit=pos.x+size.x;
+
+	if (xf_points[0].x<low_limit)
+		goto next4;
+	if (xf_points[1].x<low_limit)
+		goto next4;
+	if (xf_points[2].x<low_limit)
+		goto next4;
+	if (xf_points[3].x<low_limit)
+		goto next4;
+
+	return false;
+
+	next4:
+
+	Vector2 xf_points2[4]={
+		pos,
+		Vector2(pos.x+size.x,pos.y),
+		Vector2(pos.x,pos.y+size.y),
+		Vector2(pos.x+size.x,pos.y+size.y),
+	};
+
+	real_t maxa=p_xform.elements[0].dot(xf_points2[0]);
+	real_t mina=maxa;
+
+	real_t dp = p_xform.elements[0].dot(xf_points2[1]);
+	maxa=MAX(dp,maxa);
+	mina=MIN(dp,mina);
+
+	dp = p_xform.elements[0].dot(xf_points2[2]);
+	maxa=MAX(dp,maxa);
+	mina=MIN(dp,mina);
+
+	dp = p_xform.elements[0].dot(xf_points2[3]);
+	maxa=MAX(dp,maxa);
+	mina=MIN(dp,mina);
+
+	real_t maxb=p_xform.elements[0].dot(xf_points[0]);
+	real_t minb=maxb;
+
+	dp = p_xform.elements[0].dot(xf_points[1]);
+	maxb=MAX(dp,maxb);
+	minb=MIN(dp,minb);
+
+	dp = p_xform.elements[0].dot(xf_points[2]);
+	maxb=MAX(dp,maxb);
+	minb=MIN(dp,minb);
+
+	dp = p_xform.elements[0].dot(xf_points[3]);
+	maxb=MAX(dp,maxb);
+	minb=MIN(dp,minb);
+
+
+	if ( mina > maxb )
+		return false;
+	if ( minb > maxa  )
+		return false;
+
+	maxa=p_xform.elements[1].dot(xf_points2[0]);
+	mina=maxa;
+
+	dp = p_xform.elements[1].dot(xf_points2[1]);
+	maxa=MAX(dp,maxa);
+	mina=MIN(dp,mina);
+
+	dp = p_xform.elements[1].dot(xf_points2[2]);
+	maxa=MAX(dp,maxa);
+	mina=MIN(dp,mina);
+
+	dp = p_xform.elements[1].dot(xf_points2[3]);
+	maxa=MAX(dp,maxa);
+	mina=MIN(dp,mina);
+
+	maxb=p_xform.elements[1].dot(xf_points[0]);
+	minb=maxb;
+
+	dp = p_xform.elements[1].dot(xf_points[1]);
+	maxb=MAX(dp,maxb);
+	minb=MIN(dp,minb);
+
+	dp = p_xform.elements[1].dot(xf_points[2]);
+	maxb=MAX(dp,maxb);
+	minb=MIN(dp,minb);
+
+	dp = p_xform.elements[1].dot(xf_points[3]);
+	maxb=MAX(dp,maxb);
+	minb=MIN(dp,minb);
+
+
+	if ( mina > maxb )
+		return false;
+	if ( minb > maxa  )
+		return false;
+
+
+	return true;
+
+}
 
 Vector2 Matrix32::basis_xform(const Vector2& v) const {
 

+ 8 - 0
core/object.cpp

@@ -1033,6 +1033,13 @@ void Object::add_user_signal(const MethodInfo& p_signal) {
 	signal_map[p_signal.name]=s;
 }
 
+bool Object::_has_user_signal(const StringName& p_name) const {
+
+	if (!signal_map.has(p_name))
+		return false;
+	return signal_map[p_name].user.name.length()>0;
+}
+
 struct _ObjectSignalDisconnectData {
 
 	StringName signal;
@@ -1431,6 +1438,7 @@ void Object::_bind_methods() {
 //	ObjectTypeDB::bind_method(_MD("call_deferred","method","arg1","arg2","arg3","arg4"),&Object::_call_deferred_bind,DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()));
 
 	ObjectTypeDB::bind_method(_MD("add_user_signal","signal","arguments"),&Object::_add_user_signal,DEFVAL(Array()));
+	ObjectTypeDB::bind_method(_MD("has_user_signal","signal"),&Object::_has_user_signal);
 //	ObjectTypeDB::bind_method(_MD("emit_signal","signal","arguments"),&Object::_emit_signal,DEFVAL(Array()));
 
 

+ 1 - 0
core/object.h

@@ -386,6 +386,7 @@ friend void postinitialize_handler(Object*);
 	Dictionary metadata;
 
 	void _add_user_signal(const String& p_name, const Array& p_pargs=Array());
+	bool _has_user_signal(const StringName& p_name) const;
 	Variant _emit_signal(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
 	Array _get_signal_list() const;
 	Array _get_signal_connection_list(const String& p_signal) const;

+ 2 - 2
core/variant_call.cpp

@@ -1263,8 +1263,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
 	ADDFUNC1(VECTOR2,VECTOR2,Vector2,snapped,VECTOR2,"by",varray());
 	ADDFUNC0(VECTOR2,REAL,Vector2,get_aspect,varray());
 	ADDFUNC1(VECTOR2,REAL,Vector2,dot,VECTOR2,"with",varray());
-	ADDFUNC1(VECTOR2,REAL,Vector2,slide,VECTOR2,"vec",varray());
-	ADDFUNC1(VECTOR2,REAL,Vector2,reflect,VECTOR2,"vec",varray());
+	ADDFUNC1(VECTOR2,VECTOR2,Vector2,slide,VECTOR2,"vec",varray());
+	ADDFUNC1(VECTOR2,VECTOR2,Vector2,reflect,VECTOR2,"vec",varray());
 	//ADDFUNC1(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray());
 
 	ADDFUNC0(RECT2,REAL,Rect2,get_area,varray());

+ 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/2d/navpoly/navigation2.scn


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


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


+ 2 - 1
doc/base/classes.xml

@@ -18902,7 +18902,8 @@
 			collider_id: collider id of the object agaisnt which the ray was stopped[br]
 			collider: collider object agaisnt which the ray was stopped[br]
 			rid:  [RID] of the object agaisnt which the ray was stopped[br]
-			If the ray did not intersect anything, then null is returned instead of a [Dictionary].
+			If the ray did not intersect anything, then an empty
+			dictionary (dir.empty()==true) is returned instead.
 			</description>
 		</method>
 		<method name="intersect_shape"  >

+ 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');
 

File diff suppressed because it is too large
+ 803 - 70
drivers/gles2/rasterizer_gles2.cpp


+ 69 - 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;
@@ -1127,6 +1129,7 @@ class RasterizerGLES2 : public Rasterizer {
 		bool active;
 
 		int blur_size;
+
 		struct Blur {
 
 			GLuint fbo;
@@ -1159,6 +1162,7 @@ class RasterizerGLES2 : public Rasterizer {
 	void _process_glow_and_bloom();
 	//void _update_blur_buffer();
 
+
 	/*********/
 	/* FRAME */
 	/*********/
@@ -1177,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;
@@ -1186,11 +1229,15 @@ class RasterizerGLES2 : public Rasterizer {
 	GLuint white_tex;
 	RID canvas_tex;
 	float canvas_opacity;
+	Color canvas_modulate;
+	bool canvas_use_modulate;
 	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);
 
 
 	_FORCE_INLINE_ Texture* _bind_canvas_texture(const RID& p_texture);
@@ -1222,17 +1269,19 @@ 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;
 
 	void _draw_primitive(int p_points, const Vector3 *p_vertices, const Vector3 *p_normals, const Color* p_colors, const Vector3 *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1);
 	_FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs);
 	_FORCE_INLINE_ void _draw_gui_primitive2(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs, const Vector2 *p_uvs2);
-	void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false );
+	void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false, bool p_transpose=false );
 	void _draw_quad(const Rect2& p_rect);
 	void _copy_screen_quad();
 	void _copy_to_texscreen();
@@ -1247,6 +1296,10 @@ class RasterizerGLES2 : public Rasterizer {
 	GLuint tc0_id_cache;
 	GLuint tc0_idx;
 
+	template<bool use_normalmap>
+	_FORCE_INLINE_ void _canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip);
+	_FORCE_INLINE_ void _canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* p_shader);
+	_FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* p_shader);
 public:
 
 	/* TEXTURE API */
@@ -1562,7 +1615,18 @@ public:
 	virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor);
 	virtual void canvas_set_transform(const Matrix32& p_transform);
 
-	virtual void canvas_render_items(CanvasItem *p_item_list);
+	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 */
 
@@ -1601,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();

+ 6 - 1
drivers/gles2/shader_compiler_gles2.cpp

@@ -261,6 +261,11 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
 					uses_light=true;
 				}
 
+				if (vnode->name==vname_normal) {
+					uses_normal=true;
+				}
+
+
 			}
 
 			if (vnode->name==vname_time) {
@@ -636,7 +641,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	r_flags.uses_light=uses_light;
 	r_flags.uses_time=uses_time;
 	r_flags.uses_normalmap=uses_normalmap;
-	r_flags.uses_normal=uses_normalmap;
+	r_flags.uses_normal=uses_normal;
 	r_flags.uses_texpixel_size=uses_texpixel_size;
 	r_flags.uses_worldvec=uses_worldvec;
 	r_code_line=code;

+ 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');
 

+ 161 - 16
drivers/gles2/shaders/canvas.glsl

@@ -26,7 +26,17 @@ uniform float time;
 #ifdef USE_LIGHTING
 
 uniform highp mat4 light_matrix;
-varying vec4 light_tex_pos;
+uniform vec2 light_pos;
+varying vec4 light_uv_interp;
+
+#if defined(NORMAL_USED)
+varying vec4 local_rot;
+uniform vec2 normal_flip;
+#endif
+
+#ifdef USE_SHADOWS
+highp varying vec2 pos;
+#endif
 
 #endif
 
@@ -57,6 +67,8 @@ VERTEX_SHADER_CODE
         outvec = modelview_matrix * outvec;
 #endif
 
+
+
 #ifdef USE_PIXEL_SNAP
 
 	outvec.xy=floor(outvec.xy+0.5);
@@ -67,8 +79,16 @@ VERTEX_SHADER_CODE
 
 #ifdef USE_LIGHTING
 
-	light_tex_pos.xy = light_matrix * gl_Position;
-	light_tex_pos.zw=outvec.xy - light_matrix[4].xy; //likely wrong
+	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;
+	local_rot.zw=normalize( (modelview_matrix * ( extra_matrix * vec4(0.0,1.0,0.0,0.0) )).xy  )*normal_flip.y;
+#endif
 
 #endif
 
@@ -121,17 +141,37 @@ varying vec4 var2_interp;
 uniform float time;
 #endif
 
+#ifdef USE_MODULATE
+
+uniform vec4 modulate;
+
+#endif
 
 #ifdef USE_LIGHTING
 
 uniform sampler2D light_texture;
-varying vec4 light_tex_pos;
+uniform vec4 light_color;
+uniform float light_height;
+varying vec4 light_uv_interp;
+
+#if defined(NORMAL_USED)
+varying vec4 local_rot;
+#endif
 
 #ifdef USE_SHADOWS
 
 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
@@ -151,6 +191,7 @@ void main() {
 	vec3 normal = vec3(0,0,1);
 #endif
 
+
 	color *= texture2D( texture,  uv_interp );
 #if defined(ENABLE_SCREEN_UV)
 	vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult;
@@ -164,37 +205,141 @@ FRAGMENT_SHADER_CODE
 	color = vec4(vec3(enc32),1.0);
 #endif
 
+#ifdef USE_MODULATE
+
+	color*=modulate;
+#endif
+
+
 #ifdef USE_LIGHTING
 
+#if defined(NORMAL_USED)
+	normal.xy =  mat2(local_rot.xy,local_rot.zw) * normal.xy;
+#endif
+
 	float att=1.0;
 
-	vec3 light = texture2D(light_texture,light_tex_pos).rgb;
+	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
 
 #if defined(USE_LIGHT_SHADER_CODE)
 //light is written by the light shader
 {
-	vec2 light_dir = normalize(light_tex_pos.zw);
-	float light_distance = length(light_tex_pos.zw);
+	vec2 light_dir = normalize(light_uv_interp.zw);
+	float light_distance = length(light_uv_interp.zw);
 LIGHT_SHADER_CODE
 }
+
 #else
 
 #if defined(NORMAL_USED)
-	vec2 light_normal = normalize(light_tex_pos.zw);
-	light = color.rgb * light * max(dot(light_normal,normal),0);
+	vec3 light_normal = normalize(vec3(light_uv_interp.zw,-light_height));
+	light*=max(dot(-light_normal,normal),0);
 #endif
 
-	color.rgb=light;
+	color*=light;
+/*
+#ifdef USE_NORMAL
+	color.xy=local_rot.xy;//normal.xy;
+	color.zw=vec2(0.0,1.0);
+#endif
+*/
+	if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) {
+		color.a=0.0; //invisible
+	}
+
 //light shader code
 #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 );
 	}
 
 

+ 8 - 0
methods.py

@@ -1291,6 +1291,14 @@ def android_module_manifest(self,file):
 	base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file
 	f = open(base_path,"rb")
 	self.android_manifest_chunk+=f.read()
+def android_module_permission(self,file):
+	base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file
+	f = open(base_path,"rb")
+	self.android_permission_chunk+=f.read()
+def android_module_attribute(self,file):
+	base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file
+	f = open(base_path,"rb")
+	self.android_appattributes_chunk+=f.read()
 
 def disable_module(self):
 	self.disabled_modules.append(self.current_module)

+ 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;

+ 5 - 2
modules/gdscript/gd_tokenizer.cpp

@@ -538,9 +538,12 @@ void GDTokenizerText::_advance() {
 				is_node_path=true;
 				
 			case '\'':
-				string_mode=STRING_SINGLE_QUOTE;
 			case '"': {
-
+	
+				if (GETCHAR(0)=='\'')
+					string_mode=STRING_SINGLE_QUOTE;
+																	
+																	
 				int i=1;
 				if (string_mode==STRING_DOUBLE_QUOTE && GETCHAR(i)=='"' && GETCHAR(i+1)=='"') {
 					i+=2;

+ 2 - 1
modules/gridmap/grid_map.cpp

@@ -122,7 +122,7 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
 				Octant &g = *octant_map[ok];
 
 				g.baked=b;
-				g.bake_instance=VS::get_singleton()->instance_create();;
+				g.bake_instance=VS::get_singleton()->instance_create();;				
 				VS::get_singleton()->instance_set_base(g.bake_instance,g.baked->get_rid());
 				VS::get_singleton()->instance_geometry_set_baked_light(g.bake_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID());
 			}
@@ -418,6 +418,7 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){
 		Octant *g = memnew( Octant );
 		g->dirty=true;
 		g->static_body = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC);
+		PhysicsServer::get_singleton()->body_attach_object_instance_ID(g->static_body,get_instance_ID());
 		if (is_inside_world())
 			PhysicsServer::get_singleton()->body_set_space(g->static_body,get_world()->get_space());
 

+ 2 - 1
platform/android/AndroidManifest.xml.template

@@ -10,7 +10,7 @@
                       android:largeScreens="true"
                       android:xlargeScreens="true"/>
 
-    <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon" android:allowBackup="false">
+    <application android:label="@string/godot_project_name_string" android:icon="@drawable/icon" android:allowBackup="false" $$ADD_APPATTRIBUTE_CHUNKS$$ >
         <activity android:name="com.android.godot.Godot"
                   android:label="@string/godot_project_name_string"
                   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@@ -33,6 +33,7 @@ $$ADD_APPLICATION_CHUNKS$$
     </application>
     <uses-feature android:glEsVersion="0x00020000"/>
 
+$$ADD_PERMISSION_CHUNKS$$
 <uses-permission android:name="godot.ACCESS_CHECKIN_PROPERTIES"/>
 <uses-permission android:name="godot.ACCESS_COARSE_LOCATION"/>
 <uses-permission android:name="godot.ACCESS_FINE_LOCATION"/>

+ 2 - 0
platform/android/SCsub

@@ -56,6 +56,8 @@ pp_basein = open(abspath+"/AndroidManifest.xml.template","rb")
 pp_baseout = open(abspath+"/java/AndroidManifest.xml","wb")
 manifest = pp_basein.read()
 manifest = manifest.replace("$$ADD_APPLICATION_CHUNKS$$",env.android_manifest_chunk)
+manifest = manifest.replace("$$ADD_PERMISSION_CHUNKS$$",env.android_permission_chunk)
+manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$",env.android_appattributes_chunk)
 pp_baseout.write( manifest )
 
 

+ 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);
+		}
+	}
 }
 
 

+ 88 - 25
platform/android/java_glue.cpp

@@ -45,9 +45,18 @@ static JavaClassWrapper *java_class_wrapper=NULL;
 static OS_Android *os_android=NULL;
 
 
-jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_arg, bool force_jobject = false) {
+struct jvalret {
 
-	jvalue v;
+	jobject obj;
+	jvalue val;
+	jvalret() { obj=NULL; }
+
+
+};
+
+jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_arg, bool force_jobject = false) {
+
+	jvalret v;
 
 	switch(p_type) {
 
@@ -59,9 +68,12 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
 				jvalue val;
 				val.z = (bool)(*p_arg);
 				jobject obj = env->NewObjectA(bclass, ctor, &val);
-				v.l = obj;
+				v.val.l = obj;
+				v.obj=obj;
+				env->DeleteLocalRef(bclass);
 			} else {
-				v.z=*p_arg;
+				v.val.z=*p_arg;
+
 			};
 		} break;
 		case Variant::INT: {
@@ -73,10 +85,13 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
 				jvalue val;
 				val.i = (int)(*p_arg);
 				jobject obj = env->NewObjectA(bclass, ctor, &val);
-				v.l = obj;
+				v.val.l = obj;
+				v.obj=obj;
+				env->DeleteLocalRef(bclass);
 
 			} else {
-				v.i=*p_arg;
+				v.val.i=*p_arg;
+
 			};
 		} break;
 		case Variant::REAL: {
@@ -88,17 +103,20 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
 				jvalue val;
 				val.d = (double)(*p_arg);
 				jobject obj = env->NewObjectA(bclass, ctor, &val);
-				v.l = obj;
+				v.val.l = obj;
+				v.obj=obj;
+				env->DeleteLocalRef(bclass);
 
 			} else {
-				v.f=*p_arg;
+				v.val.f=*p_arg;
 			};
 		} break;
 		case Variant::STRING: {
 
 			String s = *p_arg;
 			jstring jStr = env->NewStringUTF(s.utf8().get_data());
-			v.l=jStr;
+			v.val.l=jStr;
+			v.obj=jStr;
 		} break;
 		case Variant::STRING_ARRAY: {
 
@@ -107,9 +125,12 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
 
 			for(int j=0;j<sarray.size();j++) {
 
-				env->SetObjectArrayElement(arr,j,env->NewStringUTF( sarray[j].utf8().get_data() ));
+				jstring str = env->NewStringUTF( sarray[j].utf8().get_data() );
+				env->SetObjectArrayElement(arr,j,str);
+				env->DeleteLocalRef(str);
 			}
-			v.l=arr;
+			v.val.l=arr;
+			v.obj=arr;
 
 		} break;
 
@@ -124,27 +145,36 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
 
 			jobjectArray jkeys = env->NewObjectArray(keys.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
 			for (int j=0; j<keys.size(); j++) {
-				env->SetObjectArrayElement(jkeys, j, env->NewStringUTF(String(keys[j]).utf8().get_data()));
+				jstring str = env->NewStringUTF(String(keys[j]).utf8().get_data());
+				env->SetObjectArrayElement(jkeys, j, str);
+				env->DeleteLocalRef(str);
 			};
 
 			jmethodID set_keys = env->GetMethodID(dclass, "set_keys", "([Ljava/lang/String;)V");
 			jvalue val;
 			val.l = jkeys;
 			env->CallVoidMethodA(jdict, set_keys, &val);
+			env->DeleteLocalRef(jkeys);
 
 			jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), NULL);
 
 			for (int j=0; j<keys.size(); j++) {
 				Variant var = dict[keys[j]];
-				val = _variant_to_jvalue(env, var.get_type(), &var, true);
-				env->SetObjectArrayElement(jvalues, j, val.l);
+				jvalret v = _variant_to_jvalue(env, var.get_type(), &var, true);
+				env->SetObjectArrayElement(jvalues, j, v.val.l);
+				if (v.obj) {
+					env->DeleteLocalRef(v.obj);
+				}
 			};
 
 			jmethodID set_values = env->GetMethodID(dclass, "set_values", "([Ljava/lang/Object;)V");
 			val.l = jvalues;
 			env->CallVoidMethodA(jdict, set_values, &val);
+			env->DeleteLocalRef(jvalues);
+			env->DeleteLocalRef(dclass);
 
-			v.l = jdict;
+			v.val.l = jdict;
+			v.obj=jdict;
 		} break;
 
 		case Variant::INT_ARRAY: {
@@ -153,7 +183,8 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
 			jintArray arr = env->NewIntArray(array.size());
 			DVector<int>::Read r = array.read();
 			env->SetIntArrayRegion(arr,0,array.size(),r.ptr());
-			v.l=arr;
+			v.val.l=arr;
+			v.obj=arr;
 
 		} break;
 		case Variant::RAW_ARRAY: {
@@ -161,7 +192,8 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
 			jbyteArray arr = env->NewByteArray(array.size());
 			DVector<uint8_t>::Read r = array.read();
 			env->SetByteArrayRegion(arr,0,array.size(),reinterpret_cast<const signed char*>(r.ptr()));
-			v.l=arr;
+			v.val.l=arr;
+			v.obj=arr;
 
 		} break;
 		case Variant::REAL_ARRAY: {
@@ -170,12 +202,13 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar
 			jfloatArray arr = env->NewFloatArray(array.size());
 			DVector<float>::Read r = array.read();
 			env->SetFloatArrayRegion(arr,0,array.size(),r.ptr());
-			v.l=arr;
+			v.val.l=arr;
+			v.obj=arr;
 
 		} break;
 		default: {
 
-			v.i = 0;
+			v.val.i = 0;
 		} break;
 
 	}
@@ -193,8 +226,11 @@ String _get_class_name(JNIEnv * env, jclass cls, bool* array) {
 		jboolean isarr = env->CallBooleanMethod(cls, isArray);
 		(*array) = isarr ? true : false;
 	}
+	String name = env->GetStringUTFChars( clsName, NULL );
+	env->DeleteLocalRef(clsName);
+
+	return name;
 
-	return env->GetStringUTFChars( clsName, NULL );
 };
 
 
@@ -223,6 +259,8 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
 			jstring string = (jstring) env->GetObjectArrayElement(arr, i);
 			const char *rawString = env->GetStringUTFChars(string, 0);
 			sarr.push_back(String(rawString));
+			env->DeleteLocalRef(string);
+
 		}
 
 		return sarr;
@@ -321,30 +359,34 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
 
 		jobjectArray arr = (jobjectArray)obj;
 		int objCount = env->GetArrayLength(arr);
-		Array varr;
+		Array varr(true);
 
 		for (int i=0; i<objCount; i++) {
 			jobject jobj = env->GetObjectArrayElement(arr, i);
 			Variant v = _jobject_to_variant(env, jobj);
 			varr.push_back(v);
+			env->DeleteLocalRef(jobj);
+
 		}
 
 		return varr;
 	};
 
-	if (name == "com.android.godot.Dictionary") {
+    if (name == "java.util.HashMap" || name == "com.android.godot.Dictionary") {
 
-		Dictionary ret;
+		Dictionary ret(true);
 		jclass oclass = c;
 		jmethodID get_keys = env->GetMethodID(oclass, "get_keys", "()[Ljava/lang/String;");
 		jobjectArray arr = (jobjectArray)env->CallObjectMethod(obj, get_keys);
 
 		StringArray keys = _jobject_to_variant(env, arr);
+		env->DeleteLocalRef(arr);
 
 		jmethodID get_values = env->GetMethodID(oclass, "get_values", "()[Ljava/lang/Object;");
 		arr = (jobjectArray)env->CallObjectMethod(obj, get_values);
 
 		Array vals = _jobject_to_variant(env, arr);
+		env->DeleteLocalRef(arr);
 
 		//print_line("adding " + String::num(keys.size()) + " to Dictionary!");
 		for (int i=0; i<keys.size(); i++) {
@@ -352,9 +394,12 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
 			ret[keys[i]] = vals[i];
 		};
 
+
 		return ret;
 	};
 
+	env->DeleteLocalRef(c);
+
 	return Variant();
 };
 
@@ -432,9 +477,13 @@ public:
 		JNIEnv *env = ThreadAndroid::get_env();
 
 		//print_line("argcount "+String::num(p_argcount));
+		List<jobject> to_erase;
 		for(int i=0;i<p_argcount;i++) {
 
-			v[i] = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+			jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+			v[i] = vr.val;
+			if (vr.obj)
+				to_erase.push_back(vr.obj);
 		}
 
 		//print_line("calling method!!");
@@ -468,6 +517,7 @@ public:
 				jobject o = env->CallObjectMethodA(instance,E->get().method,v);
 				String str = env->GetStringUTFChars((jstring)o, NULL );
 				ret=str;
+				env->DeleteLocalRef(o);
 			} break;
 			case Variant::STRING_ARRAY: {
 
@@ -475,6 +525,7 @@ public:
 
 				ret = _jobject_to_variant(env, arr);
 
+				env->DeleteLocalRef(arr);
 			} break;
 			case Variant::INT_ARRAY: {
 
@@ -488,6 +539,7 @@ public:
 				env->GetIntArrayRegion(arr,0,fCount,w.ptr());
 				w = DVector<int>::Write();
 				ret=sarr;
+				env->DeleteLocalRef(arr);
 			} break;
 			case Variant::REAL_ARRAY: {
 
@@ -501,6 +553,7 @@ public:
 				env->GetFloatArrayRegion(arr,0,fCount,w.ptr());
 				w = DVector<float>::Write();
 				ret=sarr;
+				env->DeleteLocalRef(arr);
 			} break;
 
 			case Variant::DICTIONARY: {
@@ -508,6 +561,7 @@ public:
 				//print_line("call dictionary");
 				jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
 				ret = _jobject_to_variant(env, obj);
+				env->DeleteLocalRef(obj);
 
 			} break;
 			default: {
@@ -518,6 +572,10 @@ public:
 			} break;
 		}
 
+		while (to_erase.size()) {
+			env->DeleteLocalRef(to_erase.front()->get());
+			to_erase.pop_front();
+		}
 		//print_line("success");
 
 		return ret;
@@ -872,6 +930,7 @@ static void _initialize_java_modules() {
 
 	String modules = Globals::get_singleton()->get("android/modules");
 	Vector<String> mods = modules.split(",",false);
+    print_line("ANDROID MODULES : " + modules);
 	__android_log_print(ANDROID_LOG_INFO,"godot","mod count: %i",mods.size());
 
 	if (mods.size()) {
@@ -1571,6 +1630,8 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env,
 		memnew_placement(&vlist[i], Variant);
 		vlist[i] = v;
 		vptr[i] = &vlist[i];
+		env->DeleteLocalRef(obj);
+
 	};
 
 	Variant::CallError err;
@@ -1588,13 +1649,15 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env
 	int count = env->GetArrayLength(params);
 	Variant args[VARIANT_ARG_MAX];
 
-//	print_line("Java->GD call: "+obj->get_type()+"::"+str_method+" argc "+itos(count));
+    //print_line("Java->GD call: "+obj->get_type()+"::"+str_method+" argc "+itos(count));
 
 	for (int i=0; i<MIN(count,VARIANT_ARG_MAX); i++) {
 
 		jobject obj = env->GetObjectArrayElement(params, i);
 		if (obj)
 			args[i] = _jobject_to_variant(env, obj);
+		env->DeleteLocalRef(obj);
+
 //		print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type()));
 
 	};

+ 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 );

+ 1 - 9
platform/bb10/SCsub

@@ -18,13 +18,5 @@ if env['bb10_lgles_override'] == "yes":
 
 
 prog = None
-if env["target"]=="release":
-	prog = env_bps.Program('#platform/bb10/godot_bb10_opt', bb10_lib)
-else:
-	prog = env_bps.Program('#platform/bb10/godot_bb10', bb10_lib)
-
-import os
-fname = os.path.basename(str(prog[0]))
-
-env.Command('#bin/'+fname, prog, Copy('bin/'+fname, prog[0]))
+prog = env_bps.Program('#bin/godot', bb10_lib)
 

+ 9 - 21
platform/bb10/bar/bar-descriptor.xml

@@ -1,65 +1,53 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<?xml version='1.0' encoding='utf-8' standalone='no'?>
 <qnx xmlns="http://www.qnx.com/schemas/application/1.0">
-
-<!-- BlackBerry® 10 application descriptor file.
+    <!-- BlackBerry® 10 application descriptor file.
 
     Specifies parameters for identifying, installing, and launching native applications on BlackBerry® 10 OS.
 -->
-
     <!-- A universally unique application identifier. Must be unique across all BlackBerry applications.
          Using a reverse DNS-style name as the id is recommended. (Eg. com.example.ExampleApplication.) Required. -->
     <id>com.godot.game</id>
-
     <!-- The name that is displayed in the BlackBerry application installer. 
          May have multiple values for each language. See samples or xsd schema file. Optional. -->
     <name>Godot Game</name>
-    
     <!-- A string value of the format <0-999>.<0-999>.<0-999> that represents application version which can be used to check for application upgrade. 
          Values can also be 1-part or 2-part. It is not necessary to have a 3-part value.
          An updated version of application must have a versionNumber value higher than the previous version. Required. -->
     <versionNumber>0.0.1</versionNumber>
-
     <!-- Fourth digit segment of the package version. First three segments are taken from the 
          <versionNumber> element.  Must be an integer from 0 to 2^16-1 -->
     <buildId>0</buildId>
-                 
     <!-- Description, displayed in the BlackBerry application installer.
          May have multiple values for each language. See samples or xsd schema file. Optional. -->
     <description>Game made with Godot Engine</description>
-
     <!--  Name of author which is used for signing. Must match the developer name of your development certificate. -->
     <author>You Name or Company</author>
     <authorId>authorIDherePlease</authorId>
-    
     <!--  Unique author ID assigned by signing authority. Required if using debug tokens. -->
     <!-- <authorId>ABC1234YjsnUk235h</authorId> -->
-   
     <initialWindow>
         <aspectRatio>landscape</aspectRatio>
         <autoOrients>false</autoOrients>
         <systemChrome>none</systemChrome>
         <transparent>false</transparent>
     </initialWindow>
-    
     <!--  The category where the application appears. Either core.games or core.media. -->
     <category>core.games</category>
     <permission>read_device_identifying_information</permission>
     <permission>access_internet</permission>
-    <asset path="assets">assets</asset>
+    <asset path="data.pck">data.pck</asset>
     <configuration name="Device-Debug">
-       <platformArchitecture>armle-v7</platformArchitecture>
-       <asset path="godot_bb10.qnx.armle" entry="true" type="Qnx/Elf">godot_bb10.qnx.armle</asset>
+        <platformArchitecture>armle-v7</platformArchitecture>
+        <asset type="Qnx/Elf" path="godot.bb10.debug.qnx.armle" entry="true">godot.bb10.debug.qnx.armle</asset>
     </configuration>
     <configuration name="Device-Release">
-       <platformArchitecture>armle-v7</platformArchitecture>
-       <asset path="godot_bb10_opt.qnx.armle" entry="true" type="Qnx/Elf">godot_bb10_opt.qnx.armle</asset>
+        <platformArchitecture>armle-v7</platformArchitecture>
+        <asset type="Qnx/Elf" path="godot.bb10.opt.qnx.armle" entry="true">godot.bb10.opt.qnx.armle</asset>
     </configuration>
     <!--  The icon for the application. -->
     <icon>
-       <image>icon.png</image>
+        <image>icon.png</image>
     </icon>
-    
     <!-- Ensure that shared libraries in the package are found at run-time. -->
-    <env var="LD_LIBRARY_PATH" value="app/native/lib:/usr/lib/qt4/lib"/>
-    
+    <env value="app/native/lib:/usr/lib/qt4/lib" var="LD_LIBRARY_PATH"/>
 </qnx>

+ 0 - 2
platform/bb10/detect.py

@@ -81,8 +81,6 @@ def configure(env):
 	if (env["target"]=="release"):
 
 		env.Append(CCFLAGS=['-O3','-DRELEASE_BUILD'])
-		env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
-		env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
 
 	elif (env["target"]=="debug"):
 

+ 33 - 46
platform/bb10/export/export.cpp

@@ -321,12 +321,29 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
 	//BE SUPER CAREFUL WITH THIS PLEASE!!!
 	//BLACKBERRY THIS IS YOUR FAULT FOR NOT MAKING A BETTER WAY!!
 
-	if (bar_dir.ends_with("bb10_export")) {
-		Error err = da->erase_contents_recursive();
-		if (err!=OK) {
+	bool berr = bar_dir.ends_with("bb10_export");
+	if (berr) {
+		if (da->list_dir_begin()) {
 			EditorNode::add_io_error("Can't ensure that dir is empty:\n"+bar_dir);
-			ERR_FAIL_COND_V(err!=OK,err);
-		}
+			ERR_FAIL_COND_V(berr,FAILED);
+		};
+
+		String f = da->get_next();
+		while (f != "") {
+
+			if (f == "." || f == "..") {
+				f = da->get_next();
+				continue;
+			};
+			Error err = da->remove(bar_dir + "/" + f);
+			if (err != OK) {
+				EditorNode::add_io_error("Can't ensure that dir is empty:\n"+bar_dir);
+				ERR_FAIL_COND_V(err!=OK,err);
+			};
+			f = da->get_next();
+		};
+
+		da->list_dir_end();
 
 	} else {
 		print_line("ARE YOU CRAZY??? THIS IS A SERIOUS BUG HERE!!!");
@@ -405,52 +422,23 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
 		ret = unzGoToNextFile(pkg);
 	}
 
-	ep.step("Finding Files..",1);
-
-	Vector<StringName> files=get_dependencies(false);
-
 	ep.step("Adding Files..",2);
 
-	da->change_dir(bar_dir);
-	da->make_dir("assets");
-	Error err = da->change_dir("assets");
-	ERR_FAIL_COND_V(err,err);
-
-	String asset_dir=da->get_current_dir();
-	if (!asset_dir.ends_with("/"))
-		asset_dir+="/";
-
-	for(int i=0;i<files.size();i++) {
-
-		String fname=files[i];
-		Vector<uint8_t> data = get_exported_file(fname);
-		/*
-		FileAccess *f=FileAccess::open(files[i],FileAccess::READ);
-		if (!f) {
-			EditorNode::add_io_error("Couldn't read: "+String(files[i]));
-		}
-		ERR_CONTINUE(!f);
-		data.resize(f->get_len());
-		f->get_buffer(data.ptr(),data.size());
-*/
-		String dst_path=fname;
-		dst_path=dst_path.replace_first("res://",asset_dir);
-
-		da->make_dir_recursive(dst_path.get_base_dir());
-
-		ep.step("Adding File: "+String(files[i]).get_file(),3+i*100/files.size());
-
-		FileAccessRef fr = FileAccess::open(dst_path,FileAccess::WRITE);
-		fr->store_buffer(data.ptr(),data.size());
+	FileAccess* dst = FileAccess::open(bar_dir+"/data.pck", FileAccess::WRITE);
+	if (!dst) {
+		EditorNode::add_io_error("Can't copy executable file to:\n "+p_path);
+		return ERR_FILE_CANT_WRITE;
 	}
-
+	save_pack(dst, false, 1024);
+	dst->close();
+	memdelete(dst);
 
 	ep.step("Creating BAR Package..",104);
 
 	String bb_packager=EditorSettings::get_singleton()->get("blackberry/host_tools");
 	bb_packager=bb_packager.plus_file("blackberry-nativepackager");
 	if (OS::get_singleton()->get_name()=="Windows")
-		bb_packager+=".exe";
+		bb_packager+=".bat";
 
 
 	if (!FileAccess::exists(bb_packager)) {
@@ -482,7 +470,7 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
 
 	int ec;
 
-	err = OS::get_singleton()->execute(bb_packager,args,true,NULL,NULL,&ec);
+	Error err = OS::get_singleton()->execute(bb_packager,args,true,NULL,NULL,&ec);
 
 	if (err!=OK)
 		return err;
@@ -493,7 +481,6 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
 
 }
 
-
 bool EditorExportPlatformBB10::poll_devices() {
 
 	bool dc=devices_changed;
@@ -537,7 +524,7 @@ void EditorExportPlatformBB10::_device_poll_thread(void *ud) {
 		bb_deploy=bb_deploy.plus_file("blackberry-deploy");
 		bool windows = OS::get_singleton()->get_name()=="Windows";
 		if (windows)
-			bb_deploy+=".exe";
+			bb_deploy+=".bat";
 
 		if (!FileAccess::exists(bb_deploy)) {
 			OS::get_singleton()->delay_usec(3000000);
@@ -639,7 +626,7 @@ Error EditorExportPlatformBB10::run(int p_device, bool p_dumb) {
 	String bb_deploy=EditorSettings::get_singleton()->get("blackberry/host_tools");
 	bb_deploy=bb_deploy.plus_file("blackberry-deploy");
 	if (OS::get_singleton()->get_name()=="Windows")
-		bb_deploy+=".exe";
+		bb_deploy+=".bat";
 
 	if (!FileAccess::exists(bb_deploy)) {
 		EditorNode::add_io_error("Blackberry Deploy not found:\n"+bb_deploy);

+ 1 - 1
platform/bb10/os_bb10.cpp

@@ -619,7 +619,7 @@ OSBB10::OSBB10() {
 	printf("godot bb10!\n");
 	getcwd(launch_dir, sizeof(launch_dir));
 	printf("launch dir %s\n", launch_dir);
-	chdir("app/native/assets");
+	chdir("app/native");
 	launch_dir_ptr = launch_dir;
 }
 

+ 2 - 0
platform/iphone/gl_view.h

@@ -101,6 +101,8 @@
 - (BOOL)createFramebuffer;
 - (void)destroyFramebuffer;
 
+- (void)audioRouteChangeListenerCallback:(NSNotification*)notification;
+
 @property NSTimeInterval animationInterval;
 
 @end

+ 52 - 0
platform/iphone/gl_view.mm

@@ -119,6 +119,8 @@ bool _play_video(String p_path, float p_volume, String p_audio_track, String p_s
                                                name:AVPlayerItemDidPlayToEndTimeNotification
                                              object:[_instance.avPlayer currentItem]];
 
+	[_instance.avPlayer addObserver:_instance forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:0];
+
     [_instance.avPlayerLayer setFrame:_instance.bounds];
     [_instance.layer addSublayer:_instance.avPlayerLayer];
     [_instance.avPlayer play];
@@ -610,6 +612,39 @@ static void clear_touches() {
 	printf("inserting text with character %i\n", character[0]);
 };
 
+- (void)audioRouteChangeListenerCallback:(NSNotification*)notification
+{
+	printf("*********** route changed!%i\n");
+	NSDictionary *interuptionDict = notification.userInfo;
+
+	NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
+
+	switch (routeChangeReason) {
+
+		case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
+			NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable");
+			NSLog(@"Headphone/Line plugged in");
+			break;
+
+		case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
+			NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable");
+			NSLog(@"Headphone/Line was pulled. Resuming video play....");
+			if (_is_video_playing) {
+
+				dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+							[_instance.avPlayer play]; // NOTE: change this line according your current player implementation
+							NSLog(@"resumed play");
+				});
+			};
+			break;
+
+		case AVAudioSessionRouteChangeReasonCategoryChange:
+			// called at start - also when other audio wants to play
+			NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
+			break;
+	}
+}
+
 
 // When created via code however, we get initWithFrame
 -(id)initWithFrame:(CGRect)frame
@@ -625,6 +660,11 @@ static void clear_touches() {
 	init_touches();
 	self. multipleTouchEnabled = YES;
 
+	printf("******** adding observer for sound routing changes\n");
+	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:)
+												 name:AVAudioSessionRouteChangeNotification
+											   object:nil];
+
 	//self.autoresizesSubviews = YES;
 	//[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
 
@@ -674,6 +714,18 @@ static void clear_touches() {
     		video_current_time = kCMTimeZero;
 		}
     }
+
+	if (object == _instance.avPlayer && [keyPath isEqualToString:@"rate"]) {
+		NSLog(@"Player playback rate changed: %.5f", _instance.avPlayer.rate);
+		if (_is_video_playing() && _instance.avPlayer.rate == 0.0 && !_instance.avPlayer.error) {
+			dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+						[_instance.avPlayer play]; // NOTE: change this line according your current player implementation
+						NSLog(@"resumed play");
+			});
+
+			NSLog(@" . . . PAUSED (or just started)");
+		}
+	}
 }
 
 - (void)playerItemDidReachEnd:(NSNotification *)notification {

+ 1 - 1
platform/osx/os_osx.mm

@@ -1100,7 +1100,7 @@ void OS_OSX::warp_mouse_pos(const Point2& p_to) {
 	NSPoint localPoint = { p_to.x, p_to.y };
 
 	NSPoint pointInWindow = [window_view convertPoint:localPoint toView:nil];
-	NSPoint pointOnScreen = [[window_view window] convertRectToScreen:(CGRect){.origin=pointInWindow}];
+	NSPoint pointOnScreen = [[window_view window] convertRectToScreen:(NSRect){.origin=pointInWindow}].origin;
 
 	//point in scren coords
 	CGPoint lMouseWarpPos = { pointOnScreen.x, pointOnScreen.y};

+ 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'])

+ 8 - 3
platform/windows/os_windows.cpp

@@ -715,9 +715,14 @@ String OS_Windows::get_joystick_name(int id, JOYCAPS jcaps)
 		return "";
 
 	_snprintf( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEM);
-	res = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
-	if (res != ERROR_SUCCESS) 
-		return "";
+	res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
+	if (res != ERROR_SUCCESS)
+	{
+		res = RegOpenKeyEx(HKEY_CURRENT_USER, buffer, 0, KEY_QUERY_VALUE, &hKey);
+		if (res != ERROR_SUCCESS)
+			return "";
+	}
+		
 
 	sz = sizeof(buffer);
 	res = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buffer,

+ 2 - 3
platform/winrt/os_winrt.cpp

@@ -27,7 +27,6 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #include "drivers/gles2/rasterizer_gles2.h"
-#include "drivers/gles1/rasterizer_gles1.h"
 #include "os_winrt.h"
 #include "drivers/nedmalloc/memory_pool_static_nedmalloc.h"
 #include "drivers/unix/memory_pool_static_malloc.h"
@@ -62,11 +61,11 @@ using namespace Microsoft::WRL;
 
 int OSWinrt::get_video_driver_count() const {
 
-	return 2;
+	return 1;
 }
 const char * OSWinrt::get_video_driver_name(int p_driver) const {
 
-	return p_driver==0?"GLES2":"GLES1";
+	return "GLES2";
 }
 
 OS::VideoMode OSWinrt::get_default_video_mode() const {

+ 11 - 0
scene/2d/camera_2d.cpp

@@ -323,6 +323,16 @@ void Camera2D::make_current() {
 	}
 }
 
+void Camera2D::clear_current() {
+
+	current=false;
+	if (is_inside_tree()) {
+		get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,group_name,"_make_current",(Object*)(NULL));
+	}
+
+}
+
+
 void Camera2D::set_limit(Margin p_margin,int p_limit) {
 
 	ERR_FAIL_INDEX(p_margin,4);
@@ -435,6 +445,7 @@ void Camera2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("is_rotating"),&Camera2D::is_rotating);
 
 	ObjectTypeDB::bind_method(_MD("make_current"),&Camera2D::make_current);
+	ObjectTypeDB::bind_method(_MD("clear_current"),&Camera2D::clear_current);
 	ObjectTypeDB::bind_method(_MD("_make_current"),&Camera2D::_make_current);
 
 	ObjectTypeDB::bind_method(_MD("_update_scroll"),&Camera2D::_update_scroll);

+ 95 - 94
scene/2d/camera_2d.h

@@ -26,97 +26,98 @@
 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
-#ifndef CAMERA_2D_H
-#define CAMERA_2D_H
-
-#include "scene/2d/node_2d.h"
-#include "scene/main/viewport.h"
-
-
-class Camera2D : public Node2D {
-
-	OBJ_TYPE( Camera2D, Node2D );
-
-protected:
-	Point2 camera_pos;
-	Point2 smoothed_camera_pos;
-	bool first;
-
-	Viewport *viewport;
-
-	StringName group_name;
-	StringName canvas_group_name;
-	RID canvas;
-	Vector2 offset;
-	Vector2 zoom;
-	bool centered;
-	bool rotating;
-	bool current;
-	float smoothing;
-	int limit[4];
-	float drag_margin[4];
-
-	bool h_drag_enabled;
-	bool v_drag_enabled;
-	float h_ofs;
-	float v_ofs;
-
-
-	Point2 camera_screen_center;
-	void _update_scroll();
-
-	void _make_current(Object *p_which);
-	void _set_current(bool p_current);
-protected:
-
-	virtual Matrix32 get_camera_transform();
-	void _notification(int p_what);
-	static void _bind_methods();
-public:
-
-	void set_offset(const Vector2& p_offset);
-	Vector2 get_offset() const;
-
-	void set_centered(bool p_centered);
-	bool is_centered() const;
-
-	void set_rotating(bool p_rotating);
-	bool is_rotating() const;
-
-	void set_limit(Margin p_margin,int p_limit);
-	int get_limit(Margin p_margin) const;
-
-
-	void set_h_drag_enabled(bool p_enabled);
-	bool is_h_drag_enabled() const;
-
-	void set_v_drag_enabled(bool p_enabled);
-	bool is_v_drag_enabled() const;
-
-	void set_drag_margin(Margin p_margin,float p_drag_margin);
-	float get_drag_margin(Margin p_margin) const;  
-
-	void set_v_offset(float p_offset);
-	float get_v_offset() const;
-
-	void set_h_offset(float p_offset);
-	float get_h_offset() const;
-
-	void set_follow_smoothing(float p_speed);
-	float get_follow_smoothing() const;
-
-	void make_current();
-	bool is_current() const;
-
-	void set_zoom(const Vector2& p_zoom);
-	Vector2 get_zoom() const;
-
-	Point2 get_camera_screen_center() const;
-
-	Vector2 get_camera_pos() const;
-	void force_update_scroll();
-
-	Camera2D();
-};
-
-#endif // CAMERA_2D_H
+#ifndef CAMERA_2D_H
+#define CAMERA_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/main/viewport.h"
+
+
+class Camera2D : public Node2D {
+
+	OBJ_TYPE( Camera2D, Node2D );
+
+protected:
+	Point2 camera_pos;
+	Point2 smoothed_camera_pos;
+	bool first;
+
+	Viewport *viewport;
+
+	StringName group_name;
+	StringName canvas_group_name;
+	RID canvas;
+	Vector2 offset;
+	Vector2 zoom;
+	bool centered;
+	bool rotating;
+	bool current;
+	float smoothing;
+	int limit[4];
+	float drag_margin[4];
+
+	bool h_drag_enabled;
+	bool v_drag_enabled;
+	float h_ofs;
+	float v_ofs;
+
+
+	Point2 camera_screen_center;
+	void _update_scroll();
+
+	void _make_current(Object *p_which);
+	void _set_current(bool p_current);
+protected:
+
+	virtual Matrix32 get_camera_transform();
+	void _notification(int p_what);
+	static void _bind_methods();
+public:
+
+	void set_offset(const Vector2& p_offset);
+	Vector2 get_offset() const;
+
+	void set_centered(bool p_centered);
+	bool is_centered() const;
+
+	void set_rotating(bool p_rotating);
+	bool is_rotating() const;
+
+	void set_limit(Margin p_margin,int p_limit);
+	int get_limit(Margin p_margin) const;
+
+
+	void set_h_drag_enabled(bool p_enabled);
+	bool is_h_drag_enabled() const;
+
+	void set_v_drag_enabled(bool p_enabled);
+	bool is_v_drag_enabled() const;
+
+	void set_drag_margin(Margin p_margin,float p_drag_margin);
+	float get_drag_margin(Margin p_margin) const;  
+
+	void set_v_offset(float p_offset);
+	float get_v_offset() const;
+
+	void set_h_offset(float p_offset);
+	float get_h_offset() const;
+
+	void set_follow_smoothing(float p_speed);
+	float get_follow_smoothing() const;
+
+	void make_current();
+	void clear_current();
+	bool is_current() const;
+
+	void set_zoom(const Vector2& p_zoom);
+	Vector2 get_zoom() const;
+
+	Point2 get_camera_screen_center() const;
+
+	Vector2 get_camera_pos() const;
+	void force_update_scroll();
+
+	Camera2D();
+};
+
+#endif // CAMERA_2D_H

+ 226 - 106
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())
@@ -458,6 +644,16 @@ CanvasItem::BlendMode CanvasItem::get_blend_mode() const {
 	return blend_mode;
 }
 
+void CanvasItem::set_light_mask(int p_light_mask) {
+
+	light_mask=p_light_mask;
+	VS::get_singleton()->canvas_item_set_light_mask(canvas_item,p_light_mask);
+}
+
+int CanvasItem::get_light_mask() const{
+
+	return light_mask;
+}
 
 
 void CanvasItem::item_rect_changed() {
@@ -511,7 +707,7 @@ void CanvasItem::draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos)
 	p_texture->draw(canvas_item,p_pos);
 }
 
-void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_rect, bool p_tile,const Color& p_modulate) {
+void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) {
 
 	if (!drawing) {
 		ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -519,17 +715,17 @@ void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_
 	}
 
 	ERR_FAIL_COND(p_texture.is_null());
-	p_texture->draw_rect(canvas_item,p_rect,p_tile,p_modulate);
+	p_texture->draw_rect(canvas_item,p_rect,p_tile,p_modulate,p_transpose);
 
 }
-void CanvasItem::draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) {
+void CanvasItem::draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) {
 
 	if (!drawing) {
 		ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 		ERR_FAIL();
 	}
 	ERR_FAIL_COND(p_texture.is_null());
-	p_texture->draw_rect_region(canvas_item,p_rect,p_src_rect,p_modulate);
+	p_texture->draw_rect_region(canvas_item,p_rect,p_src_rect,p_modulate,p_transpose);
 }
 
 void CanvasItem::draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect) {
@@ -720,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;
+void CanvasItem::set_material(const Ref<CanvasItemMaterial>& p_material) {
 
-#ifdef TOOLS_ENABLED
-
-	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
+	if (material.is_valid())
+		rid=material->get_rid();
+	VS::get_singleton()->canvas_item_set_material(canvas_item,rid);
+	_change_notify(); //properties for material exposed
 }
 
-void CanvasItem::set_use_parent_shader(bool p_use_parent_shader) {
+void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
 
-	use_parent_shader=p_use_parent_shader;
-	VS::get_singleton()->canvas_item_set_use_parent_shader(canvas_item,p_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);
 }
 
-bool CanvasItem::get_use_parent_shader() const{
+bool CanvasItem::get_use_parent_material() const{
 
-	return use_parent_shader;
+	return use_parent_material;
 }
 
-Ref<Shader> CanvasItem::get_shader() const{
+Ref<CanvasItemMaterial> CanvasItem::get_material() const{
 
-	return shader;
+	return material;
 }
 
-void CanvasItem::set_shader_param(const StringName& p_param,const Variant& p_value) {
-
-	VS::get_singleton()->canvas_item_set_shader_param(canvas_item,p_param,p_value);
-}
 
-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() {
@@ -857,6 +977,9 @@ void CanvasItem::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_blend_mode","blend_mode"),&CanvasItem::set_blend_mode);
 	ObjectTypeDB::bind_method(_MD("get_blend_mode"),&CanvasItem::get_blend_mode);
 
+	ObjectTypeDB::bind_method(_MD("set_light_mask","light_mask"),&CanvasItem::set_light_mask);
+	ObjectTypeDB::bind_method(_MD("get_light_mask"),&CanvasItem::get_light_mask);
+
 	ObjectTypeDB::bind_method(_MD("set_opacity","opacity"),&CanvasItem::set_opacity);
 	ObjectTypeDB::bind_method(_MD("get_opacity"),&CanvasItem::get_opacity);
 	ObjectTypeDB::bind_method(_MD("set_self_opacity","self_opacity"),&CanvasItem::set_self_opacity);
@@ -867,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));
@@ -888,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"));
 
@@ -912,8 +1030,9 @@ void CanvasItem::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top",PROPERTY_HINT_NONE,"",0), _SCS("_set_on_top"),_SCS("_is_on_top") ); //compatibility
 
 	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::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::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") );
+	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"));
@@ -990,8 +1109,9 @@ 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;
 
 	C=NULL;
 

+ 47 - 20
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 );
@@ -71,6 +106,7 @@ private:
 	List<CanvasItem*>::Element *C;
 
 	BlendMode blend_mode;
+	int light_mask;
 
 	bool first_draw;
 	bool hidden;
@@ -80,9 +116,9 @@ private:
 	bool drawing;
 	bool block_transform_notify;
 	bool behind;
+	bool use_parent_material;
 
-	bool use_parent_shader;
-	Ref<Shader> shader;
+	Ref<CanvasItemMaterial> material;
 
 	mutable Matrix32 global_transform;
 	mutable bool global_invalid;
@@ -103,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); }
@@ -113,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();
@@ -158,6 +186,9 @@ public:
 	void set_blend_mode(BlendMode p_blend_mode);
 	BlendMode get_blend_mode() const;
 
+	void set_light_mask(int p_light_mask);
+	int get_light_mask() const;
+
 	void set_opacity(float p_opacity);
 	float get_opacity() const;
 
@@ -170,8 +201,8 @@ public:
 	void draw_rect(const Rect2& p_rect, const Color& p_color);
 	void draw_circle(const Point2& p_pos, float p_radius, const Color& p_color);
 	void draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos);
-	void draw_texture_rect(const Ref<Texture>& p_texture, const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1));
-	void draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1));
+	void draw_texture_rect(const Ref<Texture>& p_texture, const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false);
+	void draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false);
 	void draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect);
 	void draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture=Ref<Texture>(),float p_width=1);
 	void draw_polygon(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), Ref<Texture> p_texture=Ref<Texture>());
@@ -212,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_use_parent_shader(bool p_use_parent_shader);
-	bool get_use_parent_shader() const;
+	void set_material(const Ref<CanvasItemMaterial>& p_material);
+	Ref<CanvasItemMaterial> get_material() const;
 
-	void set_shader_param(const StringName& p_param,const Variant& p_value);
-	Variant get_shader_param(const StringName& p_param) const;
+	void set_use_parent_material(bool p_use_parent_material);
+	bool get_use_parent_material() const;
 
-	void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
 
 	CanvasItem();
 	~CanvasItem();

+ 46 - 0
scene/2d/canvas_modulate.cpp

@@ -0,0 +1,46 @@
+#include "canvas_modulate.h"
+
+
+void CanvasModulate::_notification(int p_what) {
+
+	if (p_what==NOTIFICATION_ENTER_CANVAS) {
+
+		VS::get_singleton()->canvas_set_modulate(get_canvas(),color);
+	} else if (p_what==NOTIFICATION_EXIT_CANVAS) {
+
+		VS::get_singleton()->canvas_set_modulate(get_canvas(),Color(1,1,1,1));
+	}
+}
+
+void CanvasModulate::_bind_methods(){
+
+	ObjectTypeDB::bind_method(_MD("set_color","color"),&CanvasModulate::set_color);
+	ObjectTypeDB::bind_method(_MD("get_color"),&CanvasModulate::get_color);
+
+	ADD_PROPERTY(PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
+}
+
+
+void CanvasModulate::set_color(const Color& p_color){
+
+	color=p_color;
+	if (is_inside_tree()) {
+		VS::get_singleton()->canvas_set_modulate(get_canvas(),color);
+	}
+}
+Color CanvasModulate::get_color() const {
+
+	return color;
+}
+
+
+CanvasModulate::CanvasModulate()
+{
+	color=Color(1,1,1,1);
+}
+
+CanvasModulate::~CanvasModulate()
+{
+
+}
+

+ 23 - 0
scene/2d/canvas_modulate.h

@@ -0,0 +1,23 @@
+#ifndef CANVASMODULATE_H
+#define CANVASMODULATE_H
+
+#include "scene/2d/node_2d.h"
+
+class CanvasModulate : public Node2D {
+
+	OBJ_TYPE(CanvasModulate,Node2D);
+
+	Color color;
+protected:
+	void _notification(int p_what);
+	static void _bind_methods();
+public:
+
+	void set_color(const Color& p_color);
+	Color get_color() const;
+
+	CanvasModulate();
+	~CanvasModulate();
+};
+
+#endif // CANVASMODULATE_H

+ 300 - 0
scene/2d/light_2d.cpp

@@ -0,0 +1,300 @@
+#include "light_2d.h"
+#include "servers/visual_server.h"
+
+void Light2D::edit_set_pivot(const Point2& p_pivot) {
+
+	set_texture_offset(p_pivot);
+
+}
+
+Point2 Light2D::edit_get_pivot() const {
+
+	return get_texture_offset();
+}
+bool Light2D::edit_has_pivot() const {
+
+	return true;
+}
+
+Rect2 Light2D::get_item_rect() const {
+
+	if (texture.is_null())
+		return Rect2(0,0,1,1);
+
+	Size2i s;
+
+	s = texture->get_size();
+	Point2i ofs=texture_offset;
+	ofs-=s/2;
+
+	if (s==Size2(0,0))
+		s=Size2(1,1);
+
+	return Rect2(ofs,s);
+}
+
+
+void Light2D::set_enabled( bool p_enabled) {
+
+	VS::get_singleton()->canvas_light_set_enabled(canvas_light,p_enabled);
+	enabled=p_enabled;
+}
+
+bool Light2D::is_enabled() const {
+
+	return enabled;
+}
+
+void Light2D::set_texture( const Ref<Texture>& p_texture) {
+
+	texture=p_texture;
+	if (texture.is_valid())
+		VS::get_singleton()->canvas_light_set_texture(canvas_light,texture->get_rid());
+	else
+		VS::get_singleton()->canvas_light_set_texture(canvas_light,RID());
+}
+
+Ref<Texture> Light2D::get_texture() const {
+
+	return texture;
+}
+
+void Light2D::set_texture_offset( const Vector2& p_offset) {
+
+	texture_offset=p_offset;
+	VS::get_singleton()->canvas_light_set_texture_offset(canvas_light,texture_offset);
+}
+
+Vector2 Light2D::get_texture_offset() const {
+
+	return texture_offset;
+}
+
+void Light2D::set_color( const Color& p_color) {
+
+	color=p_color;
+	VS::get_singleton()->canvas_light_set_color(canvas_light,color);
+
+}
+Color Light2D::get_color() const {
+
+	return color;
+}
+
+void Light2D::set_height( float p_height) {
+
+	height=p_height;
+	VS::get_singleton()->canvas_light_set_height(canvas_light,height);
+
+}
+float Light2D::get_height() const {
+
+	return height;
+}
+
+void Light2D::set_z_range_min( int p_min_z) {
+
+	z_min=p_min_z;
+	VS::get_singleton()->canvas_light_set_z_range(canvas_light,z_min,z_max);
+
+}
+int Light2D::get_z_range_min() const {
+
+	return z_min;
+}
+
+void Light2D::set_z_range_max( int p_max_z) {
+
+	z_max=p_max_z;
+	VS::get_singleton()->canvas_light_set_z_range(canvas_light,z_min,z_max);
+
+}
+int Light2D::get_z_range_max() const {
+
+	return z_max;
+}
+
+void Light2D::set_layer_range_min( int p_min_layer) {
+
+	layer_min=p_min_layer;
+	VS::get_singleton()->canvas_light_set_layer_range(canvas_light,layer_min,layer_max);
+
+}
+int Light2D::get_layer_range_min() const {
+
+	return layer_min;
+}
+
+void Light2D::set_layer_range_max( int p_max_layer) {
+
+	layer_max=p_max_layer;
+	VS::get_singleton()->canvas_light_set_layer_range(canvas_light,layer_min,layer_max);
+
+}
+int Light2D::get_layer_range_max() const {
+
+	return layer_max;
+}
+
+void Light2D::set_item_mask( int p_mask) {
+
+	item_mask=p_mask;
+	VS::get_singleton()->canvas_light_set_item_mask(canvas_light,item_mask);
+
+}
+
+int Light2D::get_item_mask() const {
+
+	return item_mask;
+}
+
+void Light2D::set_subtract_mode( bool p_enable ) {
+
+	subtract_mode=p_enable;
+	VS::get_singleton()->canvas_light_set_subtract_mode(canvas_light,p_enable);
+}
+
+bool Light2D::get_subtract_mode() const {
+
+	return subtract_mode;
+}
+
+void Light2D::set_shadow_enabled( bool p_enabled) {
+
+	shadow=p_enabled;
+	VS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light,shadow);
+
+}
+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) {
+
+		VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, get_canvas() );
+	}
+
+	if (p_what==NOTIFICATION_TRANSFORM_CHANGED) {
+
+		VS::get_singleton()->canvas_light_set_transform( canvas_light, get_global_transform());
+	}
+
+	if (p_what==NOTIFICATION_EXIT_TREE) {
+
+		VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, RID() );
+	}
+
+}
+
+void Light2D::_bind_methods() {
+
+
+	ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&Light2D::set_enabled);
+	ObjectTypeDB::bind_method(_MD("is_enabled"),&Light2D::is_enabled);
+
+	ObjectTypeDB::bind_method(_MD("set_texture","texture"),&Light2D::set_texture);
+	ObjectTypeDB::bind_method(_MD("get_texture"),&Light2D::get_texture);
+
+	ObjectTypeDB::bind_method(_MD("set_texture_offset","texture_offset"),&Light2D::set_texture_offset);
+	ObjectTypeDB::bind_method(_MD("get_texture_offset"),&Light2D::get_texture_offset);
+
+	ObjectTypeDB::bind_method(_MD("set_color","color"),&Light2D::set_color);
+	ObjectTypeDB::bind_method(_MD("get_color"),&Light2D::get_color);
+
+	ObjectTypeDB::bind_method(_MD("set_height","height"),&Light2D::set_height);
+	ObjectTypeDB::bind_method(_MD("get_height"),&Light2D::get_height);
+
+	ObjectTypeDB::bind_method(_MD("set_z_range_min","z"),&Light2D::set_z_range_min);
+	ObjectTypeDB::bind_method(_MD("get_z_range_min"),&Light2D::get_z_range_min);
+
+	ObjectTypeDB::bind_method(_MD("set_z_range_max","z"),&Light2D::set_z_range_max);
+	ObjectTypeDB::bind_method(_MD("get_z_range_max"),&Light2D::get_z_range_max);
+
+	ObjectTypeDB::bind_method(_MD("set_layer_range_min","layer"),&Light2D::set_layer_range_min);
+	ObjectTypeDB::bind_method(_MD("get_layer_range_min"),&Light2D::get_layer_range_min);
+
+	ObjectTypeDB::bind_method(_MD("set_layer_range_max","layer"),&Light2D::set_layer_range_max);
+	ObjectTypeDB::bind_method(_MD("get_layer_range_max"),&Light2D::get_layer_range_max);
+
+
+	ObjectTypeDB::bind_method(_MD("set_item_mask","item_mask"),&Light2D::set_item_mask);
+	ObjectTypeDB::bind_method(_MD("get_item_mask"),&Light2D::get_item_mask);
+
+	ObjectTypeDB::bind_method(_MD("set_subtract_mode","enable"),&Light2D::set_subtract_mode);
+	ObjectTypeDB::bind_method(_MD("get_subtract_mode"),&Light2D::get_subtract_mode);
+
+	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,"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::BOOL,"subtract"),_SCS("set_subtract_mode"),_SCS("get_subtract_mode"));
+	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"));
+
+
+}
+
+Light2D::Light2D() {
+
+	canvas_light=VisualServer::get_singleton()->canvas_light_create();
+	enabled=true;
+	shadow=false;
+	color=Color(1,1,1);
+	height=0;
+	z_min=-1024;
+	z_max=1024;
+	layer_min=0;
+	layer_max=0;
+	item_mask=1;
+	subtract_mode=false;
+	shadow_buffer_size=2048;
+	shadow_esm_multiplier=80;
+
+}
+
+Light2D::~Light2D() {
+
+	VisualServer::get_singleton()->free(canvas_light);
+}

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

@@ -0,0 +1,86 @@
+#ifndef LIGHT_2D_H
+#define LIGHT_2D_H
+
+#include "scene/2d/node_2d.h"
+
+class Light2D : public Node2D {
+
+	OBJ_TYPE(Light2D,Node2D);
+private:
+	RID canvas_light;
+	bool enabled;
+	bool shadow;
+	Color color;
+	float height;
+	int z_min;
+	int z_max;
+	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;
+
+protected:
+
+	void _notification(int p_what);
+	static void _bind_methods();
+public:
+
+
+	virtual void edit_set_pivot(const Point2& p_pivot);
+	virtual Point2 edit_get_pivot() const;
+	virtual bool edit_has_pivot() const;
+
+	void set_enabled( bool p_enabled);
+	bool is_enabled() const;
+
+	void set_texture( const Ref<Texture>& p_texture);
+	Ref<Texture> get_texture() const;
+
+	void set_texture_offset( const Vector2& p_offset);
+	Vector2 get_texture_offset() const;
+
+	void set_color( const Color& p_color);
+	Color get_color() const;
+
+	void set_height( float p_height);
+	float get_height() const;
+
+	void set_z_range_min( int p_min_z);
+	int get_z_range_min() const;
+
+	void set_z_range_max( int p_max_z);
+	int get_z_range_max() const;
+
+	void set_layer_range_min( int p_min_layer);
+	int get_layer_range_min() const;
+
+	void set_layer_range_max( int p_max_layer);
+	int get_layer_range_max() const;
+
+	void set_item_mask( int p_mask);
+	int get_item_mask() const;
+
+	void set_subtract_mode( bool p_enable );
+	bool get_subtract_mode() const;
+
+	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();
+	~Light2D();
+};
+
+
+#endif // LIGHT_2D_H

+ 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

+ 38 - 1
scene/2d/navigation2d.cpp

@@ -1,5 +1,7 @@
 #include "navigation2d.h"
 
+#define USE_ENTRY_POINT
+
 void Navigation2D::_navpoly_link(int p_id) {
 
 	ERR_FAIL_COND(!navpoly_map.has(p_id));
@@ -336,12 +338,25 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
 
 	List<Polygon*> open_list;
 
+	begin_poly->entry=p_start;
+
 	for(int i=0;i<begin_poly->edges.size();i++) {
 
 		if (begin_poly->edges[i].C) {
 
 			begin_poly->edges[i].C->prev_edge=begin_poly->edges[i].C_edge;
+#ifdef USE_ENTRY_POINT
+			Vector2 edge[2]={
+				_get_vertex(begin_poly->edges[i].point),
+				_get_vertex(begin_poly->edges[(i+1)%begin_poly->edges.size()].point)
+			};
+
+			Vector2 entry = Geometry::get_closest_point_to_segment_2d(begin_poly->entry,edge);
+			begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry);
+			begin_poly->edges[i].C->entry=entry;
+#else
 			begin_poly->edges[i].C->distance=begin_poly->center.distance_to(begin_poly->edges[i].C->center);
+#endif
 			open_list.push_back(begin_poly->edges[i].C);
 
 			if (begin_poly->edges[i].C==end_poly) {
@@ -381,8 +396,9 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
 
 		Polygon *p=least_cost_poly->get();
 		//open the neighbours for search
+		int es = p->edges.size();
 
-		for(int i=0;i<p->edges.size();i++) {
+		for(int i=0;i<es;i++) {
 
 
 			Polygon::Edge &e=p->edges[i];
@@ -390,8 +406,22 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
 			if (!e.C)
 				continue;
 
+#ifdef USE_ENTRY_POINT
+			Vector2 edge[2]={
+				_get_vertex(p->edges[i].point),
+				_get_vertex(p->edges[(i+1)%es].point)
+			};
+
+			Vector2 edge_entry = Geometry::get_closest_point_to_segment_2d(p->entry,edge);
+			float distance = p->entry.distance_to(edge_entry) + p->distance;
+
+#else
+
 			float distance = p->center.distance_to(e.C->center) + p->distance;
 
+#endif
+
+
 			if (e.C->prev_edge!=-1) {
 				//oh this was visited already, can we win the cost?
 
@@ -399,12 +429,19 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
 
 					e.C->prev_edge=e.C_edge;
 					e.C->distance=distance;
+#ifdef USE_ENTRY_POINT
+					e.C->entry=edge_entry;
+#endif
 				}
 			} else {
 				//add to open neighbours
 
 				e.C->prev_edge=e.C_edge;
 				e.C->distance=distance;
+#ifdef USE_ENTRY_POINT
+				e.C->entry=edge_entry;
+#endif
+
 				open_list.push_back(e.C);
 
 				if (e.C==end_poly) {

+ 1 - 0
scene/2d/navigation2d.h

@@ -55,6 +55,7 @@ class Navigation2D : public Node2D {
 		Vector<Edge> edges;
 
 		Vector2 center;
+		Vector2 entry;
 
 		float distance;
 		int prev_edge;

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

@@ -29,7 +29,7 @@
 #include "tile_map.h"
 #include "io/marshalls.h"
 #include "servers/physics_2d_server.h"
-
+#include "method_bind_ext.inc"
 void TileMap::_notification(int p_what) {
 
 	switch(p_what) {
@@ -226,11 +226,9 @@ void TileMap::_update_dirty_quadrants() {
 
 			rect.pos+=tile_ofs;
 			if (r==Rect2()) {
-
-				tex->draw_rect(q.canvas_item,rect);
+				tex->draw_rect(q.canvas_item,rect,false,Color(1,1,1),c.transpose);
 			} else {
-
-				tex->draw_rect_region(q.canvas_item,rect,r);
+				tex->draw_rect_region(q.canvas_item,rect,r,Color(1,1,1),c.transpose);
 			}
 
 			Vector< Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id);
@@ -244,20 +242,25 @@ void TileMap::_update_dirty_quadrants() {
 					Vector2 shape_ofs = tile_set->tile_get_shape_offset(c.id);
 					Matrix32 xform;
 					xform.set_origin(offset.floor());
+					if (c.transpose) {
+						SWAP(xform.elements[0].x, xform.elements[0].y);
+						SWAP(xform.elements[1].x, xform.elements[1].y);
+						SWAP(shape_ofs.x, shape_ofs.y);
+						SWAP(s.x, s.y);
+					}
 					if (c.flip_h) {
-						xform.elements[0]=-xform.elements[0];
-						xform.elements[2].x+=s.x-shape_ofs.x;
-					} else {
-
-						xform.elements[2].x+=shape_ofs.x;
+						xform.elements[0].x=-xform.elements[0].x;
+						xform.elements[1].x=-xform.elements[1].x;
+						shape_ofs.x=s.x-shape_ofs.x;
 					}
 					if (c.flip_v) {
-						xform.elements[1]=-xform.elements[1];
-						xform.elements[2].y+=s.y-shape_ofs.y;
-					} else {
-
-						xform.elements[2].y+=shape_ofs.y;
+						xform.elements[0].y=-xform.elements[0].y;
+						xform.elements[1].y=-xform.elements[1].y;
+						shape_ofs.y=s.y-shape_ofs.y;
 					}
+					xform.elements[2].x+=shape_ofs.x;
+					xform.elements[2].y+=shape_ofs.y;
+
 
 
 					ps->body_add_shape(q.body,shape->get_rid(),xform);
@@ -386,7 +389,7 @@ void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) {
 }
 
 
-void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
+void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) {
 
 	PosKey pk(p_x,p_y);
 
@@ -422,7 +425,7 @@ void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
 	} else {
 		ERR_FAIL_COND(!Q); // quadrant should exist...
 
-		if (E->get().id==p_tile && E->get().flip_h==p_flip_x && E->get().flip_v==p_flip_y)
+		if (E->get().id==p_tile && E->get().flip_h==p_flip_x && E->get().flip_v==p_flip_y && E->get().transpose==p_transpose)
 			return; //nothing changed
 
 	}
@@ -433,6 +436,7 @@ void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
 	c.id=p_tile;
 	c.flip_h=p_flip_x;
 	c.flip_v=p_flip_y;
+	c.transpose=p_transpose;
 
 	_make_quadrant_dirty(Q);
 
@@ -472,6 +476,17 @@ bool TileMap::is_cell_y_flipped(int p_x,int p_y) const {
 
 	return E->get().flip_v;
 }
+bool TileMap::is_cell_transposed(int p_x,int p_y) const {
+
+	PosKey pk(p_x,p_y);
+
+	const Map<PosKey,Cell>::Element *E=tile_map.find(pk);
+
+	if (!E)
+		return false;
+
+	return E->get().transpose;
+}
 
 
 void TileMap::_recreate_quadrants() {
@@ -536,11 +551,12 @@ void TileMap::_set_tile_data(const DVector<int>& p_data) {
 		uint32_t v = decode_uint32(&local[4]);
 		bool flip_h = v&(1<<29);
 		bool flip_v = v&(1<<30);
+		bool transpose = v&(1<<31);
 		v&=(1<<29)-1;
 
 //		if (x<-20 || y <-20 || x>4000 || y>4000)
 //			continue;
-		set_cell(x,y,v,flip_h,flip_v);
+		set_cell(x,y,v,flip_h,flip_v,transpose);
 
 	}
 
@@ -563,6 +579,8 @@ DVector<int> TileMap::_get_tile_data() const {
 			val|=(1<<29);
 		if (E->get().flip_v)
 			val|=(1<<30);
+		if (E->get().transpose)
+			val|=(1<<31);
 
 		encode_uint32(val,&ptr[4]);
 		idx+=2;
@@ -829,7 +847,7 @@ void TileMap::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_collision_bounce","value"),&TileMap::set_collision_bounce);
 	ObjectTypeDB::bind_method(_MD("get_collision_bounce"),&TileMap::get_collision_bounce);
 
-	ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false));
+	ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y","transpose"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false),DEFVAL(false));
 	ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell);
 	ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped);
 	ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped);

+ 3 - 1
scene/2d/tile_map.h

@@ -86,6 +86,7 @@ private:
 			int32_t id:24;
 			bool flip_h:1;
 			bool flip_v:1;
+			bool transpose:1;
 		};
 
 		uint32_t _u32t;
@@ -168,10 +169,11 @@ public:
 	void set_center_y(bool p_enable);
 	bool get_center_y() const;
 
-	void set_cell(int p_x,int p_y,int p_tile,bool p_flip_x=false,bool p_flip_y=false);
+	void set_cell(int p_x,int p_y,int p_tile,bool p_flip_x=false,bool p_flip_y=false,bool p_transpose=false);
 	int get_cell(int p_x,int p_y) const;
 	bool is_cell_x_flipped(int p_x,int p_y) const;
 	bool is_cell_y_flipped(int p_x,int p_y) const;
+	bool is_cell_transposed(int p_x,int p_y) const;
 
 	Rect2 get_item_rect() const;
 

+ 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();
 };
 

+ 2 - 0
scene/gui/control.cpp

@@ -2267,8 +2267,10 @@ void Control::_window_sort_subwindows() {
 	if (!window->subwindow_order_dirty)
 		return;
 
+
 	window->modal_stack.sort_custom<CComparator>();
 	window->subwindows.sort_custom<CComparator>();
+
 	window->subwindow_order_dirty=false;
 
 }

+ 1 - 1
scene/gui/popup_menu.h

@@ -90,7 +90,7 @@ public:
 	void add_icon_check_item(const Ref<Texture>& p_icon,const String& p_label,int p_ID=-1,uint32_t p_accel=0);
 	void add_check_item(const String& p_label,int p_ID=-1,uint32_t p_accel=0);
 	void add_submenu_item(const String& p_label,const String& p_submenu, int p_ID=-1);
-	
+
 	void set_item_text(int p_idx,const String& p_text);
 	void set_item_icon(int p_idx,const Ref<Texture>& p_icon);
 	void set_item_checked(int p_idx,bool p_checked);	

+ 24 - 0
scene/main/viewport.cpp

@@ -972,6 +972,22 @@ bool Viewport::get_render_target_vflip() const{
 	return render_target_vflip;
 }
 
+void Viewport::set_render_target_clear_on_new_frame(bool p_enable) {
+
+	render_target_clear_on_new_frame=p_enable;
+	VisualServer::get_singleton()->viewport_set_render_target_clear_on_new_frame(viewport,p_enable);
+}
+
+bool Viewport::get_render_target_clear_on_new_frame() const{
+
+	return render_target_clear_on_new_frame;
+}
+
+void Viewport::render_target_clear() {
+
+	//render_target_clear=true;
+	VisualServer::get_singleton()->viewport_render_target_clear(viewport);
+}
 
 void Viewport::set_render_target_filter(bool p_enable) {
 
@@ -1264,6 +1280,11 @@ void Viewport::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("set_render_target_vflip","enable"), &Viewport::set_render_target_vflip);
 	ObjectTypeDB::bind_method(_MD("get_render_target_vflip"), &Viewport::get_render_target_vflip);
+	
+	ObjectTypeDB::bind_method(_MD("set_render_target_clear_on_new_frame","enable"), &Viewport::set_render_target_clear_on_new_frame);
+	ObjectTypeDB::bind_method(_MD("get_render_target_clear_on_new_frame"), &Viewport::get_render_target_clear_on_new_frame);
+	
+	ObjectTypeDB::bind_method(_MD("render_target_clear"), &Viewport::render_target_clear);
 
 	ObjectTypeDB::bind_method(_MD("set_render_target_filter","enable"), &Viewport::set_render_target_filter);
 	ObjectTypeDB::bind_method(_MD("get_render_target_filter"), &Viewport::get_render_target_filter);
@@ -1306,6 +1327,7 @@ void Viewport::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transparent_bg"), _SCS("set_transparent_background"), _SCS("has_transparent_background") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/enabled"), _SCS("set_as_render_target"), _SCS("is_set_as_render_target") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/v_flip"), _SCS("set_render_target_vflip"), _SCS("get_render_target_vflip") );
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/clear_on_new_frame"), _SCS("set_render_target_clear_on_new_frame"), _SCS("get_render_target_clear_on_new_frame") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/filter"), _SCS("set_render_target_filter"), _SCS("get_render_target_filter") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/gen_mipmaps"), _SCS("set_render_target_gen_mipmaps"), _SCS("get_render_target_gen_mipmaps") );
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"render_target/update_mode",PROPERTY_HINT_ENUM,"Disabled,Once,When Visible,Always"), _SCS("set_render_target_update_mode"), _SCS("get_render_target_update_mode") );
@@ -1344,6 +1366,8 @@ Viewport::Viewport() {
 	render_target_gen_mipmaps=false;
 	render_target=false;
 	render_target_vflip=false;
+	render_target_clear_on_new_frame=true;
+	//render_target_clear=true;
 	render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE;
 	render_target_texture = Ref<RenderTargetTexture>( memnew( RenderTargetTexture(this) ) );
 

+ 5 - 0
scene/main/viewport.h

@@ -114,6 +114,7 @@ friend class RenderTargetTexture;
 
 	bool transparent_bg;
 	bool render_target_vflip;
+	bool render_target_clear_on_new_frame;
 	bool render_target_filter;
 	bool render_target_gen_mipmaps;
 
@@ -220,6 +221,10 @@ public:
 	void set_render_target_vflip(bool p_enable);
 	bool get_render_target_vflip() const;
 
+	void set_render_target_clear_on_new_frame(bool p_enable);
+	bool get_render_target_clear_on_new_frame() const;
+	void render_target_clear();
+
 	void set_render_target_filter(bool p_enable);
 	bool get_render_target_filter() const;
 

+ 8 - 0
scene/register_scene_types.cpp

@@ -79,6 +79,8 @@
 #include "scene/resources/video_stream.h"
 #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"
@@ -103,6 +105,7 @@
 #include "scene/2d/remote_transform_2d.h"
 #include "scene/2d/y_sort.h"
 #include "scene/2d/navigation2d.h"
+#include "scene/2d/canvas_modulate.h"
 
 #include "scene/2d/position_2d.h"
 #include "scene/2d/tile_map.h"
@@ -263,6 +266,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_virtual_type<RenderTargetTexture>();
 	ObjectTypeDB::register_type<Timer>();
 	ObjectTypeDB::register_type<CanvasLayer>();
+	ObjectTypeDB::register_type<CanvasModulate>();
 	ObjectTypeDB::register_type<ResourcePreloader>();
 
 	/* REGISTER GUI */
@@ -451,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>();
@@ -472,6 +477,9 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<VisibilityNotifier2D>();
 	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);

+ 30 - 29
scene/resources/texture.cpp

@@ -38,19 +38,19 @@ Size2 Texture::get_size() const {
 }
 
 
-void Texture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const {
+void Texture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
 
-	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, get_size()),get_rid(),false,p_modulate);
+	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, get_size()),get_rid(),false,p_modulate,p_transpose);
 
 }
-void Texture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const {
+void Texture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
 
-	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,get_rid(),p_tile,p_modulate);
+	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,get_rid(),p_tile,p_modulate,p_transpose);
 
 }
-void Texture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const{
+void Texture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{
 
-	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,get_rid(),p_src_rect,p_modulate);
+	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,get_rid(),p_src_rect,p_modulate,p_transpose);
 }
 
 bool Texture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const {
@@ -70,9 +70,9 @@ void Texture::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("has_alpha"),&Texture::has_alpha);
 	ObjectTypeDB::bind_method(_MD("set_flags","flags"),&Texture::set_flags);
 	ObjectTypeDB::bind_method(_MD("get_flags"),&Texture::get_flags);
-	ObjectTypeDB::bind_method(_MD("draw","canvas_item","pos","modulate"),&Texture::draw,DEFVAL(Color(1,1,1)));
-	ObjectTypeDB::bind_method(_MD("draw_rect","canvas_item","rect","tile","modulate"),&Texture::draw_rect,DEFVAL(Color(1,1,1)));
-	ObjectTypeDB::bind_method(_MD("draw_rect_region","canvas_item","rect","src_rect","modulate"),&Texture::draw_rect_region,DEFVAL(Color(1,1,1)));
+	ObjectTypeDB::bind_method(_MD("draw","canvas_item","pos","modulate"),&Texture::draw,DEFVAL(Color(1,1,1)),DEFVAL(false));
+	ObjectTypeDB::bind_method(_MD("draw_rect","canvas_item","rect","tile","modulate"),&Texture::draw_rect,DEFVAL(Color(1,1,1)),DEFVAL(false));
+	ObjectTypeDB::bind_method(_MD("draw_rect_region","canvas_item","rect","src_rect","modulate"),&Texture::draw_rect_region,DEFVAL(Color(1,1,1)),DEFVAL(false));
 
 	BIND_CONSTANT( FLAG_MIPMAPS );
 	BIND_CONSTANT( FLAG_REPEAT );
@@ -327,28 +327,27 @@ bool ImageTexture::has_alpha() const {
 }
 
 
-void ImageTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const {
+void ImageTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
 
 	if ((w|h)==0)
 		return;
-	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate);
+	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate,p_transpose);
 
 }
-void ImageTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const {
+void ImageTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
 
 	if ((w|h)==0)
 		return;
-	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate);
+	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate,p_transpose);
 
 }
-void ImageTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const{
+void ImageTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{
 
 	if ((w|h)==0)
 		return;
-	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate);
+	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate,p_transpose);
 }
 
-
 void ImageTexture::set_size_override(const Size2& p_size) {
 
 	Size2 s=p_size;
@@ -546,7 +545,7 @@ void AtlasTexture::_bind_methods() {
 
 
 
-void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const {
+void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
 
 	Rect2 rc=region;
 
@@ -561,10 +560,10 @@ void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_m
 		rc.size.height=atlas->get_height();
 	}
 
-	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,Rect2(p_pos+margin.pos,rc.size),atlas->get_rid(),rc,p_modulate);
+	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,Rect2(p_pos+margin.pos,rc.size),atlas->get_rid(),rc,p_modulate,p_transpose);
 }
 
-void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const {
+void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
 
 	Rect2 rc=region;
 
@@ -582,10 +581,10 @@ void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,
 	Vector2 scale = p_rect.size / (region.size+margin.size);
 	Rect2 dr( p_rect.pos+margin.pos*scale,rc.size*scale  );
 
-	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),rc,p_modulate);
+	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),rc,p_modulate,p_transpose);
 
 }
-void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const {
+void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const {
 
 	//this might not necesarily work well if using a rect, needs to be fixed properly
 	Rect2 rc=region;
@@ -615,7 +614,7 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const
     }
 	Rect2 dr( p_rect.pos+ofs*scale,src_c.size*scale );
 
-	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),src_c,p_modulate);
+	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),src_c,p_modulate,p_transpose);
 }
 
 bool AtlasTexture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const {
@@ -801,15 +800,16 @@ void LargeTexture::_bind_methods() {
 
 
 
-void LargeTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const {
+void LargeTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {
 
 	for(int i=0;i<pieces.size();i++) {
 
-		pieces[i].texture->draw(p_canvas_item,pieces[i].offset+p_pos,p_modulate);
+		// TODO
+		pieces[i].texture->draw(p_canvas_item,pieces[i].offset+p_pos,p_modulate,p_transpose);
 	}
 }
 
-void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const {
+void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {
 
 	//tiling not supported for this
 	if (size.x==0 || size.y==0)
@@ -819,11 +819,11 @@ void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,
 
 	for(int i=0;i<pieces.size();i++) {
 
-		pieces[i].texture->draw_rect(p_canvas_item,Rect2(pieces[i].offset*scale+p_rect.pos,pieces[i].texture->get_size()*scale),false,p_modulate);
+		// TODO
+		pieces[i].texture->draw_rect(p_canvas_item,Rect2(pieces[i].offset*scale+p_rect.pos,pieces[i].texture->get_size()*scale),false,p_modulate,p_transpose);
 	}
-
 }
-void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const {
+void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const {
 
 
 	//tiling not supported for this
@@ -834,6 +834,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const
 
 	for(int i=0;i<pieces.size();i++) {
 
+		// TODO
 		Rect2 rect( pieces[i].offset, pieces[i].texture->get_size());
 		if (!p_src_rect.intersects(rect))
 			continue;
@@ -842,7 +843,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const
 		target.size*=scale;
 		target.pos=p_rect.pos+(p_src_rect.pos+rect.pos)*scale;
 		local.pos-=rect.pos;
-		pieces[i].texture->draw_rect_region(p_canvas_item,target,local,p_modulate);
+		pieces[i].texture->draw_rect_region(p_canvas_item,target,local,p_modulate,p_transpose);
 	}
 
 }

+ 12 - 13
scene/resources/texture.h

@@ -69,9 +69,9 @@ public:
 	virtual void set_flags(uint32_t p_flags)=0;
 	virtual uint32_t get_flags() const=0;
 
-	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const;
-	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const;
-	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const;
+	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
 	virtual bool get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const;
 
 
@@ -135,10 +135,9 @@ public:
 	virtual RID get_rid() const;
 	
 	bool has_alpha() const;
-	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const;
-	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const;
-	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const;
-
+	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
 	void set_storage(Storage p_storage);
 	Storage get_storage() const;
 
@@ -191,9 +190,9 @@ public:
 	void set_margin(const Rect2& p_margin);
 	Rect2 get_margin() const ;
 
-	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const;
-	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const;
-	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const;
+	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
 	virtual bool get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const;
 
 
@@ -241,9 +240,9 @@ public:
 	Vector2 get_piece_offset(int p_idx) const;
 	Ref<Texture> get_piece_texture(int p_idx) const;
 
-	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const;
-	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const;
-	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const;
+	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
+	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;
 
 
 	LargeTexture();

+ 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;

+ 109 - 9
servers/visual/rasterizer.h

@@ -564,7 +564,76 @@ public:
 		CANVAS_RECT_REGION=1,
 		CANVAS_RECT_TILE=2,
 		CANVAS_RECT_FLIP_H=4,
-		CANVAS_RECT_FLIP_V=8
+		CANVAS_RECT_FLIP_V=8,
+		CANVAS_RECT_TRANSPOSE=16
+	};
+
+
+	struct CanvasLight {
+
+
+
+		bool enabled;
+		Color color;
+		Matrix32 xform;
+		float height;
+		int z_min;
+		int z_max;
+		int layer_min;
+		int layer_max;
+		int item_mask;
+		bool subtract;
+		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;			
+			color=Color(1,1,1);
+			height=0;
+			z_min=-1024;
+			z_max=1024;
+			layer_min=0;
+			layer_max=0;
+			item_mask=1;
+			subtract=false;
+			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 {
@@ -689,25 +758,25 @@ public:
 		bool visible;
 		bool ontop;
 		VS::MaterialBlendMode blend_mode;
+		int light_mask;
 		Vector<Command*> commands;
 		mutable bool custom_rect;
 		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;
 
-		const Rect2& get_rect() const {
+		Rect2 global_rect_cache;
 
+		const Rect2& get_rect() const {
 			if (custom_rect || !rect_dirty)
 				return rect;
 
@@ -830,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() { 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(); }
 	};
 
@@ -853,9 +922,38 @@ public:
 	virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor)=0;
 	virtual void canvas_set_transform(const Matrix32& p_transform)=0;
 
-	virtual void canvas_render_items(CanvasItem *p_item_list)=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 */
 	
 
@@ -894,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;

+ 1 - 1
servers/visual/rasterizer_dummy.cpp

@@ -1622,7 +1622,7 @@ void RasterizerDummy::canvas_set_transform(const Matrix32& p_transform) {
 
 }
 
-void RasterizerDummy::canvas_render_items(CanvasItem *p_item_list) {
+void RasterizerDummy::canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light) {
 
 
 }

+ 1 - 1
servers/visual/rasterizer_dummy.h

@@ -710,7 +710,7 @@ public:
 	virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor);
 	virtual void canvas_set_transform(const Matrix32& p_transform);
 
-	virtual void canvas_render_items(CanvasItem *p_item_list);
+	virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light);
 
 	/* ENVIRONMENT */
 

+ 3 - 1
servers/visual/shader_language.cpp

@@ -2059,7 +2059,9 @@ Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_ex
 					at+=get_datatype_name(compute_node_type(op->arguments[i]));
 
 				}
-				parser.set_error("Invalid arguments to operator "+String(token_names[op->op])+": "+at);
+				static const char *op_names[OP_MAX]={"=","+","-","*","/","+=","-=","*=","/=","-","!","==","!=","<=",">=","<",">","||","&&","call","()"};
+
+				parser.set_error("Invalid arguments to operator "+String(op_names[op->op])+": "+at);
 				return ERR_PARSE_ERROR;
 			}
 			expression.remove(next_op);

+ 554 - 61
servers/visual/visual_server_raster.cpp

@@ -1576,6 +1576,15 @@ void VisualServerRaster::viewport_set_render_target_vflip(RID p_viewport,bool p_
 
 }
 
+void VisualServerRaster::viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable) {
+
+	Viewport *viewport = viewport_owner.get( p_viewport );
+	ERR_FAIL_COND(!viewport);
+
+	viewport->render_target_clear_on_new_frame=p_enable;
+
+}
+
 void VisualServerRaster::viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect) {
 
 	Viewport *viewport = viewport_owner.get( p_viewport );
@@ -1594,6 +1603,23 @@ bool VisualServerRaster::viewport_get_render_target_vflip(RID p_viewport) const{
 
 }
 
+bool VisualServerRaster::viewport_get_render_target_clear_on_new_frame(RID p_viewport) const{
+
+	const Viewport *viewport = viewport_owner.get( p_viewport );
+	ERR_FAIL_COND_V(!viewport,false);
+
+	return viewport->render_target_clear_on_new_frame;
+
+}
+
+void VisualServerRaster::viewport_render_target_clear(RID p_viewport) {
+
+	Viewport *viewport = viewport_owner.get( p_viewport );
+	ERR_FAIL_COND(!viewport);
+
+	viewport->render_target_clear=true;
+
+}
 
 void VisualServerRaster::viewport_queue_screen_capture(RID p_viewport) {
 
@@ -3195,6 +3221,7 @@ RID VisualServerRaster::canvas_create() {
 	return rid;
 }
 
+
 void VisualServerRaster::canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring) {
 
 	Canvas * canvas = canvas_owner.get(p_canvas);
@@ -3220,6 +3247,14 @@ Point2 VisualServerRaster::canvas_get_item_mirroring(RID p_canvas,RID p_item) co
 	return canvas->child_items[idx].mirror;
 }
 
+void VisualServerRaster::canvas_set_modulate(RID p_canvas,const Color& p_color) {
+
+	Canvas * canvas = canvas_owner.get(p_canvas);
+	ERR_FAIL_COND(!canvas);
+	canvas->modulate=p_color;
+}
+
+
 
 RID VisualServerRaster::canvas_item_create() {
 	
@@ -3305,14 +3340,27 @@ bool VisualServerRaster::canvas_item_is_visible(RID p_item) const {
 
 }
 
+void VisualServerRaster::canvas_item_set_light_mask(RID p_canvas_item,int p_mask) {
+
+	VS_CHANGED;
+
+	CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item );
+	ERR_FAIL_COND(!canvas_item);
+
+	if (canvas_item->light_mask==p_mask)
+		return;
+	VS_CHANGED;
+
+	canvas_item->light_mask=p_mask;
+
+}
+
+
 void VisualServerRaster::canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend) {
 
 	VS_CHANGED;
 
 	CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item );
-	if (!canvas_item) {
-		printf("!canvas_item\n");
-	};
 	ERR_FAIL_COND(!canvas_item);
 
 	if (canvas_item->blend_mode==p_blend)
@@ -3470,7 +3518,7 @@ void VisualServerRaster::canvas_item_add_circle(RID p_item, const Point2& p_pos,
 
 }
 
-void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile,const Color& p_modulate) {
+void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile,const Color& p_modulate,bool p_transpose) {
 	VS_CHANGED;
 	CanvasItem *canvas_item = canvas_item_owner.get( p_item );
 	ERR_FAIL_COND(!canvas_item);
@@ -3493,12 +3541,16 @@ void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p
 		rect->flags|=Rasterizer::CANVAS_RECT_FLIP_V;
 		rect->rect.size.y = -rect->rect.size.y;
 	}
+	if (p_transpose) {
+		rect->flags|=Rasterizer::CANVAS_RECT_TRANSPOSE;
+		SWAP(rect->rect.size.x, rect->rect.size.y);
+	}
 	rect->texture=p_texture;
 	canvas_item->rect_dirty=true;
 	canvas_item->commands.push_back(rect);
 }
 
-void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate)  {
+void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate,bool p_transpose)  {
 	VS_CHANGED;
 	CanvasItem *canvas_item = canvas_item_owner.get( p_item );
 	ERR_FAIL_COND(!canvas_item);
@@ -3521,12 +3573,17 @@ void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const R
 		rect->flags|=Rasterizer::CANVAS_RECT_FLIP_V;
 		rect->rect.size.y = -rect->rect.size.y;
 	}
+	if (p_transpose) {
+		rect->flags|=Rasterizer::CANVAS_RECT_TRANSPOSE;
+		SWAP(rect->rect.size.x, rect->rect.size.y);
+	}
 
 	canvas_item->rect_dirty=true;
 
 	canvas_item->commands.push_back(rect);	
 	
 }
+
 void VisualServerRaster::canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center,const Color& p_modulate) {
 
 	VS_CHANGED;
@@ -3708,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{
+	if (canvas_item->material)
+		canvas_item->material->owners.erase(canvas_item);
 
-	CanvasItem *canvas_item = canvas_item_owner.get( p_item );
-	ERR_FAIL_COND_V(!canvas_item,RID());
-	return canvas_item->shader;
+	canvas_item->material=NULL;
 
-}
-
-void VisualServerRaster::canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value){
-
-	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;
@@ -3823,60 +3857,150 @@ void VisualServerRaster::canvas_item_raise(RID p_item) {
 
 RID VisualServerRaster::canvas_light_create() {
 
-	return RID();
+	Rasterizer::CanvasLight *clight = memnew( Rasterizer::CanvasLight );
+	return canvas_light_owner.make_rid(clight);
 }
 
 void VisualServerRaster::canvas_light_attach_to_canvas(RID p_light,RID p_canvas){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+
+	if (clight->canvas.is_valid()) {
+
+		Canvas *canvas = canvas_owner.get(clight->canvas);
+		canvas->lights.erase(clight);
+	}
+
+	if (!canvas_owner.owns(p_canvas))
+		p_canvas=RID();
+	clight->canvas=p_canvas;
+
+	if (clight->canvas.is_valid()) {
+
+		Canvas *canvas = canvas_owner.get(clight->canvas);
+		canvas->lights.insert(clight);
+	}
+
+
 
 }
 void VisualServerRaster::canvas_light_set_enabled(RID p_light, bool p_enabled){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->enabled=p_enabled;
 
 }
 void VisualServerRaster::canvas_light_set_transform(RID p_light, const Matrix32& p_transform){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->xform=p_transform;
 
 }
 void VisualServerRaster::canvas_light_set_texture(RID p_light, RID p_texture){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->texture=p_texture;
 
 }
 void VisualServerRaster::canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->texture_offset=p_offset;
 
 }
 void VisualServerRaster::canvas_light_set_color(RID p_light, const Color& p_color){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->color=p_color;
+
 
 }
 void VisualServerRaster::canvas_light_set_height(RID p_light, float p_height){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->height=p_height;
 
 }
 void VisualServerRaster::canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->z_min=p_min_z;
+	clight->z_max=p_max_z;
+
+}
+
+void VisualServerRaster::canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer) {
+
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->layer_min=p_min_layer;
+	clight->layer_max=p_max_layer;
 
 }
+
 void VisualServerRaster::canvas_light_set_item_mask(RID p_light, int p_mask){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->item_mask=p_mask;
 
 }
 
-void VisualServerRaster::canvas_light_set_blend_mode(RID p_light, CanvasLightBlendMode p_blend_mode){
+void VisualServerRaster::canvas_light_set_subtract_mode(RID p_light, bool p_enable) {
 
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+	clight->subtract=p_enable;
+
 }
 void VisualServerRaster::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
+
+	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;
 
 }
 
@@ -3884,24 +4008,215 @@ 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_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_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape){
+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 *********/
@@ -4154,7 +4469,17 @@ void VisualServerRaster::free( RID p_rid ) {
 
 			canvas->child_items[i].item->parent=RID();
 		}
-		
+
+		for (Set<Rasterizer::CanvasLight*>::Element *E=canvas->lights.front();E;E=E->next()) {
+
+			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 );
 		
 		memdelete( canvas );
@@ -4183,9 +4508,75 @@ 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);
+		ERR_FAIL_COND(!canvas_light);
+
+		if (canvas_light->canvas.is_valid()) {
+			Canvas* canvas = canvas_owner.get(canvas_light->canvas);
+			if (canvas)
+				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);
@@ -6231,7 +6622,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 }
 
 
-void VisualServerRaster::_render_canvas_item_tree(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect) {
+void VisualServerRaster::_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) {
 
 
 	static const int z_range = CANVAS_ITEM_Z_MAX-CANVAS_ITEM_Z_MIN+1;
@@ -6249,7 +6640,7 @@ void VisualServerRaster::_render_canvas_item_tree(CanvasItem *p_canvas_item,cons
 	for(int i=0;i<z_range;i++) {
 		if (!z_list[i])
 			continue;
-		rasterizer->canvas_render_items(z_list[i]);
+		rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_modulate,p_lights);
 	}
 
 }
@@ -6264,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;
 
@@ -6309,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;
 	}
 
 
@@ -6347,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);
 	}
 
 
@@ -6355,7 +6746,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 		//something to draw?
 		ci->final_transform=xform;
 		ci->final_opacity=opacity * ci->self_opacity;
-
+		ci->global_rect_cache=global_rect;
 
 		int zidx = p_z-CANVAS_ITEM_Z_MIN;
 
@@ -6368,6 +6759,8 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 			z_last_list[zidx]=ci;
 		}
 
+
+
 		ci->next=NULL;
 
 	}
@@ -6376,12 +6769,12 @@ 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);
 	}
 
 }
 
-void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform) {
+void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights) {
 
 	rasterizer->canvas_begin();
 
@@ -6414,30 +6807,30 @@ void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_trans
 		for(int i=0;i<z_range;i++) {
 			if (!z_list[i])
 				continue;
-			rasterizer->canvas_render_items(z_list[i]);
+			rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_canvas->modulate,p_lights);
 		}
 	} else {
 
 		for(int i=0;i<l;i++) {
 
 			Canvas::ChildItem& ci=p_canvas->child_items[i];
-			_render_canvas_item_tree(ci.item,p_transform,clip_rect);
+			_render_canvas_item_tree(ci.item,p_transform,clip_rect,p_canvas->modulate,p_lights);
 
 			//mirroring (useful for scrolling backgrounds)
 			if (ci.mirror.x!=0) {
 
 				Matrix32 xform2 = p_transform * Matrix32(0,Vector2(ci.mirror.x,0));
-				_render_canvas_item_tree(ci.item,xform2,clip_rect);
+				_render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);
 			}
 			if (ci.mirror.y!=0) {
 
 				Matrix32 xform2 = p_transform * Matrix32(0,Vector2(0,ci.mirror.y));
-				_render_canvas_item_tree(ci.item,xform2,clip_rect);
+				_render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);
 			}
 			if (ci.mirror.y!=0 && ci.mirror.x!=0) {
 
 				Matrix32 xform2 = p_transform * Matrix32(0,ci.mirror);
-				_render_canvas_item_tree(ci.item,xform2,clip_rect);
+				_render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);
 			}
 
 		}
@@ -6492,7 +6885,15 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 	} else if (true /*|| !p_viewport->canvas_list.empty()*/){
 
 		//clear the viewport black because of no camera? i seriously should..
-		rasterizer->clear_viewport(clear_color);
+		if (p_viewport->render_target_clear_on_new_frame || p_viewport->render_target_clear) {
+			if (p_viewport->transparent_bg) {
+				rasterizer->clear_viewport(Color(0,0,0,0));
+			}
+			else {
+				rasterizer->clear_viewport(clear_color);
+			}
+			p_viewport->render_target_clear=false;
+		}
 	}
 
 	if (!p_viewport->hide_canvas) {
@@ -6500,21 +6901,113 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 
 		Map<Viewport::CanvasKey,Viewport::CanvasData*> canvas_map;
 
+		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()) {
+
+			Matrix32 xf = p_viewport->global_transform * E->get().transform;
+
+			//find lights in canvas
+
+
+			for(Set<Rasterizer::CanvasLight*>::Element *F=E->get().canvas->lights.front();F;F=F->next()) {
+
+				Rasterizer::CanvasLight* cl=F->get();
+				if (cl->enabled && cl->texture.is_valid()) {
+					//not super efficient..
+					Size2 tsize(rasterizer->texture_get_width(cl->texture),rasterizer->texture_get_height(cl->texture));
+					Vector2 offset=tsize/2.0;
+					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;
+						cl->texture_cache=NULL;
+						Matrix32 scale;
+						scale.scale(cl->rect_cache.size);
+						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) {
+
+				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()) {
 
 
 	//		print_line("canvas "+itos(i)+" size: "+itos(I->get()->canvas->child_items.size()));
 			//print_line("GT "+p_viewport->global_transform+". CT: "+E->get()->transform);
 			Matrix32 xform = p_viewport->global_transform * E->get()->transform;
-			_render_canvas( E->get()->canvas,xform );
+
+			Rasterizer::CanvasLight *canvas_lights=NULL;
+
+			Rasterizer::CanvasLight *ptr=lights;
+			while(ptr) {
+				if (E->get()->layer>=ptr->layer_min && E->get()->layer<=ptr->layer_max) {
+					ptr->next_ptr=canvas_lights;
+					canvas_lights=ptr;
+				}
+				ptr=ptr->filter_next_ptr;
+			}
+
+			_render_canvas( E->get()->canvas,xform,canvas_lights );
 			i++;
 
 		}
+
+		rasterizer->canvas_debug_viewport_shadows(lights_with_shadow);
 	}
 
 	//capture

+ 69 - 33
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,26 @@ 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 {
 
 		Set<RID> viewports;
@@ -419,8 +439,11 @@ class VisualServerRaster : public VisualServer {
 			CanvasItem *item;
 		};
 
+		Set<Rasterizer::CanvasLight*> lights;
+		Set<Rasterizer::CanvasLightOccluderInstance*> occluders;
 
 		Vector<ChildItem> child_items;
+		Color modulate;
 
 		int find_item(CanvasItem *p_item) {
 			for(int i=0;i<child_items.size();i++) {
@@ -435,11 +458,13 @@ class VisualServerRaster : public VisualServer {
 				child_items.remove(idx);
 		}
 
-		Canvas() {  }
+		Canvas() { modulate=Color(1,1,1,1); }
 		
 	};
 
 
+	RID_Owner<Rasterizer::CanvasLight> canvas_light_owner;
+
 
 	struct Viewport {
 
@@ -462,6 +487,8 @@ class VisualServerRaster : public VisualServer {
 		bool transparent_bg;
 		bool queue_capture;
 		bool render_target_vflip;
+		bool render_target_clear_on_new_frame;
+		bool render_target_clear;
 		Image capture;
 
 		bool rendered_in_prev_frame;
@@ -488,7 +515,7 @@ class VisualServerRaster : public VisualServer {
 
 		SelfList<Viewport> update_list;
 
-		Viewport() : update_list(this) { transparent_bg=false; render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; queue_capture=false; rendered_in_prev_frame=false; render_target_vflip=false;}
+		Viewport() : update_list(this) { transparent_bg=false; render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; queue_capture=false; rendered_in_prev_frame=false; render_target_vflip=false; render_target_clear_on_new_frame=true; render_target_clear=true;}
 	};
 
 	SelfList<Viewport>::List viewport_update_list;
@@ -601,9 +628,9 @@ 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);
-	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(Canvas *p_canvas,const Matrix32 &p_transform);
+	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_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);
 
@@ -951,6 +978,9 @@ public:
 	virtual RID viewport_get_render_target_texture(RID p_viewport) const;
 	virtual void viewport_set_render_target_vflip(RID p_viewport,bool p_enable);
 	virtual bool viewport_get_render_target_vflip(RID p_viewport) const;
+	virtual void viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable);
+	virtual bool viewport_get_render_target_clear_on_new_frame(RID p_viewport) const;
+	virtual void viewport_render_target_clear(RID p_viewport);
 	virtual void viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect);
 
 	virtual void viewport_queue_screen_capture(RID p_viewport);
@@ -1073,6 +1103,8 @@ public:
 	virtual RID canvas_create();
 	virtual void canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring);
 	virtual Point2 canvas_get_item_mirroring(RID p_canvas,RID p_item) const;
+	virtual void canvas_set_modulate(RID p_canvas,const Color& p_color);
+
 
 	virtual RID canvas_item_create();
 
@@ -1083,6 +1115,8 @@ public:
 	virtual bool canvas_item_is_visible(RID p_item) const;
 
 	virtual void canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend);
+	virtual void canvas_item_set_light_mask(RID p_canvas_item,int p_mask);
+
 
 
 	//virtual void canvas_item_set_rect(RID p_item, const Rect2& p_rect);
@@ -1102,8 +1136,8 @@ public:
 	virtual void canvas_item_add_line(RID p_item, const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0);
 	virtual void canvas_item_add_rect(RID p_item, const Rect2& p_rect, const Color& p_color);
 	virtual void canvas_item_add_circle(RID p_item, const Point2& p_pos, float p_radius,const Color& p_color);
-	virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1));
-	virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1));
+	virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1),bool p_transpose=false);
+	virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1),bool p_transpose=false);
 	virtual void canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center=true,const Color& p_modulate=Color(1,1,1));
 	virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width=1.0);
 	virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), RID p_texture=RID());
@@ -1116,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);
@@ -1135,33 +1162,42 @@ public:
 	virtual void canvas_light_set_color(RID p_light, const Color& p_color);
 	virtual void canvas_light_set_height(RID p_light, float p_height);
 	virtual void canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z);
+	virtual void canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer);
 	virtual void canvas_light_set_item_mask(RID p_light, int p_mask);
 
-	enum CanvasightBlendMode {
-		CANVAS_LIGHT_BLEND_ADD,
-		CANVAS_LIGHT_BLEND_SUB,
-		CANVAS_LIGHT_BLEND_MULTIPLY,
-		CANVAS_LIGHT_BLEND_DODGE,
-		CANVAS_LIGHT_BLEND_BURN,
-		CANVAS_LIGHT_BLEND_LIGHTEN,
-		CANVAS_LIGHT_BLEND_DARKEN,
-		CANVAS_LIGHT_BLEND_OVERLAY,
-		CANVAS_LIGHT_BLEND_SCREEN,
-	};
-	virtual void canvas_light_set_blend_mode(RID p_light, CanvasLightBlendMode p_blend_mode);
+	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);

+ 32 - 14
servers/visual/visual_server_wrap_mt.h

@@ -967,6 +967,10 @@ public:
 	FUNC2(viewport_set_render_target_vflip,RID,bool);
 	FUNC1RC(bool,viewport_get_render_target_vflip,RID);
 	FUNC2(viewport_set_render_target_to_screen_rect,RID,const Rect2&);
+	
+	FUNC2(viewport_set_render_target_clear_on_new_frame,RID,bool);
+	FUNC1RC(bool,viewport_get_render_target_clear_on_new_frame,RID);
+	FUNC1(viewport_render_target_clear,RID);
 
 	FUNC1(viewport_queue_screen_capture,RID);
 	FUNC1RC(Image,viewport_get_screen_capture,RID);
@@ -1087,6 +1091,8 @@ public:
 	FUNC0R(RID,canvas_create);
 	FUNC3(canvas_set_item_mirroring,RID,RID,const Point2&);
 	FUNC2RC(Point2,canvas_get_item_mirroring,RID,RID);
+	FUNC2(canvas_set_modulate,RID,const Color&);
+
 
 	FUNC0R(RID,canvas_item_create);
 
@@ -1097,7 +1103,7 @@ public:
 	FUNC1RC(bool,canvas_item_is_visible,RID);
 
 	FUNC2(canvas_item_set_blend_mode,RID,MaterialBlendMode );
-
+	FUNC2(canvas_item_set_light_mask,RID,int );
 
 	//FUNC(canvas_item_set_rect,RID, const Rect2& p_rect);
 	FUNC2(canvas_item_set_transform,RID, const Matrix32& );
@@ -1116,9 +1122,8 @@ public:
 	FUNC5(canvas_item_add_line,RID, const Point2& , const Point2& ,const Color& ,float );
 	FUNC3(canvas_item_add_rect,RID, const Rect2& , const Color& );
 	FUNC4(canvas_item_add_circle,RID, const Point2& , float ,const Color& );
-	FUNC5(canvas_item_add_texture_rect,RID, const Rect2& , RID ,bool ,const Color& );
-	FUNC5(canvas_item_add_texture_rect_region,RID, const Rect2& , RID ,const Rect2& ,const Color& );
-
+	FUNC6(canvas_item_add_texture_rect,RID, const Rect2& , RID ,bool ,const Color&,bool );
+	FUNC6(canvas_item_add_texture_rect_region,RID, const Rect2& , RID ,const Rect2& ,const Color&,bool );
 	FUNC7(canvas_item_add_style_box,RID, const Rect2& , RID ,const Vector2& ,const Vector2&, bool ,const Color& );
 	FUNC6(canvas_item_add_primitive,RID, const Vector<Point2>& , const Vector<Color>& ,const Vector<Point2>& , RID ,float );
 	FUNC5(canvas_item_add_polygon,RID, const Vector<Point2>& , const Vector<Color>& ,const Vector<Point2>& , RID );
@@ -1134,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_use_parent_shader,RID, bool );
-
+	FUNC2(canvas_item_set_material,RID, RID );
 
-	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);
@@ -1155,20 +1155,38 @@ public:
 	FUNC2(canvas_light_set_texture_offset,RID,const Vector2&);
 	FUNC2(canvas_light_set_color,RID,const Color&);
 	FUNC2(canvas_light_set_height,RID,float);
+	FUNC3(canvas_light_set_layer_range,RID,int,int);
 	FUNC3(canvas_light_set_z_range,RID,int,int);
 	FUNC2(canvas_light_set_item_mask,RID,int);
 
-	FUNC2(canvas_light_set_blend_mode,RID,CanvasLightBlendMode);
+	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

+ 4 - 2
servers/visual_server.cpp

@@ -28,6 +28,7 @@
 /*************************************************************************/
 #include "visual_server.h"
 #include "globals.h"
+#include "method_bind_ext.inc"
 
 VisualServer *VisualServer::singleton=NULL;
 VisualServer* (*VisualServer::create_func)()=NULL;
@@ -510,8 +511,9 @@ void VisualServer::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("canvas_item_add_line"),&VisualServer::canvas_item_add_line, DEFVAL(1.0));
 	ObjectTypeDB::bind_method(_MD("canvas_item_add_rect"),&VisualServer::canvas_item_add_rect);
-	ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect"),&VisualServer::canvas_item_add_texture_rect, DEFVAL(Color(1,1,1)));
-	ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect_region"),&VisualServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1,1,1)));
+	ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect"),&VisualServer::canvas_item_add_texture_rect, DEFVAL(Color(1,1,1)), DEFVAL(false));
+	ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect_region"),&VisualServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1,1,1)), DEFVAL(false));
+
 	ObjectTypeDB::bind_method(_MD("canvas_item_add_style_box"),&VisualServer::_canvas_item_add_style_box, DEFVAL(Color(1,1,1)));
 //	ObjectTypeDB::bind_method(_MD("canvas_item_add_primitive"),&VisualServer::canvas_item_add_primitive,DEFVAL(Vector<Vector2>()),DEFVAL(RID()));
 	ObjectTypeDB::bind_method(_MD("canvas_item_add_circle"),&VisualServer::canvas_item_add_circle);

+ 36 - 22
servers/visual_server.h

@@ -684,6 +684,9 @@ public:
 	virtual RID viewport_get_render_target_texture(RID p_viewport) const=0;
 	virtual void viewport_set_render_target_vflip(RID p_viewport,bool p_enable)=0;
 	virtual bool viewport_get_render_target_vflip(RID p_viewport) const=0;
+	virtual void viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable)=0;
+	virtual bool viewport_get_render_target_clear_on_new_frame(RID p_viewport) const=0;
+	virtual void viewport_render_target_clear(RID p_viewport)=0;
 
 	virtual void viewport_queue_screen_capture(RID p_viewport)=0;
 	virtual Image viewport_get_screen_capture(RID p_viewport) const=0;
@@ -944,6 +947,8 @@ public:
 	virtual RID canvas_create()=0;
 	virtual void canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring)=0;
 	virtual Point2 canvas_get_item_mirroring(RID p_canvas,RID p_item) const=0;
+	virtual void canvas_set_modulate(RID p_canvas,const Color& p_color)=0;
+
 
 
 	virtual RID canvas_item_create()=0;
@@ -953,6 +958,8 @@ public:
 	virtual void canvas_item_set_visible(RID p_item,bool p_visible)=0;
 	virtual bool canvas_item_is_visible(RID p_item) const=0;
 
+	virtual void canvas_item_set_light_mask(RID p_item,int p_mask)=0;
+
 	virtual void canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend)=0;
 
 	virtual void canvas_item_attach_viewport(RID p_item, RID p_viewport)=0;
@@ -974,8 +981,8 @@ public:
 	virtual void canvas_item_add_line(RID p_item, const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0)=0;
 	virtual void canvas_item_add_rect(RID p_item, const Rect2& p_rect, const Color& p_color)=0;
 	virtual void canvas_item_add_circle(RID p_item, const Point2& p_pos, float p_radius,const Color& p_color)=0;
-	virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1))=0;
-	virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1))=0;
+	virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1),bool p_transpose=false)=0;
+	virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1),bool p_transpose=false)=0;
 	virtual void canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center=true,const Color& p_modulate=Color(1,1,1))=0;
 	virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width=1.0)=0;
 	virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), RID p_texture=RID())=0;
@@ -991,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;
@@ -1008,29 +1011,40 @@ public:
 	virtual void canvas_light_set_color(RID p_light, const Color& p_color)=0;
 	virtual void canvas_light_set_height(RID p_light, float p_height)=0;
 	virtual void canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z)=0;
+	virtual void canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer)=0;
 	virtual void canvas_light_set_item_mask(RID p_light, int p_mask)=0;
 
-	enum CanvasLightBlendMode {
-		CANVAS_LIGHT_BLEND_ADD,
-		CANVAS_LIGHT_BLEND_SUB,
-		CANVAS_LIGHT_BLEND_MULTIPLY,
-		CANVAS_LIGHT_BLEND_DODGE,
-		CANVAS_LIGHT_BLEND_BURN,
-		CANVAS_LIGHT_BLEND_LIGHTEN,
-		CANVAS_LIGHT_BLEND_DARKEN,
-		CANVAS_LIGHT_BLEND_OVERLAY,
-		CANVAS_LIGHT_BLEND_SCREEN,
-	};
-	virtual void canvas_light_set_blend_mode(RID p_light, CanvasLightBlendMode p_blend_mode)=0;
+	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

+ 1 - 1
tools/collada/collada.cpp

@@ -817,7 +817,7 @@ void Collada::_parse_camera(XMLParser& parser) {
 			if (name=="perspective") {
 
 				camera.mode=CameraData::MODE_PERSPECTIVE;
-			} else if (name=="orthogonal") {
+			} else if (name=="orthographic") {
 
 				camera.mode=CameraData::MODE_ORTHOGONAL;
 			} else if (name=="xfov") {

+ 18 - 0
tools/collada/collada.h

@@ -337,6 +337,24 @@ public:
 					if(normal==p_vert.normal) {
 						if(uv==p_vert.uv) {
 							if(uv2==p_vert.uv2) {
+
+								if (!weights.empty() || !p_vert.weights.empty()) {
+
+									if (weights.size()==p_vert.weights.size()) {
+
+										for(int i=0;i<weights.size();i++) {
+											if (weights[i].bone_idx!=p_vert.weights[i].bone_idx)
+												return weights[i].bone_idx<p_vert.weights[i].bone_idx;
+
+											if (weights[i].weight!=p_vert.weights[i].weight)
+												return weights[i].weight<p_vert.weights[i].weight;
+										}
+									}  else {
+										return weights.size() < p_vert.weights.size();
+									}
+
+								}
+
 								return (color<p_vert.color);
 							} else
 								return (uv2<p_vert.uv2);

+ 28 - 2
tools/editor/editor_import_export.cpp

@@ -904,6 +904,16 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
 	return OK;
 }
 
+static int _get_pad(int p_alignment, int p_n) {
+
+	int rest = p_n % p_alignment;
+	int pad = 0;
+	if (rest > 0) {
+		pad = p_alignment - rest;
+	};
+
+	return pad;
+};
 
 Error EditorExportPlatform::save_pack_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total) {
 
@@ -930,11 +940,19 @@ Error EditorExportPlatform::save_pack_file(void *p_userdata,const String& p_path
 	pd->ep->step("Storing File: "+p_path,2+p_file*100/p_total);
 	pd->count++;
 	pd->ftmp->store_buffer(p_data.ptr(),p_data.size());
+	if (pd->alignment > 1) {
+
+		int pad = _get_pad(pd->alignment, pd->ftmp->get_pos());
+		for (int i=0; i<pad; i++) {
+
+			pd->ftmp->store_8(0);
+		};
+	};
 	return OK;
 
 }
 
-Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles) {
+Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles, int p_alignment) {
 
 	EditorProgress ep("savepack","Packing",102);
 
@@ -952,7 +970,6 @@ Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles) {
 		dst->store_32(0);
 	}
 
-
 	size_t fcountpos = dst->get_pos();
 	dst->store_32(0);
 
@@ -961,11 +978,20 @@ Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles) {
 	pd.f=dst;
 	pd.ftmp=tmp;
 	pd.count=0;
+	pd.alignment = p_alignment;
 	Error err = export_project_files(save_pack_file,&pd,p_make_bundles);
 	memdelete(tmp);
 	if (err)
 		return err;
 
+	if (p_alignment > 1) {
+		int pad = _get_pad(p_alignment, dst->get_pos());
+		for (int i=0; i<pad; i++) {
+
+			dst->store_8(0);
+		};
+	};
+
 	size_t ofsplus = dst->get_pos();
 	//append file
 

+ 2 - 1
tools/editor/editor_import_export.h

@@ -100,6 +100,7 @@ protected:
 		Vector<TempData> file_ofs;
 		EditorProgress *ep;
 		int count;
+		int alignment;
 
 	};
 
@@ -121,7 +122,7 @@ public:
 
 	Error export_project_files(EditorExportSaveFunction p_func, void* p_udata,bool p_make_bundles);
 
-	Error save_pack(FileAccess *p_where, bool p_make_bundles=false);
+	Error save_pack(FileAccess *p_where, bool p_make_bundles=false, int p_alignment = 1);
 	virtual String get_name() const =0;
 	virtual ImageCompression get_image_compression() const=0;
 	virtual Ref<Texture> get_logo() const =0;

+ 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_2d.png


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


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


二進制
tools/editor/icons/icon_rotate_0.png


二進制
tools/editor/icons/icon_rotate_180.png


二進制
tools/editor/icons/icon_rotate_270.png


二進制
tools/editor/icons/icon_rotate_90.png


二進制
tools/editor/icons/icon_transpose.png


+ 7 - 4
tools/editor/io_plugins/editor_import_collada.cpp

@@ -285,13 +285,16 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
 
 					case Collada::CameraData::MODE_ORTHOGONAL: {
 
-						if (cd.orthogonal.x_mag) {
+						if (cd.orthogonal.y_mag) {
 
-							camera->set_orthogonal(cd.orthogonal.x_mag,cd.z_near,cd.z_far);
+							camera->set_keep_aspect_mode(Camera::KEEP_HEIGHT);
+							camera->set_orthogonal(cd.orthogonal.y_mag*2.0 ,cd.z_near,cd.z_far);
 
-						} else if (!cd.orthogonal.x_mag && cd.orthogonal.y_mag) {
+						} else if (!cd.orthogonal.y_mag && cd.orthogonal.x_mag) {
 
-							camera->set_orthogonal(cd.orthogonal.y_mag * cd.aspect,cd.z_near,cd.z_far);
+
+							camera->set_keep_aspect_mode(Camera::KEEP_WIDTH);
+							camera->set_orthogonal(cd.orthogonal.x_mag*2.0,cd.z_near,cd.z_far);
 						}
 
 					} break;

+ 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

+ 127 - 19
tools/editor/plugins/tile_map_editor_plugin.cpp

@@ -34,7 +34,7 @@
 #include "os/file_access.h"
 #include "tools/editor/editor_settings.h"
 #include "os/input.h"
-
+#include "method_bind_ext.inc"
 
 void TileMapEditor::_notification(int p_what) {
 
@@ -42,8 +42,13 @@ void TileMapEditor::_notification(int p_what) {
 
 		case NOTIFICATION_READY: {
 
+			transpose->set_icon( get_icon("Transpose","EditorIcons"));
 			mirror_x->set_icon( get_icon("MirrorX","EditorIcons"));
 			mirror_y->set_icon( get_icon("MirrorY","EditorIcons"));
+			rotate_0->set_icon( get_icon("Rotate0","EditorIcons"));
+			rotate_90->set_icon( get_icon("Rotate90","EditorIcons"));
+			rotate_180->set_icon( get_icon("Rotate180","EditorIcons"));
+			rotate_270->set_icon( get_icon("Rotate270","EditorIcons"));
 
 		} break;
 	}
@@ -85,24 +90,31 @@ void TileMapEditor::set_selected_tile(int p_tile) {
 	}
 }
 
-void TileMapEditor::_set_cell(const Point2i& p_pos,int p_value,bool p_flip_h, bool p_flip_v,bool p_with_undo) {
+// Wrapper to workaround five arg limit of undo/redo methods
+void TileMapEditor::_set_cell_shortened(const Point2& p_pos,int p_value,bool p_flip_h, bool p_flip_v, bool p_transpose) {
+	ERR_FAIL_COND(!node);
+	node->set_cell(floor(p_pos.x), floor(p_pos.y), p_value, p_flip_h, p_flip_v, p_transpose);
+}
+	
+void TileMapEditor::_set_cell(const Point2i& p_pos,int p_value,bool p_flip_h, bool p_flip_v, bool p_transpose,bool p_with_undo) {
 
 	ERR_FAIL_COND(!node);
 
 	bool prev_flip_h=node->is_cell_x_flipped(p_pos.x,p_pos.y);
 	bool prev_flip_v=node->is_cell_y_flipped(p_pos.x,p_pos.y);
+	bool prev_transpose=node->is_cell_transposed(p_pos.x,p_pos.y);
 	int prev_val=node->get_cell(p_pos.x,p_pos.y);
 
-	if (p_value==prev_val && p_flip_h==prev_flip_h && p_flip_v==prev_flip_v)
+	if (p_value==prev_val && p_flip_h==prev_flip_h && p_flip_v==prev_flip_v && p_transpose==prev_transpose)
 		return; //check that it's actually different
 
 
 	if (p_with_undo) {
-		undo_redo->add_do_method(node,"set_cell",p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v);
-		undo_redo->add_undo_method(node,"set_cell",p_pos.x,p_pos.y,prev_val,prev_flip_h,prev_flip_v);
+		undo_redo->add_do_method(this,"_set_cell_shortened",Point2(p_pos),p_value,p_flip_h,p_flip_v,p_transpose);
+		undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p_pos),prev_val,prev_flip_h,prev_flip_v,prev_transpose);
 	} else {
 
-		node->set_cell(p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v);
+		node->set_cell(p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v,p_transpose);
 
 	}
 
@@ -168,6 +180,7 @@ struct _TileMapEditorCopyData {
 	int cell;
 	bool flip_h;
 	bool flip_v;
+	bool transpose;
 };
 
 bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
@@ -204,6 +217,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 							tcd.cell=node->get_cell(j,i);
 							tcd.flip_h=node->is_cell_x_flipped(j,i);
 							tcd.flip_v=node->is_cell_y_flipped(j,i);
+							tcd.transpose=node->is_cell_transposed(j,i);
 							dupdata.push_back(tcd);
 
 
@@ -214,7 +228,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 					for (List<_TileMapEditorCopyData>::Element *E=dupdata.front();E;E=E->next()) {
 
 
-						_set_cell(E->get().pos+ofs,E->get().cell,E->get().flip_h,E->get().flip_v,true);
+						_set_cell(E->get().pos+ofs,E->get().cell,E->get().flip_h,E->get().flip_v,E->get().transpose,true);
 					}
 					undo_redo->commit_action();
 
@@ -239,6 +253,10 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 					} else if (mb.mod.control) {
 						tool=TOOL_PICKING;
 						set_selected_tile(node->get_cell(over_tile.x, over_tile.y));
+						mirror_x->set_pressed(node->is_cell_x_flipped(over_tile.x, over_tile.y));
+						mirror_y->set_pressed(node->is_cell_y_flipped(over_tile.x, over_tile.y));
+						transpose->set_pressed(node->is_cell_transposed(over_tile.x, over_tile.y));
+						_update_transform_buttons();
 						canvas_item_editor->update();
 						return true;
 					} else {
@@ -248,7 +266,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 							Point2i local =node->world_to_map((xform_inv.xform(Point2(mb.x,mb.y))));
 							paint_undo.clear();
 							paint_undo[local]=_get_op_from_cell(local);
-							node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed());
+							node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());
 							return true;
 						}
 					}
@@ -263,8 +281,8 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 								for(Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {
 
 									Point2i p=E->key();
-									undo_redo->add_do_method(node,"set_cell",p.x,p.y,node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y));
-									undo_redo->add_undo_method(node,"set_cell",p.x,p.y,E->get().idx,E->get().xf,E->get().yf);
+									undo_redo->add_do_method(this,"_set_cell_shortened",Point2(p),node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y),node->is_cell_transposed(p.x,p.y));
+									undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p),E->get().idx,E->get().xf,E->get().yf,E->get().tr);
 								}
 
 								undo_redo->commit_action();
@@ -289,7 +307,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 					Point2i local =node->world_to_map(xform_inv.xform(Point2(mb.x,mb.y)));
 					paint_undo.clear();
 					paint_undo[local]=_get_op_from_cell(local);
-					//node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed());
+					//node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());
 					//return true;
 					_set_cell(local,TileMap::INVALID_CELL);
 					return true;
@@ -302,9 +320,9 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 							for(Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {
 
 								Point2i p=E->key();
-								//undo_redo->add_do_method(node,"set_cell",p.x,p.y,node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y));
-								_set_cell(p,TileMap::INVALID_CELL,false,false,true);
-								undo_redo->add_undo_method(node,"set_cell",p.x,p.y,E->get().idx,E->get().xf,E->get().yf);
+								//undo_redo->add_do_method(node,"set_cell",p.x,p.y,node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y),node->is_cell_transposed(p.x,p.y));
+								_set_cell(p,TileMap::INVALID_CELL,false,false,false,true);
+								undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p),E->get().idx,E->get().xf,E->get().yf,E->get().tr);
 							}
 
 							undo_redo->commit_action();
@@ -340,7 +358,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 
 						paint_undo[over_tile]=_get_op_from_cell(over_tile);
 					}
-					node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed());
+					node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());
 
 					return true;
 				}
@@ -373,13 +391,17 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
 				if (!paint_undo.has(over_tile)) {
 					paint_undo[over_tile]=_get_op_from_cell(over_tile);
 				}
-				//node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed());
+				//node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());
 				_set_cell(local,TileMap::INVALID_CELL);
 				return true;
 			}
 
 			if (tool==TOOL_PICKING) {
 				set_selected_tile(node->get_cell(over_tile.x, over_tile.y));
+				mirror_x->set_pressed(node->is_cell_x_flipped(over_tile.x, over_tile.y));
+				mirror_y->set_pressed(node->is_cell_y_flipped(over_tile.x, over_tile.y));
+				transpose->set_pressed(node->is_cell_transposed(over_tile.x, over_tile.y));
+				_update_transform_buttons();
 				canvas_item_editor->update();
 				return true;
 			}
@@ -627,10 +649,10 @@ void TileMapEditor::_canvas_draw() {
 							sc.y*=-1.0;
 						if (r==Rect2()) {
 
-							canvas_item_editor->draw_texture_rect(t,Rect2(from,t->get_size()*sc),false,Color(1,1,1,0.5));
+							canvas_item_editor->draw_texture_rect(t,Rect2(from,t->get_size()*sc),false,Color(1,1,1,0.5),transpose->is_pressed());
 						} else {
 
-							canvas_item_editor->draw_texture_rect_region(t,Rect2(from,r.get_size()*sc),r,Color(1,1,1,0.5));
+							canvas_item_editor->draw_texture_rect_region(t,Rect2(from,r.get_size()*sc),r,Color(1,1,1,0.5),transpose->is_pressed());
 						}
 					}
 				}
@@ -697,6 +719,8 @@ void TileMapEditor::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("_canvas_mouse_enter"),&TileMapEditor::_canvas_mouse_enter);
 	ObjectTypeDB::bind_method(_MD("_canvas_mouse_exit"),&TileMapEditor::_canvas_mouse_exit);
 	ObjectTypeDB::bind_method(_MD("_tileset_settings_changed"),&TileMapEditor::_tileset_settings_changed);
+	ObjectTypeDB::bind_method(_MD("_update_transform_buttons"),&TileMapEditor::_update_transform_buttons);
+	ObjectTypeDB::bind_method(_MD("_set_cell_shortened","pos","tile","flip_x","flip_y","transpose"),&TileMapEditor::_set_cell_shortened,DEFVAL(false),DEFVAL(false),DEFVAL(false));
 
 }
 
@@ -709,10 +733,60 @@ TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i& p_pos)
 			op.xf=true;
 		if (node->is_cell_y_flipped(p_pos.x,p_pos.y))
 			op.yf=true;
+		if (node->is_cell_transposed(p_pos.x,p_pos.y))
+			op.tr=true;
 	}
 	return op;
 }
 
+void TileMapEditor::_update_transform_buttons(Object *p_button) {
+	//ERR_FAIL_NULL(p_button);
+	ToolButton *b=p_button->cast_to<ToolButton>();
+	//ERR_FAIL_COND(!b);
+	
+	mirror_x->set_block_signals(true);
+	mirror_y->set_block_signals(true);
+	transpose->set_block_signals(true);
+	rotate_0->set_block_signals(true);
+	rotate_90->set_block_signals(true);
+	rotate_180->set_block_signals(true);
+	rotate_270->set_block_signals(true);
+	
+	if (b == rotate_0) {
+		mirror_x->set_pressed(false);
+		mirror_y->set_pressed(false);
+		transpose->set_pressed(false);
+	}
+	else if (b == rotate_90) {
+		mirror_x->set_pressed(true);
+		mirror_y->set_pressed(false);
+		transpose->set_pressed(true);
+	}
+	else if (b == rotate_180) {
+		mirror_x->set_pressed(true);
+		mirror_y->set_pressed(true);
+		transpose->set_pressed(false);
+	}
+	else if (b == rotate_270) {
+		mirror_x->set_pressed(false);
+		mirror_y->set_pressed(true);
+		transpose->set_pressed(true);
+	}
+	
+	rotate_0->set_pressed(!mirror_x->is_pressed() && !mirror_y->is_pressed() && !transpose->is_pressed());
+	rotate_90->set_pressed(mirror_x->is_pressed() && !mirror_y->is_pressed() && transpose->is_pressed());
+	rotate_180->set_pressed(mirror_x->is_pressed() && mirror_y->is_pressed() && !transpose->is_pressed());
+	rotate_270->set_pressed(!mirror_x->is_pressed() && mirror_y->is_pressed() && transpose->is_pressed());
+
+	mirror_x->set_block_signals(false);
+	mirror_y->set_block_signals(false);
+	transpose->set_block_signals(false);
+	rotate_0->set_block_signals(false);
+	rotate_90->set_block_signals(false);
+	rotate_180->set_block_signals(false);
+	rotate_270->set_block_signals(false);
+}
+
 TileMapEditor::TileMapEditor(EditorNode *p_editor) {
 
 	node=NULL;
@@ -734,18 +808,52 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
 	canvas_item_editor_hb = memnew( HBoxContainer );
 	CanvasItemEditor::get_singleton()->add_control_to_menu_panel(canvas_item_editor_hb);
 	canvas_item_editor_hb->add_child( memnew( VSeparator ));
+	transpose = memnew( ToolButton );
+	transpose->set_toggle_mode(true);
+	transpose->set_tooltip("Transpose");
+	transpose->set_focus_mode(FOCUS_NONE);
+	transpose->connect("pressed", this, "_update_transform_buttons", make_binds(transpose));
+	canvas_item_editor_hb->add_child(transpose);
 	mirror_x = memnew( ToolButton );
 	mirror_x->set_toggle_mode(true);
 	mirror_x->set_tooltip("Mirror X (A)");
 	mirror_x->set_focus_mode(FOCUS_NONE);
+	mirror_x->connect("pressed", this, "_update_transform_buttons", make_binds(mirror_x));
 	canvas_item_editor_hb->add_child(mirror_x);
 	mirror_y = memnew( ToolButton );
 	mirror_y->set_toggle_mode(true);
 	mirror_y->set_tooltip("Mirror Y (S)");
 	mirror_y->set_focus_mode(FOCUS_NONE);
+	mirror_y->connect("pressed", this, "_update_transform_buttons", make_binds(mirror_y));
 	canvas_item_editor_hb->add_child(mirror_y);
+	canvas_item_editor_hb->add_child(memnew(VSeparator));
+	rotate_0 = memnew( ToolButton );
+	rotate_0->set_toggle_mode(true);
+	rotate_0->set_tooltip("Rotate 0 degrees");
+	rotate_0->set_focus_mode(FOCUS_NONE);
+	rotate_0->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_0));
+	canvas_item_editor_hb->add_child(rotate_0);
+	rotate_90 = memnew( ToolButton );
+	rotate_90->set_toggle_mode(true);
+	rotate_90->set_tooltip("Rotate 90 degrees");
+	rotate_90->set_focus_mode(FOCUS_NONE);
+	rotate_90->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_90));
+	canvas_item_editor_hb->add_child(rotate_90);
+	rotate_180 = memnew( ToolButton );
+	rotate_180->set_toggle_mode(true);
+	rotate_180->set_tooltip("Rotate 180 degrees");
+	rotate_180->set_focus_mode(FOCUS_NONE);
+	rotate_180->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_180));
+	canvas_item_editor_hb->add_child(rotate_180);
+	rotate_270 = memnew( ToolButton );
+	rotate_270->set_toggle_mode(true);
+	rotate_270->set_tooltip("Rotate 270 degrees");
+	rotate_270->set_focus_mode(FOCUS_NONE);
+	rotate_270->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_270));
+	canvas_item_editor_hb->add_child(rotate_270);
 	canvas_item_editor_hb->hide();
-
+	
+	rotate_0->set_pressed(true);
 	tool=TOOL_NONE;
 	selection_active=false;
 	mouse_over=false;

+ 10 - 3
tools/editor/plugins/tile_map_editor_plugin.h

@@ -71,8 +71,13 @@ class TileMapEditor : public VBoxContainer {
 	bool mouse_over;
 
 	Label *mirror_label;
+	ToolButton *transpose;
 	ToolButton *mirror_x;
 	ToolButton *mirror_y;
+	ToolButton *rotate_0;
+	ToolButton *rotate_90;
+	ToolButton *rotate_180;
+	ToolButton *rotate_270;
 
 	HBoxContainer *canvas_item_editor_hb;
 
@@ -81,8 +86,8 @@ class TileMapEditor : public VBoxContainer {
 		int idx;
 		bool xf;
 		bool yf;
-		CellOp() { idx=-1; xf=false; yf=false; }
-		CellOp(const CellOp& p_other) : idx(p_other.idx), xf(p_other.xf), yf(p_other.yf) {}
+		bool tr;
+		CellOp() { idx=-1; xf=false; yf=false; tr=false; }
 	};
 
 	Map<Point2i,CellOp> paint_undo;
@@ -94,7 +99,8 @@ class TileMapEditor : public VBoxContainer {
 	void _canvas_draw();
 	void _menu_option(int p_option);
 
-	void _set_cell(const Point2i& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_with_undo=false);
+	void _set_cell(const Point2i& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_transpose=false, bool p_with_undo=false);
+	void _set_cell_shortened(const Point2& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_transpose=false);
 
 	void _canvas_mouse_enter();
 	void _canvas_mouse_exit();
@@ -106,6 +112,7 @@ protected:
 	void _node_removed(Node *p_node);
 	static void _bind_methods();
 	CellOp _get_op_from_cell(const Point2i& p_pos);
+	void _update_transform_buttons(Object *p_button=0);
 public:
 
 	HBoxContainer *get_canvas_item_editor_hb() const { return canvas_item_editor_hb; }

+ 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") );
 				}

+ 1 - 1
tools/editor/scene_tree_dock.cpp

@@ -1254,7 +1254,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
 
 	tb = memnew( ToolButton );
 	tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_INSTANCE, false));
-	tb->set_tooltip("Instance a Node from scene file.");
+	tb->set_tooltip("Instance a scene file as a Node.");
 	hbc_top->add_child(tb);
 	tool_buttons[TOOL_INSTANCE]=tb;
 

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