Explorar el Código

Merge branch 'master' of https://github.com/okamstudio/godot into snapping2

Carl Olsson hace 10 años
padre
commit
41686d5fdd
Se han modificado 42 ficheros con 1644 adiciones y 370 borrados
  1. 160 2
      core/math/math_2d.h
  2. BIN
      demos/2d/navpoly/navigation2.scn
  3. 349 191
      drivers/gles2/rasterizer_gles2.cpp
  4. 12 2
      drivers/gles2/rasterizer_gles2.h
  5. 6 1
      drivers/gles2/shader_compiler_gles2.cpp
  6. 52 10
      drivers/gles2/shaders/canvas.glsl
  7. 5 2
      modules/gdscript/gd_tokenizer.cpp
  8. 1 1
      platform/osx/os_osx.mm
  9. 2 3
      platform/winrt/os_winrt.cpp
  10. 19 4
      scene/2d/canvas_item.cpp
  11. 7 3
      scene/2d/canvas_item.h
  12. 46 0
      scene/2d/canvas_modulate.cpp
  13. 23 0
      scene/2d/canvas_modulate.h
  14. 267 0
      scene/2d/light_2d.cpp
  15. 78 0
      scene/2d/light_2d.h
  16. 38 1
      scene/2d/navigation2d.cpp
  17. 1 0
      scene/2d/navigation2d.h
  18. 37 19
      scene/2d/tile_map.cpp
  19. 3 1
      scene/2d/tile_map.h
  20. 1 1
      scene/gui/popup_menu.h
  21. 24 0
      scene/main/viewport.cpp
  22. 5 0
      scene/main/viewport.h
  23. 4 0
      scene/register_scene_types.cpp
  24. 30 29
      scene/resources/texture.cpp
  25. 12 13
      scene/resources/texture.h
  26. 55 4
      servers/visual/rasterizer.h
  27. 1 1
      servers/visual/rasterizer_dummy.cpp
  28. 1 1
      servers/visual/rasterizer_dummy.h
  29. 218 19
      servers/visual/visual_server_raster.cpp
  30. 23 18
      servers/visual/visual_server_raster.h
  31. 11 5
      servers/visual/visual_server_wrap_mt.h
  32. 4 2
      servers/visual_server.cpp
  33. 11 14
      servers/visual_server.h
  34. BIN
      tools/editor/icons/icon_light_2d.png
  35. BIN
      tools/editor/icons/icon_rotate_0.png
  36. BIN
      tools/editor/icons/icon_rotate_180.png
  37. BIN
      tools/editor/icons/icon_rotate_270.png
  38. BIN
      tools/editor/icons/icon_rotate_90.png
  39. BIN
      tools/editor/icons/icon_transpose.png
  40. 127 19
      tools/editor/plugins/tile_map_editor_plugin.cpp
  41. 10 3
      tools/editor/plugins/tile_map_editor_plugin.h
  42. 1 1
      tools/editor/scene_tree_dock.cpp

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

BIN
demos/2d/navpoly/navigation2.scn


+ 349 - 191
drivers/gles2/rasterizer_gles2.cpp

@@ -6409,7 +6409,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 					 } break;
 					 case VS::MATERIAL_BLEND_MODE_SUB: {
 
-						glBlendEquation(GL_FUNC_SUBTRACT);
+						glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
 						glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 					 } break;
 					case VS::MATERIAL_BLEND_MODE_MUL: {
@@ -7824,8 +7824,10 @@ void RasterizerGLES2::canvas_begin() {
 	//material_shader.unbind();
 	canvas_shader.unbind();
 	canvas_shader.set_custom_shader(0);
+	canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false);
 	canvas_shader.bind();
 	canvas_shader.set_uniform(CanvasShaderGLES2::TEXTURE, 0);
+	canvas_use_modulate=false;
 	_set_color_attrib(Color(1,1,1));
 	canvas_transform=Transform();
 	canvas_transform.translate(-(viewport.width / 2.0f), -(viewport.height / 2.0f), 0.0f);
@@ -7840,7 +7842,6 @@ void RasterizerGLES2::canvas_begin() {
 
 	canvas_opacity=1.0;
 	canvas_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
-
 	canvas_texscreen_used=false;
 	uses_texpixel_size=false;
 	canvas_last_shader=RID();
@@ -7876,7 +7877,7 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) {
 		 } break;
 		 case VS::MATERIAL_BLEND_MODE_SUB: {
 
-			glBlendEquation(GL_FUNC_SUBTRACT);
+			glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
 			glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 		 } break;
 		case VS::MATERIAL_BLEND_MODE_MUL: {
@@ -8103,7 +8104,7 @@ void RasterizerGLES2::_draw_gui_primitive2(int p_points, const Vector2 *p_vertic
 	_rinfo.ci_draw_commands++;
 }
 
-void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip ) {
+void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip, bool p_transpose ) {
 
 	Vector2 texcoords[4]= {
 		Vector2( p_src_region.pos.x/p_tex_size.width,
@@ -8119,6 +8120,9 @@ void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_sr
 		(p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height)
 	};
 
+	if (p_transpose) {
+		SWAP( texcoords[1], texcoords[3] );
+	}
 	if (p_h_flip) {
 		SWAP( texcoords[0], texcoords[1] );
 		SWAP( texcoords[2], texcoords[3] );
@@ -8166,11 +8170,11 @@ void RasterizerGLES2::canvas_draw_rect(const Rect2& p_rect, int p_flags, const R
 		if (!(p_flags&CANVAS_RECT_REGION)) {
 
 			Rect2 region = Rect2(0,0,texture->width,texture->height);
-			_draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V);
+			_draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V,p_flags&CANVAS_RECT_TRANSPOSE);
 
 		} else {
 
-			_draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V );
+			_draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V,p_flags&CANVAS_RECT_TRANSPOSE);
 
 		}
 	} else {
@@ -8325,13 +8329,265 @@ void RasterizerGLES2::canvas_set_transform(const Matrix32& p_transform) {
 	//canvas_transform = Variant(p_transform);
 }
 
+void RasterizerGLES2::_canvas_normal_set_flip(const Vector2& p_flip) {
+
+	if (p_flip==normal_flip)
+		return;
+	normal_flip=p_flip;
+	canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,normal_flip);
+}
+
+
+template<bool use_normalmap>
+void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip) {
+
+	int cc=p_item->commands.size();
+	CanvasItem::Command **commands = p_item->commands.ptr();
+
+
+	for(int i=0;i<cc;i++) {
+
+		CanvasItem::Command *c=commands[i];
+
+		switch(c->type) {
+			case CanvasItem::Command::TYPE_LINE: {
+
+				CanvasItem::CommandLine* line = static_cast<CanvasItem::CommandLine*>(c);
+				canvas_draw_line(line->from,line->to,line->color,line->width);
+			} break;
+			case CanvasItem::Command::TYPE_RECT: {
+
+				CanvasItem::CommandRect* rect = static_cast<CanvasItem::CommandRect*>(c);
+//						canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate);
+#if 0
+				int flags=0;
+
+				if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) {
+					flags|=Rasterizer::CANVAS_RECT_REGION;
+				}
+				if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) {
+					flags|=Rasterizer::CANVAS_RECT_TILE;
+				}
+				if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) {
+
+					flags|=Rasterizer::CANVAS_RECT_FLIP_H;
+				}
+				if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) {
+
+					flags|=Rasterizer::CANVAS_RECT_FLIP_V;
+				}
+#else
+
+				int flags=rect->flags;
+#endif
+				if (use_normalmap)
+					_canvas_normal_set_flip(Vector2((flags&CANVAS_RECT_FLIP_H)?-1:1,(flags&CANVAS_RECT_FLIP_V)?-1:1));
+				canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate);
+
+			} break;
+			case CanvasItem::Command::TYPE_STYLE: {
+
+				CanvasItem::CommandStyle* style = static_cast<CanvasItem::CommandStyle*>(c);
+				if (use_normalmap)
+					_canvas_normal_set_flip(Vector2(1,1));
+				canvas_draw_style_box(style->rect,style->texture,style->margin,style->draw_center,style->color);
+
+			} break;
+			case CanvasItem::Command::TYPE_PRIMITIVE: {
+
+				if (use_normalmap)
+					_canvas_normal_set_flip(Vector2(1,1));
+				CanvasItem::CommandPrimitive* primitive = static_cast<CanvasItem::CommandPrimitive*>(c);
+				canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width);
+			} break;
+			case CanvasItem::Command::TYPE_POLYGON: {
+
+				if (use_normalmap)
+					_canvas_normal_set_flip(Vector2(1,1));
+				CanvasItem::CommandPolygon* polygon = static_cast<CanvasItem::CommandPolygon*>(c);
+				canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1);
+
+			} break;
+
+			case CanvasItem::Command::TYPE_POLYGON_PTR: {
+
+				if (use_normalmap)
+					_canvas_normal_set_flip(Vector2(1,1));
+				CanvasItem::CommandPolygonPtr* polygon = static_cast<CanvasItem::CommandPolygonPtr*>(c);
+				canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false);
+			} break;
+			case CanvasItem::Command::TYPE_CIRCLE: {
+
+				CanvasItem::CommandCircle* circle = static_cast<CanvasItem::CommandCircle*>(c);
+				static const int numpoints=32;
+				Vector2 points[numpoints+1];
+				points[numpoints]=circle->pos;
+				int indices[numpoints*3];
+
+				for(int i=0;i<numpoints;i++) {
+
+					points[i]=circle->pos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius;
+					indices[i*3+0]=i;
+					indices[i*3+1]=(i+1)%numpoints;
+					indices[i*3+2]=numpoints;
+				}
+				canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true);
+				//canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1);
+			} break;
+			case CanvasItem::Command::TYPE_TRANSFORM: {
+
+				CanvasItem::CommandTransform* transform = static_cast<CanvasItem::CommandTransform*>(c);
+				canvas_set_transform(transform->xform);
+			} break;
+			case CanvasItem::Command::TYPE_BLEND_MODE: {
+
+				CanvasItem::CommandBlendMode* bm = static_cast<CanvasItem::CommandBlendMode*>(c);
+				canvas_set_blend_mode(bm->blend_mode);
+
+			} break;
+			case CanvasItem::Command::TYPE_CLIP_IGNORE: {
+
+				CanvasItem::CommandClipIgnore* ci = static_cast<CanvasItem::CommandClipIgnore*>(c);
+				if (current_clip) {
+
+					if (ci->ignore!=reclip) {
+						if (ci->ignore) {
+
+							glDisable(GL_SCISSOR_TEST);
+							reclip=true;
+						} else  {
+
+							glEnable(GL_SCISSOR_TEST);
+							glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)),
+							current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height);
+							reclip=false;
+						}
+					}
+				}
+
+
+
+			} break;
+		}
+	}
+
+}
+
+void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItem *shader_owner,Shader* shader) {
+
+	if (canvas_shader.bind())
+		rebind_texpixel_size=true;
+
+	if (shader_owner->shader_version!=shader->version) {
+		//todo optimize uniforms
+		shader_owner->shader_version=shader->version;
+	}
+
+	if (shader->has_texscreen && framebuffer.active) {
+
+		int x = viewport.x;
+		int y = window_size.height-(viewport.height+viewport.y);
+
+		canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height));
+		canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height));
+		canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,max_texture_units-1);
+		glActiveTexture(GL_TEXTURE0+max_texture_units-1);
+		glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
+		if (framebuffer.scale==1 && !canvas_texscreen_used) {
+#ifdef GLEW_ENABLED
+			glReadBuffer(GL_COLOR_ATTACHMENT0);
+#endif
+			glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height);
+//			if (current_clip) {
+//			//	print_line(" a clip ");
+//			}
+
+			canvas_texscreen_used=true;
+		}
+
+		glActiveTexture(GL_TEXTURE0);
+
+	}
+
+	if (shader->has_screen_uv) {
+		canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height));
+	}
+
+	if (shader->uses_time) {
+		canvas_shader.set_uniform(CanvasShaderGLES2::TIME,Math::fmod(last_time,300.0));
+		draw_next_frame=true;
+	}
+		//if uses TIME - draw_next_frame=true
+
+	uses_texpixel_size=shader->uses_texpixel_size;
+
+}
+
+void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItem *shader_owner,Shader* shader) {
+
+	//this can be optimized..
+	int tex_id=1;
+	int idx=0;
+	for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
+
+		Map<StringName,Variant>::Element *F=shader_owner->shader_param.find(E->key());
+
+		if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) {
+
+			RID rid;
+			if (F) {
+				rid=F->get();
+			}
+
+			if (!rid.is_valid()) {
+
+				Map<StringName,RID>::Element *DT=shader->default_textures.find(E->key());
+				if (DT) {
+					rid=DT->get();
+				}
+			}
+
+			if (rid.is_valid()) {
+
+				int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic..
 
-void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
+				glActiveTexture(GL_TEXTURE0+tex_id);
+				Texture *t=texture_owner.get(rid);
+				if (!t)
+					glBindTexture(GL_TEXTURE_2D,white_tex);
+				else
+					glBindTexture(t->target,t->tex_id);
+
+				glUniform1i(loc,tex_id);
+				tex_id++;
+			}
+		} else {
+			Variant &v=F?F->get():E->get().default_value;
+			canvas_shader.set_custom_uniform(idx,v);
+		}
+
+		idx++;
+	}
+
+	if (tex_id>1) {
+		glActiveTexture(GL_TEXTURE0);
+	}
+
+}
+
+void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light) {
 
 
 	CanvasItem *current_clip=NULL;
 	Shader *shader_cache=NULL;
+
+	bool rebind_shader=true;
+
 	canvas_opacity=1.0;
+	canvas_use_modulate=p_modulate!=Color(1,1,1,1);
+	canvas_modulate=p_modulate;
+	canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
+
 	while(p_item_list) {
 
 		CanvasItem *ci=p_item_list;
@@ -8343,6 +8599,12 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
 			memdelete(ci->vp_render);
 			ci->vp_render=NULL;
 			canvas_last_shader=RID();
+			canvas_use_modulate=p_modulate!=Color(1,1,1,1);
+			canvas_modulate=p_modulate;
+			canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
+			rebind_shader=true;
+
+
 		}
 
 		if (current_clip!=ci->final_clip_owner) {
@@ -8365,7 +8627,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
 		//begin rect
 		CanvasItem *shader_owner = ci->shader_owner?ci->shader_owner:ci;
 
-		if (shader_owner->shader!=canvas_last_shader) {
+		if (shader_owner->shader!=canvas_last_shader || rebind_shader) {
 
 			Shader *shader = NULL;
 			if (shader_owner->shader.is_valid()) {
@@ -8379,52 +8641,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
 
 			if (shader) {
 				canvas_shader.set_custom_shader(shader->custom_code_id);
-				if (canvas_shader.bind())
-					rebind_texpixel_size=true;
-
-				if (shader_owner->shader_version!=shader->version) {
-					//todo optimize uniforms
-					shader_owner->shader_version=shader->version;
-				}
-
-				if (shader->has_texscreen && framebuffer.active) {
-
-					int x = viewport.x;
-					int y = window_size.height-(viewport.height+viewport.y);
-
-					canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height));
-					canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height));
-					canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,max_texture_units-1);
-					glActiveTexture(GL_TEXTURE0+max_texture_units-1);
-					glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
-					if (framebuffer.scale==1 && !canvas_texscreen_used) {
-#ifdef GLEW_ENABLED
-						glReadBuffer(GL_COLOR_ATTACHMENT0);
-#endif
-						glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height);
-						if (current_clip) {
-						//	print_line(" a clip ");
-						}
-
-						canvas_texscreen_used=true;
-					}	
-
-					glActiveTexture(GL_TEXTURE0);
-
-				}
-
-				if (shader->has_screen_uv) {
-					canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height));
-				}
-
-				if (shader->uses_time) {
-					canvas_shader.set_uniform(CanvasShaderGLES2::TIME,Math::fmod(last_time,300.0));
-					draw_next_frame=true;
-				}
-					//if uses TIME - draw_next_frame=true
-
-				uses_texpixel_size=shader->uses_texpixel_size;
-
+				_canvas_item_setup_shader_params(shader_owner,shader);
 			} else {
 				shader_cache=NULL;
 				canvas_shader.set_custom_shader(0);
@@ -8435,60 +8652,15 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
 
 
 			canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform);
+			if (canvas_use_modulate)
+				canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
 			canvas_last_shader=shader_owner->shader;
+			rebind_shader=false;
 		}
 
 		if (shader_cache) {
 
-			Shader *shader = shader_cache;
-			//this can be optimized..
-			int tex_id=1;
-			int idx=0;
-			for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
-
-				Map<StringName,Variant>::Element *F=shader_owner->shader_param.find(E->key());
-
-				if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) {
-
-					RID rid;
-					if (F) {
-						rid=F->get();
-					}
-
-					if (!rid.is_valid()) {
-
-						Map<StringName,RID>::Element *DT=shader->default_textures.find(E->key());
-						if (DT) {
-							rid=DT->get();
-						}
-					}
-
-					if (rid.is_valid()) {
-
-						int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic..
-
-						glActiveTexture(GL_TEXTURE0+tex_id);
-						Texture *t=texture_owner.get(rid);
-						if (!t)
-							glBindTexture(GL_TEXTURE_2D,white_tex);
-						else
-							glBindTexture(t->target,t->tex_id);
-
-						glUniform1i(loc,tex_id);
-						tex_id++;
-					}
-				} else {
-					Variant &v=F?F->get():E->get().default_value;
-					canvas_shader.set_custom_uniform(idx,v);
-				}
-
-				idx++;
-			}
-
-			if (tex_id>1) {
-				glActiveTexture(GL_TEXTURE0);
-			}
-
+			_canvas_item_setup_shader_uniforms(shader_owner,shader_cache);
 		}
 
 		canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
@@ -8514,7 +8686,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
 				 } break;
 				 case VS::MATERIAL_BLEND_MODE_SUB: {
 
-					glBlendEquation(GL_FUNC_SUBTRACT);
+					glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
 					glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 				 } break;
 				case VS::MATERIAL_BLEND_MODE_MUL: {
@@ -8531,128 +8703,114 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
 			canvas_blend_mode=ci->blend_mode;
 		}
 
-		int cc=ci->commands.size();
-		CanvasItem::Command **commands = ci->commands.ptr();
-
 		canvas_opacity = ci->final_opacity;
 
-		for(int i=0;i<cc;i++) {
+		_canvas_item_render_commands<false>(ci,current_clip,reclip);
 
-			CanvasItem::Command *c=commands[i];
+		if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light) {
 
-			switch(c->type) {
-				case CanvasItem::Command::TYPE_LINE: {
+			CanvasLight *light = p_light;
+			bool light_used=false;
+			bool subtract=false;
 
-					CanvasItem::CommandLine* line = static_cast<CanvasItem::CommandLine*>(c);
-					canvas_draw_line(line->from,line->to,line->color,line->width);
-				} break;
-				case CanvasItem::Command::TYPE_RECT: {
 
-					CanvasItem::CommandRect* rect = static_cast<CanvasItem::CommandRect*>(c);
-//						canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate);
-#if 0
-					int flags=0;
+			while(light) {
 
-					if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) {
-						flags|=Rasterizer::CANVAS_RECT_REGION;
-					}
-					if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) {
-						flags|=Rasterizer::CANVAS_RECT_TILE;
-					}
-					if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) {
+				if (ci->light_mask&light->item_mask && p_z>=light->z_min && p_z<=light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache,light->rect_cache)) {
 
-						flags|=Rasterizer::CANVAS_RECT_FLIP_H;
-					}
-					if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) {
+					//intersects this light
 
-						flags|=Rasterizer::CANVAS_RECT_FLIP_V;
-					}
-#else
+					if (!light_used || subtract!=light->subtract) {
 
-					int flags=rect->flags;
-#endif
-					canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate);
+						subtract=light->subtract;
 
-				} break;
-				case CanvasItem::Command::TYPE_STYLE: {
+						if (subtract) {
 
-					CanvasItem::CommandStyle* style = static_cast<CanvasItem::CommandStyle*>(c);
-					canvas_draw_style_box(style->rect,style->texture,style->margin,style->draw_center,style->color);
+							glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+							glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 
-				} break;
-				case CanvasItem::Command::TYPE_PRIMITIVE: {
+						} else {
 
-					CanvasItem::CommandPrimitive* primitive = static_cast<CanvasItem::CommandPrimitive*>(c);
-					canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width);
-				} break;
-				case CanvasItem::Command::TYPE_POLYGON: {
+							glBlendEquation(GL_FUNC_ADD);
+							glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 
-					CanvasItem::CommandPolygon* polygon = static_cast<CanvasItem::CommandPolygon*>(c);
-					canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1);
+						}
+					}
 
-				} break;
+					if (!light_used) {
 
-				case CanvasItem::Command::TYPE_POLYGON_PTR: {
+						canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,true);
+						canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false);
+						light_used=true;
+						normal_flip=Vector2(1,1);
 
-					CanvasItem::CommandPolygonPtr* polygon = static_cast<CanvasItem::CommandPolygonPtr*>(c);
-					canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false);
-				} break;
-				case CanvasItem::Command::TYPE_CIRCLE: {
+					}
+					bool light_rebind = canvas_shader.bind();
 
-					CanvasItem::CommandCircle* circle = static_cast<CanvasItem::CommandCircle*>(c);
-					static const int numpoints=32;
-					Vector2 points[numpoints+1];
-					points[numpoints]=circle->pos;
-					int indices[numpoints*3];
+					if (light_rebind) {
+
+						if (shader_owner && shader_cache) {
+							_canvas_item_setup_shader_params(shader_owner,shader_cache);
+							_canvas_item_setup_shader_uniforms(shader_owner,shader_cache);
+						}
+
+						canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
+						canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32());
+						canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform);
+						if (canvas_use_modulate)
+							canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
+						canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,Vector2(1,1));
 
-					for(int i=0;i<numpoints;i++) {
 
-						points[i]=circle->pos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius;
-						indices[i*3+0]=i;
-						indices[i*3+1]=(i+1)%numpoints;
-						indices[i*3+2]=numpoints;
 					}
-					canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true);
-					//canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1);
-				} break;
-				case CanvasItem::Command::TYPE_TRANSFORM: {
 
-					CanvasItem::CommandTransform* transform = static_cast<CanvasItem::CommandTransform*>(c);
-					canvas_set_transform(transform->xform);
-				} break;
-				case CanvasItem::Command::TYPE_BLEND_MODE: {
+					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX,light->light_shader_xform);
+					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS,light->light_shader_pos);
+					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,light->color);
+					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height);
+					glActiveTexture(GL_TEXTURE0+max_texture_units-2);
+					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_TEXTURE,max_texture_units-2);
+					Texture *t = texture_owner.get(light->texture);
+					if (!t) {
+						glBindTexture(GL_TEXTURE_2D,white_tex);
+					} else {
 
-					CanvasItem::CommandBlendMode* bm = static_cast<CanvasItem::CommandBlendMode*>(c);
-					canvas_set_blend_mode(bm->blend_mode);
+						glBindTexture(t->target,t->tex_id);
+					}
 
-				} break;
-				case CanvasItem::Command::TYPE_CLIP_IGNORE: {
+					glActiveTexture(GL_TEXTURE0);
+					_canvas_item_render_commands<true>(ci,current_clip,reclip); //redraw using light
 
-					CanvasItem::CommandClipIgnore* ci = static_cast<CanvasItem::CommandClipIgnore*>(c);
-					if (current_clip) {
+				}
 
-						if (ci->ignore!=reclip) {
-							if (ci->ignore) {
+				light=light->next_ptr;
+			}
 
-								glDisable(GL_SCISSOR_TEST);
-								reclip=true;
-							} else  {
+			if (light_used) {
 
-								glEnable(GL_SCISSOR_TEST);
-								glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)),
-								current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height);
-								reclip=false;
-							}
-						}
-					}
 
+				canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,false);
+				canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
 
+				canvas_shader.bind();
 
-				} break;
+				if (shader_owner && shader_cache) {
+					_canvas_item_setup_shader_params(shader_owner,shader_cache);
+					_canvas_item_setup_shader_uniforms(shader_owner,shader_cache);
+				}
+
+				canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
+				canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32());
+				if (canvas_use_modulate)
+					canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate);
+
+				glBlendEquation(GL_FUNC_ADD);
+				glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
 			}
-		}
 
 
+		}
+
 		if (reclip) {
 
 			glEnable(GL_SCISSOR_TEST);

+ 12 - 2
drivers/gles2/rasterizer_gles2.h

@@ -1127,6 +1127,7 @@ class RasterizerGLES2 : public Rasterizer {
 		bool active;
 
 		int blur_size;
+
 		struct Blur {
 
 			GLuint fbo;
@@ -1186,11 +1187,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;
 	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);
@@ -1232,7 +1237,7 @@ class RasterizerGLES2 : public Rasterizer {
 	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 +1252,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(CanvasItem *shader_owner,Shader* p_shader);
+	_FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItem *shader_owner,Shader* p_shader);
 public:
 
 	/* TEXTURE API */
@@ -1562,7 +1571,8 @@ 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 */
 

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

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

@@ -26,7 +26,13 @@ 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
 
 #endif
 
@@ -67,8 +73,13 @@ 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;
+
+#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,11 +132,22 @@ 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
 
@@ -151,6 +173,11 @@ void main() {
 	vec3 normal = vec3(0,0,1);
 #endif
 
+#ifdef USE_MODULATE
+
+	color*=modulate;
+#endif
+
 	color *= texture2D( texture,  uv_interp );
 #if defined(ENABLE_SCREEN_UV)
 	vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult;
@@ -166,9 +193,13 @@ FRAGMENT_SHADER_CODE
 
 #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);
@@ -183,18 +214,29 @@ FRAGMENT_SHADER_CODE
 #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
 

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

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

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

@@ -458,6 +458,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 +521,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 +529,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) {
@@ -857,6 +867,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);
@@ -912,6 +925,7 @@ 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::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"shader/shader",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph"), _SCS("set_shader"),_SCS("get_shader") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"shader/use_parent"), _SCS("set_use_parent_shader"),_SCS("get_use_parent_shader") );
 	//exporting these two things doesn't really make much sense i think
@@ -992,6 +1006,7 @@ CanvasItem::CanvasItem() : xform_change(this) {
 	canvas_layer=NULL;
 	use_parent_shader=false;
 	global_invalid=true;
+	light_mask=1;
 
 	C=NULL;
 

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

@@ -71,6 +71,7 @@ private:
 	List<CanvasItem*>::Element *C;
 
 	BlendMode blend_mode;
+	int light_mask;
 
 	bool first_draw;
 	bool hidden;
@@ -80,8 +81,8 @@ private:
 	bool drawing;
 	bool block_transform_notify;
 	bool behind;
-
 	bool use_parent_shader;
+
 	Ref<Shader> shader;
 
 	mutable Matrix32 global_transform;
@@ -158,6 +159,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 +174,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>());

+ 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

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

@@ -0,0 +1,267 @@
+#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::_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);
+
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
+	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
+	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"texture_offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset"));
+	ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"height"),_SCS("set_height"),_SCS("get_height"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"z_range_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"z_range_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"layer_range_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"layer_range_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask"));
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"subtract"),_SCS("set_subtract_mode"),_SCS("get_subtract_mode"));
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow_enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled"));
+
+
+}
+
+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;
+
+}
+
+Light2D::~Light2D() {
+
+	VisualServer::get_singleton()->free(canvas_light);
+}

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

@@ -0,0 +1,78 @@
+#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;
+	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;
+
+	virtual Rect2 get_item_rect() const;
+
+	Light2D();
+	~Light2D();
+};
+
+
+#endif // LIGHT_2D_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;
 

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

+ 4 - 0
scene/register_scene_types.cpp

@@ -79,6 +79,7 @@
 #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/canvas_item.h"
 #include "scene/2d/sprite.h"
@@ -103,6 +104,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 +265,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 */
@@ -472,6 +475,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<VisibilityNotifier2D>();
 	ObjectTypeDB::register_type<VisibilityEnabler2D>();
 	ObjectTypeDB::register_type<Polygon2D>();
+	ObjectTypeDB::register_type<Light2D>();
 	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();

+ 55 - 4
servers/visual/rasterizer.h

@@ -564,9 +564,58 @@ 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;
+		bool shadow;
+		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;
+
+
+		void *texture_cache; // implementation dependent
+		Rect2 rect_cache;
+		Matrix32 xform_cache;
+
+		Matrix32 light_shader_xform;
+		Vector2 light_shader_pos;
+
+		CanvasLight *filter_next_ptr;
+		CanvasLight *next_ptr;
+
+		CanvasLight() {
+			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=false;
+			texture_cache=NULL;
+			next_ptr=NULL;
+			filter_next_ptr=NULL;
+		}
+	};
+
+
 	struct CanvasItem {
 
 		struct Command {
@@ -689,6 +738,7 @@ public:
 		bool visible;
 		bool ontop;
 		VS::MaterialBlendMode blend_mode;
+		int light_mask;
 		Vector<Command*> commands;
 		mutable bool custom_rect;
 		mutable bool rect_dirty;
@@ -706,8 +756,9 @@ public:
 		CanvasItem* shader_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;
 
@@ -831,7 +882,7 @@ public:
 		}
 
 		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;}
+		CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1;  blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; shader_version=0; shader_owner=NULL;}
 		virtual ~CanvasItem() { clear(); }
 	};
 
@@ -853,7 +904,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)=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;
 
 
 	/* ENVIRONMENT */

+ 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 */
 

+ 218 - 19
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;
@@ -3823,60 +3880,128 @@ 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);
+	clight->shadow=p_enabled;
 
 }
 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);
 
 }
 void VisualServerRaster::canvas_light_set_shadow_filter(RID p_light, int p_size){
 
+	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+	ERR_FAIL_COND(!clight);
 
 }
 
@@ -4154,7 +4279,13 @@ 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();
+		}
+
+
 		canvas_owner.free( p_rid );
 		
 		memdelete( canvas );
@@ -4186,6 +4317,21 @@ void VisualServerRaster::free( RID p_rid ) {
 		canvas_item_owner.free( p_rid );
 		
 		memdelete( canvas_item );
+
+	} 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);
+		}
+
+		canvas_light_owner.free( p_rid );
+		memdelete( canvas_light );
+
 	} else if (scenario_owner.owns(p_rid)) {
 		
 		Scenario *scenario=scenario_owner.get(p_rid);
@@ -6231,7 +6377,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 +6395,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);
 	}
 
 }
@@ -6355,7 +6501,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 +6514,8 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 			z_last_list[zidx]=ci;
 		}
 
+
+
 		ci->next=NULL;
 
 	}
@@ -6381,7 +6529,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
 
 }
 
-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 +6562,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 +6640,10 @@ 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) {
+			rasterizer->clear_viewport(clear_color);
+			p_viewport->render_target_clear=false;
+		}
 	}
 
 	if (!p_viewport->hide_canvas) {
@@ -6500,7 +6651,43 @@ 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;
+
 		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];
+					}
+
+
+
+
+				}
+			}
+
 			canvas_map[ Viewport::CanvasKey( E->key(), E->get().layer) ]=&E->get();
 
 		}
@@ -6511,7 +6698,19 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 	//		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++;
 
 		}

+ 23 - 18
servers/visual/visual_server_raster.h

@@ -410,6 +410,8 @@ class VisualServerRaster : public VisualServer {
 		}
 	};
 
+	struct CanvasLight;
+
 	struct Canvas {
 
 		Set<RID> viewports;
@@ -419,8 +421,10 @@ class VisualServerRaster : public VisualServer {
 			CanvasItem *item;
 		};
 
+		Set<Rasterizer::CanvasLight*> lights;
 
 		Vector<ChildItem> child_items;
+		Color modulate;
 
 		int find_item(CanvasItem *p_item) {
 			for(int i=0;i<child_items.size();i++) {
@@ -435,11 +439,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 +468,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 +496,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 +609,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_tree(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, const Color &p_modulate, Rasterizer::CanvasLight *p_lights);
 	void _render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_shader_owner);
-	void _render_canvas(Canvas *p_canvas,const Matrix32 &p_transform);
+	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 +959,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 +1084,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 +1096,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 +1117,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());
@@ -1135,20 +1150,10 @@ 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);

+ 11 - 5
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 );
@@ -1155,10 +1160,11 @@ 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);

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

+ 11 - 14
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;
@@ -1008,20 +1015,10 @@ 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;

BIN
tools/editor/icons/icon_light_2d.png


BIN
tools/editor/icons/icon_rotate_0.png


BIN
tools/editor/icons/icon_rotate_180.png


BIN
tools/editor/icons/icon_rotate_270.png


BIN
tools/editor/icons/icon_rotate_90.png


BIN
tools/editor/icons/icon_transpose.png


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

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