Browse Source

Merge pull request #1369 from not-surt/tile_rotation

Tile Rotation
Juan Linietsky 10 years ago
parent
commit
1d7337ba10

+ 6 - 3
drivers/gles2/rasterizer_gles2.cpp

@@ -8104,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,
@@ -8120,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] );
@@ -8167,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 {

+ 1 - 1
drivers/gles2/rasterizer_gles2.h

@@ -1237,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();

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

@@ -521,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.");
@@ -529,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) {

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

@@ -174,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>());

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

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

+ 2 - 1
servers/visual/rasterizer.h

@@ -564,7 +564,8 @@ 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
 	};
 
 

+ 11 - 2
servers/visual/visual_server_raster.cpp

@@ -3518,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);
@@ -3541,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);
@@ -3569,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;

+ 2 - 2
servers/visual/visual_server_raster.h

@@ -1117,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());

+ 2 - 3
servers/visual/visual_server_wrap_mt.h

@@ -1122,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 );

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

+ 2 - 2
servers/visual_server.h

@@ -981,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;

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