Ejemplo n.º 1
0
bool CollisionSolver2DSW::solve_raycast(const Shape2DSW *p_shape_A, const Matrix32 &p_transform_A, const Shape2DSW *p_shape_B, const Matrix32 &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis) {

	const RayShape2DSW *ray = static_cast<const RayShape2DSW *>(p_shape_A);
	if (p_shape_B->get_type() == Physics2DServer::SHAPE_RAY)
		return false;

	Vector2 from = p_transform_A.get_origin();
	Vector2 to = from + p_transform_A[1] * ray->get_length();
	Vector2 support_A = to;

	Matrix32 invb = p_transform_B.affine_inverse();
	from = invb.xform(from);
	to = invb.xform(to);

	Vector2 p, n;
	if (!p_shape_B->intersect_segment(from, to, p, n)) {

		if (sep_axis)
			*sep_axis = p_transform_A[1].normalized();
		return false;
	}

	Vector2 support_B = p_transform_B.xform(p);

	if (p_result_callback) {
		if (p_swap_result)
			p_result_callback(support_B, support_A, p_userdata);
		else
			p_result_callback(support_A, support_B, p_userdata);
	}
	return true;
}
Ejemplo n.º 2
0
void Area2DSW::set_transform(const Matrix32& p_transform) {

	if (!moved_list.in_list() && get_space())
		get_space()->area_add_to_moved_list(&moved_list);

	_set_transform(p_transform);
	_set_inv_transform(p_transform.affine_inverse());
}
Ejemplo n.º 3
0
void CollisionObject2DSW::set_shape_transform(int p_index,const Matrix32& p_transform) {

    ERR_FAIL_INDEX(p_index,shapes.size());

    shapes[p_index].xform=p_transform;
    shapes[p_index].xform_inv=p_transform.affine_inverse();
    _update_shapes();
    _shapes_changed();
}
Ejemplo n.º 4
0
static void _collision_rectangle_convex_polygon(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) {

	const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW*>(p_a);
	const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW*>(p_b);

	SeparatorAxisTest2D<RectangleShape2DSW,ConvexPolygonShape2DSW,castA,castB,withMargin> separator(rectangle_A,p_transform_a,convex_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B);


	if (!separator.test_previous_axis())
		return;

	if (!separator.test_cast())
		return;

	//box faces
	if (!separator.test_axis(p_transform_a.elements[0].normalized()))
		return;

	if (!separator.test_axis(p_transform_a.elements[1].normalized()))
		return;

	//convex faces
	Matrix32 boxinv;
	if (withMargin) {
		boxinv=p_transform_a.affine_inverse();
	}
	for(int i=0;i<convex_B->get_point_count();i++) {

		if (!separator.test_axis( convex_B->get_xformed_segment_normal(p_transform_b,i)))
			return;

		if (withMargin) {
			//all points vs all points need to be tested if margin exist
			if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,p_transform_b.xform(convex_B->get_point(i)))))
				return;
			if (castA) {

				if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,p_transform_b.xform(convex_B->get_point(i))-p_motion_a)))
					return;
			}
			if (castB) {

				if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,p_transform_b.xform(convex_B->get_point(i))+p_motion_b)))
					return;
			}
			if (castA && castB) {

				if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,p_transform_b.xform(convex_B->get_point(i))+p_motion_b-p_motion_a)))
					return;
			}

		}
	}

	separator.generate_contacts();

}
Ejemplo n.º 5
0
bool BodyPair2DSW::_test_ccd(float p_step,Body2DSW *p_A, int p_shape_A,const Matrix32& p_xform_A,Body2DSW *p_B, int p_shape_B,const Matrix32& p_xform_B,bool p_swap_result) {



	Vector2 motion = p_A->get_linear_velocity()*p_step;
	real_t mlen = motion.length();
	if (mlen<CMP_EPSILON)
		return false;

	Vector2 mnormal = motion / mlen;

	real_t min,max;
	p_A->get_shape(p_shape_A)->project_rangev(mnormal,p_xform_A,min,max);
	bool fast_object = mlen > (max-min)*0.3; //going too fast in that direction

	if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
		return false;
	}

	//cast a segment from support in motion normal, in the same direction of motion by motion length
	//support is the worst case collision point, so real collision happened before
	int a;
	Vector2 s[2];
	p_A->get_shape(p_shape_A)->get_supports(p_xform_A.basis_xform(mnormal).normalized(),s,a);
	Vector2 from = p_xform_A.xform(s[0]);
	Vector2 to = from + motion;

	Matrix32 from_inv = p_xform_B.affine_inverse();

	Vector2 local_from = from_inv.xform(from-mnormal*mlen*0.1); //start from a little inside the bounding box
	Vector2 local_to = from_inv.xform(to);

	Vector2 rpos,rnorm;
	if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from,local_to,rpos,rnorm))
		return false;

	//ray hit something


	Vector2 hitpos = p_xform_B.xform(rpos);

	Vector2 contact_A = to;
	Vector2 contact_B = hitpos;

	//create a contact

	if (p_swap_result)
		_contact_added_callback(contact_B,contact_A);
	else
		_contact_added_callback(contact_A,contact_B);


	return true;
}
Ejemplo n.º 6
0
static void _collision_circle_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) {

	const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW*>(p_a);
	const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW*>(p_b);


	SeparatorAxisTest2D<CircleShape2DSW,RectangleShape2DSW,castA,castB,withMargin> separator(circle_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B);

	if (!separator.test_previous_axis())
		return;

	if (!separator.test_cast())
		return;

	const Vector2 &sphere=p_transform_a.elements[2];
	const Vector2 *axis=&p_transform_b.elements[0];
//	const Vector2& half_extents = rectangle_B->get_half_extents();

	if (!separator.test_axis(axis[0].normalized()))
		return;

	if (!separator.test_axis(axis[1].normalized()))
		return;

	Matrix32 binv = p_transform_b.affine_inverse();
	{

		if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,binv,sphere ) ) )
			return;
	}

	if (castA) {

		Vector2 sphereofs = sphere + p_motion_a;
		if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,binv, sphereofs) ) )
			return;
	}

	if (castB) {

		Vector2 sphereofs = sphere - p_motion_b;
		if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,binv, sphereofs) ) )
			return;
	}

	if (castA && castB) {

		Vector2 sphereofs = sphere - p_motion_b + p_motion_a;
		if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,binv, sphereofs) ) )
			return;
	}

	separator.generate_contacts();
}
Ejemplo n.º 7
0
bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result) {


	const LineShape2DSW *line = static_cast<const LineShape2DSW*>(p_shape_A);
	if (p_shape_B->get_type()==Physics2DServer::SHAPE_LINE)
		return false;


	Vector2 n = p_transform_A.basis_xform(line->get_normal()).normalized();
	Vector2 p = p_transform_A.xform(line->get_normal()*line->get_d());
	real_t d = n.dot(p);

	Vector2 supports[2];
	int support_count;

	p_shape_B->get_supports(p_transform_A.affine_inverse().basis_xform(-n).normalized(),supports,support_count);

	bool found=false;


	for(int i=0;i<support_count;i++) {

		supports[i] = p_transform_B.xform( supports[i] );
		real_t pd = n.dot(supports[i]);
		if (pd>=d)
			continue;
		found=true;

		Vector2 support_A = supports[i] - n*(pd-d);

		if (p_result_callback) {
			if (p_swap_result)
				p_result_callback(supports[i],support_A,p_userdata);
			else
				p_result_callback(support_A,supports[i],p_userdata);
		}

	}


	return found;
}
Ejemplo n.º 8
0
void SpriteRegionEditor::_region_input(const InputEvent& p_input)
{
	Matrix32 mtx;
	mtx.elements[2]=-draw_ofs;
	mtx.scale_basis(Vector2(draw_zoom,draw_zoom));

	Vector2 endpoints[8]={
		mtx.xform(rect.pos)+Vector2(-4,-4),
		mtx.xform(rect.pos+Vector2(rect.size.x/2,0))+Vector2(0,-4),
		mtx.xform(rect.pos+Vector2(rect.size.x,0))+Vector2(4,-4),
		mtx.xform(rect.pos+Vector2(rect.size.x,rect.size.y/2))+Vector2(4,0),
		mtx.xform(rect.pos+rect.size)+Vector2(4,4),
		mtx.xform(rect.pos+Vector2(rect.size.x/2,rect.size.y))+Vector2(0,4),
		mtx.xform(rect.pos+Vector2(0,rect.size.y))+Vector2(-4,4),
		mtx.xform(rect.pos+Vector2(0,rect.size.y/2))+Vector2(-4,0)
	};

	if (p_input.type==InputEvent::MOUSE_BUTTON) {


		const InputEventMouseButton &mb=p_input.mouse_button;

		if (mb.button_index==BUTTON_LEFT) {


			if (mb.pressed) {

				drag_from=mtx.affine_inverse().xform(Vector2(mb.x,mb.y));
				drag_from=snap_point(drag_from);
				drag=true;
				rect_prev=node->get_region_rect();

				drag_index=-1;
				for(int i=0;i<8;i++) {

					Vector2 tuv=endpoints[i];
					if (tuv.distance_to(Vector2(mb.x,mb.y))<8) {
						drag_index=i;
						creating = false;
					}
				}

				if (drag_index==-1) {
					creating = true;
					rect = Rect2(drag_from,Size2());
				}

			} else if (drag) {

				undo_redo->create_action(TTR("Set region_rect"));
				undo_redo->add_do_method(node,"set_region_rect",node->get_region_rect());
				undo_redo->add_undo_method(node,"set_region_rect",rect_prev);
				undo_redo->add_do_method(edit_draw,"update");
				undo_redo->add_undo_method(edit_draw,"update");
				undo_redo->commit_action();

				drag=false;
			}

		} else if (mb.button_index==BUTTON_RIGHT && mb.pressed) {

			if (drag) {
				drag=false;
				node->set_region_rect(rect_prev);
				rect=rect_prev;
				edit_draw->update();
			}

		} else if (mb.button_index==BUTTON_WHEEL_UP && mb.pressed) {

			zoom->set_val( zoom->get_val()/0.9 );
		} else if (mb.button_index==BUTTON_WHEEL_DOWN && mb.pressed) {

			zoom->set_val( zoom->get_val()*0.9);
		}

	} else if (p_input.type==InputEvent::MOUSE_MOTION) {

		const InputEventMouseMotion &mm=p_input.mouse_motion;

		if (mm.button_mask&BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {

			Vector2 draged(mm.relative_x,mm.relative_y);
			hscroll->set_val( hscroll->get_val()-draged.x );
			vscroll->set_val( vscroll->get_val()-draged.y );

		} else if (drag) {

			Vector2 new_pos = mtx.affine_inverse().xform(Vector2(mm.x,mm.y));
			new_pos = snap_point(new_pos);

			if (creating) {
				rect = Rect2(drag_from,Size2());
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
				edit_draw->update();
				return;
			}

			switch(drag_index) {
			case 0: {
				Vector2 p=rect_prev.pos+rect_prev.size;
				rect = Rect2(p,Size2());
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
			} break;
			case 1: {
				Vector2 p=rect_prev.pos+Vector2(0,rect_prev.size.y);
				rect = Rect2(p,Size2(rect_prev.size.x,0));
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
			} break;
			case 2: {
				Vector2 p=rect_prev.pos+Vector2(0,rect_prev.size.y);
				rect = Rect2(p,Size2());
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
			} break;
			case 3: {
				Vector2 p=rect_prev.pos;
				rect = Rect2(p,Size2(0,rect_prev.size.y));
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
			} break;
			case 4: {
				Vector2 p=rect_prev.pos;
				rect = Rect2(p,Size2());
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
			} break;
			case 5: {
				Vector2 p=rect_prev.pos;
				rect = Rect2(p,Size2(rect_prev.size.x,0));
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
			} break;
			case 6: {
				Vector2 p=rect_prev.pos+Vector2(rect_prev.size.x,0);
				rect = Rect2(p,Size2());
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
			} break;
			case 7: {
				Vector2 p=rect_prev.pos+Vector2(rect_prev.size.x,0);
				rect = Rect2(p,Size2(0,rect_prev.size.y));
				rect.expand_to(new_pos);
				node->set_region_rect(rect);
			} break;

			}
			edit_draw->update();
		}

	}
}
Ejemplo n.º 9
0
void TileMapEditor::_canvas_draw() {

	if (!node)
		return;

	Size2 cell_size=node->get_cell_size();
	Matrix32 cell_xf = node->get_cell_transform();

	Matrix32 xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
	Matrix32 xform_inv = xform.affine_inverse();


	Size2 screen_size=canvas_item_editor->get_size();
	{
		Rect2 aabb;
		aabb.pos=node->world_to_map(xform_inv.xform(Vector2()));
		aabb.expand_to(node->world_to_map(xform_inv.xform(Vector2(0,screen_size.height))));
		aabb.expand_to(node->world_to_map(xform_inv.xform(Vector2(screen_size.width,0))));
		aabb.expand_to(node->world_to_map(xform_inv.xform(screen_size)));
		Rect2i si=aabb.grow(1.0);

		if (node->get_half_offset()!=TileMap::HALF_OFFSET_X) {

			for(int i=(si.pos.x)-1;i<=(si.pos.x+si.size.x);i++) {

				Vector2 from = xform.xform(node->map_to_world(Vector2(i,si.pos.y)));
				Vector2 to = xform.xform(node->map_to_world(Vector2(i,si.pos.y+si.size.y+1)));

				Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
				canvas_item_editor->draw_line(from,to,col,1);

			}
		} else {


			for(int i=(si.pos.x)-1;i<=(si.pos.x+si.size.x);i++) {

				for(int j=(si.pos.y)-1;j<=(si.pos.y+si.size.y);j++) {

					Vector2 ofs;
					if (ABS(j)&1) {
						ofs=cell_xf[0]*0.5;
					}

					Vector2 from = xform.xform(node->map_to_world(Vector2(i,j),true)+ofs);
					Vector2 to = xform.xform(node->map_to_world(Vector2(i,j+1),true)+ofs);
					Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
					canvas_item_editor->draw_line(from,to,col,1);
				}

			}
		}

		if (node->get_half_offset()!=TileMap::HALF_OFFSET_Y) {

			for(int i=(si.pos.y)-1;i<=(si.pos.y+si.size.y);i++) {

				Vector2 from = xform.xform(node->map_to_world(Vector2(si.pos.x,i)));
				Vector2 to = xform.xform(node->map_to_world(Vector2(si.pos.x+si.size.x+1,i)));

				Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
				canvas_item_editor->draw_line(from,to,col,1);

			}
		} else {


			for(int i=(si.pos.y)-1;i<=(si.pos.y+si.size.y);i++) {

				for(int j=(si.pos.x)-1;j<=(si.pos.x+si.size.x);j++) {

					Vector2 ofs;
					if (ABS(j)&1) {
						ofs=cell_xf[1]*0.5;
					}

					Vector2 from = xform.xform(node->map_to_world(Vector2(j,i),true)+ofs);
					Vector2 to = xform.xform(node->map_to_world(Vector2(j+1,i),true)+ofs);
					Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
					canvas_item_editor->draw_line(from,to,col,1);
				}

			}



		}
/*
	for(int i=(si.pos.y/cell_size.y)-1;i<=(si.pos.y+si.size.y)/cell_size.y;i++) {

		int ofs = i*cell_size.y;
		Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
		canvas_item_editor->draw_line(xform.xform(Point2(si.pos.x,ofs)),xform.xform(Point2(si.pos.x+si.size.x,ofs)),col,1);*/
	}


	if (selection_active) {

		Vector<Vector2> points;
		points.push_back( xform.xform( node->map_to_world(( selection.pos ) )));
		points.push_back( xform.xform( node->map_to_world((selection.pos+Point2(selection.size.x+1,0)) ) ));
		points.push_back( xform.xform( node->map_to_world((selection.pos+Point2(selection.size.x+1,selection.size.y+1)) ) ));
		points.push_back( xform.xform( node->map_to_world((selection.pos+Point2(0,selection.size.y+1)) ) ));
		Color col=Color(0.2,0.8,1,0.4);

		canvas_item_editor->draw_colored_polygon(points,col);
	}


	if (mouse_over){

		Vector2 endpoints[4]={

			( node->map_to_world(over_tile,true) ) ,
			( node->map_to_world((over_tile+Point2(1,0)),true ) ),
			( node->map_to_world((over_tile+Point2(1,1)),true ) ),
			( node->map_to_world((over_tile+Point2(0,1)),true ) )

		};

		for(int i=0;i<4;i++) {
			if (node->get_half_offset()==TileMap::HALF_OFFSET_X && ABS(over_tile.y)&1)
				endpoints[i]+=cell_xf[0]*0.5;
			if (node->get_half_offset()==TileMap::HALF_OFFSET_Y && ABS(over_tile.x)&1)
				endpoints[i]+=cell_xf[1]*0.5;
			endpoints[i]=xform.xform(endpoints[i]);
		}
		Color col;
		if (node->get_cell(over_tile.x,over_tile.y)!=TileMap::INVALID_CELL)
			col=Color(0.2,0.8,1.0,0.8);
		else
			col=Color(1.0,0.4,0.2,0.8);

		for(int i=0;i<4;i++)
			canvas_item_editor->draw_line(endpoints[i],endpoints[(i+1)%4],col,2);



		if (tool==TOOL_DUPLICATING) {

			Rect2i duplicate=selection;
			duplicate.pos=over_tile;


			Vector<Vector2> points;
			points.push_back( xform.xform( node->map_to_world(duplicate.pos ) ));
			points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(duplicate.size.x+1,0)) ) ));
			points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(duplicate.size.x+1,duplicate.size.y+1))) ));
			points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(0,duplicate.size.y+1))) ));
			Color col=Color(0.2,1.0,0.8,0.4);

			canvas_item_editor->draw_colored_polygon(points,col);

		} else {

			Ref<TileSet> ts = node->get_tileset();


			if (ts.is_valid()) {

				int st = get_selected_tile();
				if (ts->has_tile(st)) {

					Ref<Texture> t = ts->tile_get_texture(st);
					if (t.is_valid()) {
						Vector2 from = node->map_to_world(over_tile)+node->get_cell_draw_offset();
						Rect2 r = ts->tile_get_region(st);
						Size2 sc = xform.get_scale();
						if (mirror_x->is_pressed())
							sc.x*=-1.0;
						if (mirror_y->is_pressed())
							sc.y*=-1.0;

						Rect2 rect;
						if (r==Rect2()) {
							rect=Rect2(from,t->get_size());
						} else {

							rect=Rect2(from,r.get_size());
						}


						if (node->get_tile_origin()==TileMap::TILE_ORIGIN_TOP_LEFT) {
							rect.pos+=ts->tile_get_texture_offset(st);

						} else if (node->get_tile_origin()==TileMap::TILE_ORIGIN_CENTER) {
							rect.pos+=node->get_cell_size()/2;
							Vector2 s = r.size;

							Vector2 center = (s/2) - ts->tile_get_texture_offset(st);


							if (mirror_x->is_pressed())
								rect.pos.x-=s.x-center.x;
							else
								rect.pos.x-=center.x;

							if (mirror_y->is_pressed())
								rect.pos.y-=s.y-center.y;
							else
								rect.pos.y-=center.y;
						}

						rect.pos=xform.xform(rect.pos);
						rect.size*=sc;

						if (r==Rect2()) {

							canvas_item_editor->draw_texture_rect(t,rect,false,Color(1,1,1,0.5),transpose->is_pressed());
						} else {

							canvas_item_editor->draw_texture_rect_region(t,rect,r,Color(1,1,1,0.5),transpose->is_pressed());
						}
					}
				}
			}

		}
	}



}
Ejemplo n.º 10
0
bool TileMapEditor::forward_input_event(const InputEvent& p_event) {

	if (!node || !node->get_tileset().is_valid())
		return false;

	Matrix32 xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
	Matrix32 xform_inv = xform.affine_inverse();
	Vector2 snap = node->get_cell_size();


	switch(p_event.type) {

		case InputEvent::MOUSE_BUTTON: {

			const InputEventMouseButton &mb=p_event.mouse_button;

			if (mb.button_index==BUTTON_LEFT) {


				if (mb.pressed && tool==TOOL_DUPLICATING) {


					List<_TileMapEditorCopyData> dupdata;
					Point2 ofs = over_tile-selection.pos;

					for(int i=selection.pos.y;i<=selection.pos.y+selection.size.y;i++) {

						for(int j=selection.pos.x;j<=selection.pos.x+selection.size.x;j++) {

							_TileMapEditorCopyData tcd;
							tcd.pos=Point2i(j,i);
							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);


						}
					}

					undo_redo->create_action("Duplicate");
					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,E->get().transpose,true);
					}
					undo_redo->commit_action();

					tool=TOOL_NONE;
					canvas_item_editor->update();
					selection.pos=over_tile;

				} else if (mb.pressed && tool==TOOL_NONE) {

					if (Input::get_singleton()->is_key_pressed(KEY_SPACE))
						return false; //drag
					if (mb.mod.shift) {

						tool=TOOL_SELECTING;
						selection_begin =node->world_to_map(xform_inv.xform(Point2(mb.x,mb.y)));
						selection.pos=selection_begin;
						selection.size=Point2(0,0);
						selection_active=true;
						canvas_item_editor->update();
						return true;

					} 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 {
						int id = get_selected_tile();
						if (id!=TileMap::INVALID_CELL) {
							tool=TOOL_PAINTING;
							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(),transpose->is_pressed());
							return true;
						}
					}
				} else {

					if (tool==TOOL_PAINTING || tool == TOOL_SELECTING || tool == TOOL_PICKING) {

						if (tool==TOOL_PAINTING) {

							if (paint_undo.size()) {
								undo_redo->create_action("Paint TileMap");
								for(Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {

									Point2i p=E->key();
									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();
								paint_undo.clear();
							}
						}
						tool=TOOL_NONE;
						return true;
					}
				}
			}

			if (mb.button_index==BUTTON_RIGHT) {

				if (mb.pressed && tool==TOOL_DUPLICATING) {

					tool=TOOL_NONE;
					canvas_item_editor->update();
				} else if (mb.pressed && tool==TOOL_NONE) {

					tool=TOOL_ERASING;
					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(),transpose->is_pressed());
					//return true;
					_set_cell(local,TileMap::INVALID_CELL);
					return true;
				} else {

					if (tool==TOOL_ERASING) {

						if (paint_undo.size()) {
							undo_redo->create_action("Erase TileMap");
							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),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();
							paint_undo.clear();

						}
						tool=TOOL_NONE;
						return true;
					}
				}
			}

		} break;
		case InputEvent::MOUSE_MOTION: {

			const InputEventMouseMotion &mm=p_event.mouse_motion;

			Point2i new_over_tile = node->world_to_map(xform_inv.xform(Point2(mm.x,mm.y)));//(xform_inv.xform(Point2(mm.x,mm.y))/snap).floor();
			if (new_over_tile!=over_tile) {

				over_tile=new_over_tile;
				canvas_item_editor->update();
			}



			if (tool==TOOL_PAINTING) {

				int id = get_selected_tile();
				if (id!=TileMap::INVALID_CELL) {

					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(),transpose->is_pressed());

					return true;
				}
			}

			if (tool==TOOL_SELECTING) {

				Point2i begin=selection_begin;
				Point2i end =over_tile;

				if (begin.x > end.x) {

					SWAP( begin.x, end.x);
				}
				if (begin.y > end.y) {

					SWAP( begin.y, end.y);
				}

				selection.pos=begin;
				selection.size=end-begin;
				canvas_item_editor->update();

				return true;

			}

			if (tool==TOOL_ERASING) {
				Point2i local =over_tile;
				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(),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;
			}

		} break;
		case InputEvent::KEY: {

			const InputEventKey &k = p_event.key;
			if (!node)
				break;

			if (k.pressed && k.scancode==KEY_DELETE && selection_active && tool==TOOL_NONE) {

				undo_redo->create_action("Delete");
				for(int i=selection.pos.y;i<=selection.pos.y+selection.size.y;i++) {

					for(int j=selection.pos.x;j<=selection.pos.x+selection.size.x;j++) {


						_set_cell(Point2i(j,i),TileMap::INVALID_CELL);
					}
				}
				undo_redo->commit_action();

				selection_active=false;
				canvas_item_editor->update();
				return true;
			}

			if (mouse_over && k.pressed && k.scancode==KEY_A  && tool==TOOL_NONE && !k.mod.command) {

				/*int cell = node->get_cell(over_tile.x,over_tile.y);
				if (cell!=TileMap::INVALID_CELL) {
					bool flip_h = node->is_cell_x_flipped(over_tile.x,over_tile.y);
					bool flip_v = node->is_cell_y_flipped(over_tile.x,over_tile.y);
					_set_cell(over_tile,cell,!flip_h,flip_v);
				}*/

				mirror_x->set_pressed( ! mirror_x->is_pressed() );
				canvas_item_editor->update();
				return true;
			}
			if (mouse_over && k.pressed && k.scancode==KEY_S  && tool==TOOL_NONE && !k.mod.command) {


				/*
				int cell = node->get_cell(over_tile.x,over_tile.y);
				if (cell!=TileMap::INVALID_CELL) {

					bool flip_h = node->is_cell_x_flipped(over_tile.x,over_tile.y);
					bool flip_v = node->is_cell_y_flipped(over_tile.x,over_tile.y);
					_set_cell(over_tile,cell,flip_h,!flip_v);
				}*/

				mirror_y->set_pressed( ! mirror_y->is_pressed() );
				canvas_item_editor->update();
				return true;
			}

			if (mouse_over && selection_active && k.pressed && k.mod.command && k.scancode==KEY_D && tool==TOOL_NONE) {

				tool=TOOL_DUPLICATING;
				canvas_item_editor->update();
				return true;
			}



		} break;
	}

	return false;
}
Ejemplo n.º 11
0
bool Path2DEditor::forward_input_event(const InputEvent& p_event) {

	if (!node)
		return false;

	if (!node->is_visible())
		return false;

	if (!node->get_curve().is_valid())
		return false;

	switch(p_event.type) {

		case InputEvent::MOUSE_BUTTON: {

			const InputEventMouseButton &mb=p_event.mouse_button;

			Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();

			Vector2 gpoint = Point2(mb.x,mb.y);
			Vector2 cpoint = !mb.mod.alt? canvas_item_editor->snap_point(xform.affine_inverse().xform(gpoint))
										: node->get_global_transform().affine_inverse().xform( canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) );

			//first check if a point is to be added (segment split)
			real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);



			// Test move point!!

			if ( mb.pressed && action==ACTION_NONE ) {

				Ref<Curve2D> curve = node->get_curve();

				for(int i=0;i<curve->get_point_count();i++) {

					bool pointunder=false;

					{
						Point2 p = xform.xform( curve->get_point_pos(i) );
						if (gpoint.distance_to(p) < grab_treshold ) {

							if (mb.button_index==BUTTON_LEFT && !mb.mod.shift && mode==MODE_EDIT) {

								action=ACTION_MOVING_POINT;
								action_point=i;
								moving_from=curve->get_point_pos(i);
								moving_screen_from=gpoint;
								return true;
							} else if  ((mb.button_index==BUTTON_RIGHT && mode==MODE_EDIT) || (mb.button_index==BUTTON_LEFT && mode==MODE_DELETE)) {

								undo_redo->create_action(TTR("Remove Point from Curve"));
								undo_redo->add_do_method(curve.ptr(),"remove_point",i);
								undo_redo->add_undo_method(curve.ptr(),"add_point",curve->get_point_pos(i),curve->get_point_in(i),curve->get_point_out(i),i);
								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
								undo_redo->commit_action();
								return true;
							} else
								pointunder=true;
						}
					}

					if (mb.button_index==BUTTON_LEFT && i<(curve->get_point_count()-1)) {
						Point2 p = xform.xform( curve->get_point_pos(i)+curve->get_point_out(i) );
						if (gpoint.distance_to(p) < grab_treshold && (mode == MODE_EDIT || mode==MODE_EDIT_CURVE) ) {

							action=ACTION_MOVING_OUT;
							action_point=i;
							moving_from=curve->get_point_out(i);
							moving_screen_from=gpoint;
							return true;
						}
					}

					if (mb.button_index==BUTTON_LEFT && i>0) {
						Point2 p = xform.xform( curve->get_point_pos(i)+curve->get_point_in(i) );
						if (gpoint.distance_to(p) < grab_treshold && (mode == MODE_EDIT || mode==MODE_EDIT_CURVE)) {

							action=ACTION_MOVING_IN;
							action_point=i;
							moving_from=curve->get_point_in(i);
							moving_screen_from=gpoint;
							return true;
						}
					}

					if (pointunder)
						return true;

				}

			}

			// Test add point in empty space!

			if ( mb.pressed && mb.button_index==BUTTON_LEFT && ((mb.mod.command && mode == MODE_EDIT) || mode == MODE_CREATE)) {

				Ref<Curve2D> curve = node->get_curve();

				undo_redo->create_action(TTR("Add Point to Curve"));
				undo_redo->add_do_method(curve.ptr(),"add_point",cpoint);
				undo_redo->add_undo_method(curve.ptr(),"remove_point",curve->get_point_count());
				undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
				undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
				undo_redo->commit_action();

				action=ACTION_MOVING_POINT;
				action_point=curve->get_point_count()-1;
				moving_from=curve->get_point_pos(action_point);
				moving_screen_from=gpoint;

				canvas_item_editor->get_viewport_control()->update();

				return true;
			}

			if ( !mb.pressed && mb.button_index==BUTTON_LEFT && action!=ACTION_NONE) {


				Ref<Curve2D> curve = node->get_curve();

				Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
				switch(action) {

					case ACTION_MOVING_POINT: {


						undo_redo->create_action(TTR("Move Point in Curve"));
						undo_redo->add_do_method(curve.ptr(),"set_point_pos",action_point,cpoint);
						undo_redo->add_undo_method(curve.ptr(),"set_point_pos",action_point,moving_from);
						undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
						undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
						undo_redo->commit_action();

					} break;
					case ACTION_MOVING_IN: {

						undo_redo->create_action(TTR("Move In-Control in Curve"));
						undo_redo->add_do_method(curve.ptr(),"set_point_in",action_point,new_pos);
						undo_redo->add_undo_method(curve.ptr(),"set_point_in",action_point,moving_from);
						undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
						undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
						undo_redo->commit_action();

					} break;
					case ACTION_MOVING_OUT: {

						undo_redo->create_action(TTR("Move Out-Control in Curve"));
						undo_redo->add_do_method(curve.ptr(),"set_point_out",action_point,new_pos);
						undo_redo->add_undo_method(curve.ptr(),"set_point_out",action_point,moving_from);
						undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
						undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
						undo_redo->commit_action();

					} break;

				}

				action=ACTION_NONE;

				return true;
			}


#if 0
			switch(mode) {


				case MODE_CREATE: {

					if (mb.button_index==BUTTON_LEFT && mb.pressed) {


						if (!wip_active) {

							wip.clear();
							wip.push_back( canvas_item_editor->snap_point(cpoint) );
							wip_active=true;
							edited_point_pos=canvas_item_editor->snap_point(cpoint);
							canvas_item_editor->update();
							edited_point=1;
							return true;
						} else {

							if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
								//wip closed
								_wip_close();

								return true;
							} else {

								wip.push_back( canvas_item_editor->snap_point(cpoint) );
								edited_point=wip.size();
								canvas_item_editor->update();
								return true;

								//add wip point
							}
						}
					} else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) {
						_wip_close();
					}



				} break;

				case MODE_EDIT: {

					if (mb.button_index==BUTTON_LEFT) {
						if (mb.pressed) {

							if (mb.mod.control) {


								if (poly.size() < 3) {

									undo_redo->create_action(TTR("Edit Poly"));
									undo_redo->add_undo_method(node,"set_polygon",poly);
									poly.push_back(cpoint);
									undo_redo->add_do_method(node,"set_polygon",poly);
									undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
									undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
									undo_redo->commit_action();
									return true;
								}

								//search edges
								int closest_idx=-1;
								Vector2 closest_pos;
								real_t closest_dist=1e10;
								for(int i=0;i<poly.size();i++) {

									Vector2 points[2] ={ xform.xform(poly[i]),
										xform.xform(poly[(i+1)%poly.size()]) };

									Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
									if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2)
										continue; //not valid to reuse point

									real_t d = cp.distance_to(gpoint);
									if (d<closest_dist && d<grab_treshold) {
										closest_dist=d;
										closest_pos=cp;
										closest_idx=i;
									}


								}

								if (closest_idx>=0) {

									pre_move_edit=poly;
									poly.insert(closest_idx+1,canvas_item_editor->snap_point(xform.affine_inverse().xform(closest_pos)));
									edited_point=closest_idx+1;
									edited_point_pos=canvas_item_editor->snap_point(xform.affine_inverse().xform(closest_pos));
									node->set_polygon(poly);
									canvas_item_editor->update();
									return true;
								}
							} else {

								//look for points to move

								int closest_idx=-1;
								Vector2 closest_pos;
								real_t closest_dist=1e10;
								for(int i=0;i<poly.size();i++) {

									Vector2 cp =xform.xform(poly[i]);

									real_t d = cp.distance_to(gpoint);
									if (d<closest_dist && d<grab_treshold) {
										closest_dist=d;
										closest_pos=cp;
										closest_idx=i;
									}

								}

								if (closest_idx>=0) {

									pre_move_edit=poly;
									edited_point=closest_idx;
									edited_point_pos=xform.affine_inverse().xform(closest_pos);
									canvas_item_editor->update();
									return true;
								}
							}
						} else {

							if (edited_point!=-1) {

								//apply

								ERR_FAIL_INDEX_V(edited_point,poly.size(),false);
								poly[edited_point]=edited_point_pos;
								undo_redo->create_action(TTR("Edit Poly"));
								undo_redo->add_do_method(node,"set_polygon",poly);
								undo_redo->add_undo_method(node,"set_polygon",pre_move_edit);
								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
								undo_redo->commit_action();

								edited_point=-1;
								return true;
							}
						}
					} if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) {



						int closest_idx=-1;
						Vector2 closest_pos;
						real_t closest_dist=1e10;
						for(int i=0;i<poly.size();i++) {

							Vector2 cp =xform.xform(poly[i]);

							real_t d = cp.distance_to(gpoint);
							if (d<closest_dist && d<grab_treshold) {
								closest_dist=d;
								closest_pos=cp;
								closest_idx=i;
							}

						}

						if (closest_idx>=0) {


							undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
							undo_redo->add_undo_method(node,"set_polygon",poly);
							poly.remove(closest_idx);
							undo_redo->add_do_method(node,"set_polygon",poly);
							undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
							undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
							undo_redo->commit_action();
							return true;
						}

					}



				} break;
			}


#endif
		} break;
		case InputEvent::MOUSE_MOTION: {

			const InputEventMouseMotion &mm=p_event.mouse_motion;


			if ( action!=ACTION_NONE) {

				Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
				Vector2 gpoint = Point2(mm.x,mm.y);
				Vector2 cpoint = !mm.mod.alt? canvas_item_editor->snap_point(xform.affine_inverse().xform(gpoint))
											: node->get_global_transform().affine_inverse().xform( canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) );

				Ref<Curve2D> curve = node->get_curve();

				Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);

				switch(action) {

					case ACTION_MOVING_POINT: {

						curve->set_point_pos(action_point,cpoint);
					} break;
					case ACTION_MOVING_IN: {

						curve->set_point_in(action_point,new_pos);

					} break;
					case ACTION_MOVING_OUT: {

						curve->set_point_out(action_point,new_pos);

					} break;
				}


				canvas_item_editor->get_viewport_control()->update();
				return true;
			}

#if 0
			if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {


				Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();

				Vector2 gpoint = Point2(mm.x,mm.y);
				edited_point_pos = canvas_item_editor->snap_point(xform.affine_inverse().xform(gpoint));
				canvas_item_editor->update();

			}
#endif
		} break;
	}

	return false;
}
Ejemplo n.º 12
0
static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) {

	const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW*>(p_a);
	const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW*>(p_b);


	SeparatorAxisTest2D<RectangleShape2DSW,CapsuleShape2DSW,castA,castB> separator(rectangle_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b);

	if (!separator.test_previous_axis())
		return;

	if (!separator.test_cast())
		return;

	//box faces
	if (!separator.test_axis(p_transform_a.elements[0].normalized()))
		return;

	if (!separator.test_axis(p_transform_a.elements[1].normalized()))
		return;

	//capsule axis
	if (!separator.test_axis(p_transform_b.elements[0].normalized()))
		return;


	//box endpoints to capsule circles

	Matrix32 boxinv = p_transform_a.affine_inverse();

	for(int i=0;i<2;i++) {

		{
			Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5);

			const Vector2& half_extents = rectangle_A->get_half_extents();
			Vector2 local_v = boxinv.xform(capsule_endpoint);

			Vector2 he(
				(local_v.x<0) ? -half_extents.x : half_extents.x,
				(local_v.y<0) ? -half_extents.y : half_extents.y
			);

			if (!separator.test_axis(p_transform_a.xform(he-capsule_endpoint).normalized()))
				return;
		}


		if (castA) {
			Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5);
			capsule_endpoint-=p_motion_a;


			const Vector2& half_extents = rectangle_A->get_half_extents();
			Vector2 local_v = boxinv.xform(capsule_endpoint);

			Vector2 he(
				(local_v.x<0) ? -half_extents.x : half_extents.x,
				(local_v.y<0) ? -half_extents.y : half_extents.y
			);

			if (!separator.test_axis(p_transform_a.xform(he-capsule_endpoint).normalized()))
				return;
		}

		if (castB) {
			Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5);
			capsule_endpoint+=p_motion_b;


			const Vector2& half_extents = rectangle_A->get_half_extents();
			Vector2 local_v = boxinv.xform(capsule_endpoint);

			Vector2 he(
				(local_v.x<0) ? -half_extents.x : half_extents.x,
				(local_v.y<0) ? -half_extents.y : half_extents.y
			);

			if (!separator.test_axis(p_transform_a.xform(he-capsule_endpoint).normalized()))
				return;
		}

		if (castA && castB) {
			Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5);
			capsule_endpoint-=p_motion_a;
			capsule_endpoint+=p_motion_b;


			const Vector2& half_extents = rectangle_A->get_half_extents();
			Vector2 local_v = boxinv.xform(capsule_endpoint);

			Vector2 he(
				(local_v.x<0) ? -half_extents.x : half_extents.x,
				(local_v.y<0) ? -half_extents.y : half_extents.y
			);

			if (!separator.test_axis(p_transform_a.xform(he-capsule_endpoint).normalized()))
				return;
		}

	}


	separator.generate_contacts();
}
Ejemplo n.º 13
0
void TileMapEditor::_canvas_draw() {

	if (!node)
		return;

	Matrix32 cell_xf = node->get_cell_transform();

	Matrix32 xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
	Matrix32 xform_inv = xform.affine_inverse();


	Size2 screen_size=canvas_item_editor->get_size();
	{
		Rect2 aabb;
		aabb.pos=node->world_to_map(xform_inv.xform(Vector2()));
		aabb.expand_to(node->world_to_map(xform_inv.xform(Vector2(0,screen_size.height))));
		aabb.expand_to(node->world_to_map(xform_inv.xform(Vector2(screen_size.width,0))));
		aabb.expand_to(node->world_to_map(xform_inv.xform(screen_size)));
		Rect2i si=aabb.grow(1.0);

		if (node->get_half_offset()!=TileMap::HALF_OFFSET_X) {

			int max_lines=2000; //avoid crash if size too smal

			for (int i=(si.pos.x)-1;i<=(si.pos.x+si.size.x);i++) {

				Vector2 from = xform.xform(node->map_to_world(Vector2(i,si.pos.y)));
				Vector2 to = xform.xform(node->map_to_world(Vector2(i,si.pos.y+si.size.y+1)));

				Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
				canvas_item_editor->draw_line(from,to,col,1);
				if (max_lines--==0)
					break;
			}
		} else {

			int max_lines=10000; //avoid crash if size too smal

			for (int i=(si.pos.x)-1;i<=(si.pos.x+si.size.x);i++) {

				for (int j=(si.pos.y)-1;j<=(si.pos.y+si.size.y);j++) {

					Vector2 ofs;
					if (ABS(j)&1) {
						ofs=cell_xf[0]*0.5;
					}

					Vector2 from = xform.xform(node->map_to_world(Vector2(i,j),true)+ofs);
					Vector2 to = xform.xform(node->map_to_world(Vector2(i,j+1),true)+ofs);
					Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
					canvas_item_editor->draw_line(from,to,col,1);

					if (max_lines--==0)
						break;

				}

			}
		}

		int max_lines=10000; //avoid crash if size too smal

		if (node->get_half_offset()!=TileMap::HALF_OFFSET_Y) {

			for (int i=(si.pos.y)-1;i<=(si.pos.y+si.size.y);i++) {

				Vector2 from = xform.xform(node->map_to_world(Vector2(si.pos.x,i)));
				Vector2 to = xform.xform(node->map_to_world(Vector2(si.pos.x+si.size.x+1,i)));

				Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
				canvas_item_editor->draw_line(from,to,col,1);

				if (max_lines--==0)
					break;

			}
		} else {


			for (int i=(si.pos.y)-1;i<=(si.pos.y+si.size.y);i++) {

				for (int j=(si.pos.x)-1;j<=(si.pos.x+si.size.x);j++) {

					Vector2 ofs;
					if (ABS(j)&1) {
						ofs=cell_xf[1]*0.5;
					}

					Vector2 from = xform.xform(node->map_to_world(Vector2(j,i),true)+ofs);
					Vector2 to = xform.xform(node->map_to_world(Vector2(j+1,i),true)+ofs);
					Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
					canvas_item_editor->draw_line(from,to,col,1);

					if (max_lines--==0)
						break;

				}
			}
		}
	}

	if (selection_active) {

		Vector<Vector2> points;
		points.push_back( xform.xform( node->map_to_world(( rectangle.pos ) )));
		points.push_back( xform.xform( node->map_to_world((rectangle.pos+Point2(rectangle.size.x+1,0)) ) ));
		points.push_back( xform.xform( node->map_to_world((rectangle.pos+Point2(rectangle.size.x+1,rectangle.size.y+1)) ) ));
		points.push_back( xform.xform( node->map_to_world((rectangle.pos+Point2(0,rectangle.size.y+1)) ) ));

		canvas_item_editor->draw_colored_polygon(points, Color(0.2,0.8,1,0.4));
	}

	if (mouse_over){

		Vector2 endpoints[4]={
			node->map_to_world(over_tile, true),
			node->map_to_world((over_tile+Point2(1,0)), true),
			node->map_to_world((over_tile+Point2(1,1)), true),
			node->map_to_world((over_tile+Point2(0,1)), true)
		};

		for (int i=0;i<4;i++) {
			if (node->get_half_offset()==TileMap::HALF_OFFSET_X && ABS(over_tile.y)&1)
				endpoints[i]+=cell_xf[0]*0.5;
			if (node->get_half_offset()==TileMap::HALF_OFFSET_Y && ABS(over_tile.x)&1)
				endpoints[i]+=cell_xf[1]*0.5;
			endpoints[i]=xform.xform(endpoints[i]);
		}
		Color col;
		if (node->get_cell(over_tile.x,over_tile.y)!=TileMap::INVALID_CELL)
			col=Color(0.2,0.8,1.0,0.8);
		else
			col=Color(1.0,0.4,0.2,0.8);

		for (int i=0;i<4;i++)
			canvas_item_editor->draw_line(endpoints[i],endpoints[(i+1)%4],col,2);


		if (tool==TOOL_SELECTING || tool==TOOL_PICKING || tool==TOOL_BUCKET) {

			return;
		}

		if (tool==TOOL_LINE_PAINT) {

			if (paint_undo.empty())
				return;

			int id = get_selected_tile();

			if (id==TileMap::INVALID_CELL)
				return;

			for (Map<Point2i, CellOp>::Element *E=paint_undo.front();E;E=E->next()) {

				_draw_cell(id, E->key(), flip_h, flip_v, transpose, xform);
			}

		} else if (tool==TOOL_RECTANGLE_PAINT) {

			int id = get_selected_tile();

			if (id==TileMap::INVALID_CELL)
				return;

			for (int i=rectangle.pos.y;i<=rectangle.pos.y+rectangle.size.y;i++) {
				for (int j=rectangle.pos.x;j<=rectangle.pos.x+rectangle.size.x;j++) {

					_draw_cell(id, Point2i(j, i), flip_h, flip_v, transpose, xform);
				}
			}
		} else if (tool==TOOL_DUPLICATING) {

			if (copydata.empty())
				return;

			Ref<TileSet> ts = node->get_tileset();

			if (ts.is_null())
				return;

			Point2 ofs = over_tile-rectangle.pos;

			for (List<TileData>::Element *E=copydata.front();E;E=E->next()) {

				if (!ts->has_tile(E->get().cell))
					continue;

				TileData tcd = E->get();

				_draw_cell(tcd.cell, tcd.pos+ofs, tcd.flip_h, tcd.flip_v, tcd.transpose, xform);
			}

			Rect2i duplicate=rectangle;
			duplicate.pos=over_tile;

			Vector<Vector2> points;
			points.push_back( xform.xform( node->map_to_world(duplicate.pos ) ));
			points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(duplicate.size.x+1,0)) ) ));
			points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(duplicate.size.x+1,duplicate.size.y+1))) ));
			points.push_back( xform.xform( node->map_to_world((duplicate.pos+Point2(0,duplicate.size.y+1))) ));

			canvas_item_editor->draw_colored_polygon(points, Color(0.2,1.0,0.8,0.2));

		} else {

			int st = get_selected_tile();

			if (st==TileMap::INVALID_CELL)
				return;

			_draw_cell(st, over_tile, flip_h, flip_v, transpose, xform);
		}
	}
}
Ejemplo n.º 14
0
static void _collision_circle_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b) {

	const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW*>(p_a);
	const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW*>(p_b);


	SeparatorAxisTest2D<CircleShape2DSW,RectangleShape2DSW,castA,castB> separator(circle_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b);

	if (!separator.test_previous_axis())
		return;

	if (!separator.test_cast())
		return;

	const Vector2 &sphere=p_transform_a.elements[2];
	const Vector2 *axis=&p_transform_b.elements[0];
	const Vector2& half_extents = rectangle_B->get_half_extents();

	if (!separator.test_axis(axis[0].normalized()))
		return;

	if (!separator.test_axis(axis[1].normalized()))
		return;

	{
		Vector2 local_v = p_transform_b.affine_inverse().xform(p_transform_a.get_origin());

		Vector2 he(
			(local_v.x<0) ? -half_extents.x : half_extents.x,
			(local_v.y<0) ? -half_extents.y : half_extents.y
		);


		if (!separator.test_axis((p_transform_b.xform(he)-sphere).normalized()))
			return;
	}

	if (castA) {

		Vector2 sphereofs = sphere + p_motion_a;
		Vector2 local_v = p_transform_b.affine_inverse().xform(sphereofs);

		Vector2 he(
			(local_v.x<0) ? -half_extents.x : half_extents.x,
			(local_v.y<0) ? -half_extents.y : half_extents.y
		);


		if (!separator.test_axis((p_transform_b.xform(he)-sphereofs).normalized()))
			return;
	}

	if (castB) {

		Vector2 sphereofs = sphere - p_motion_b;
		Vector2 local_v = p_transform_b.affine_inverse().xform(sphereofs);

		Vector2 he(
			(local_v.x<0) ? -half_extents.x : half_extents.x,
			(local_v.y<0) ? -half_extents.y : half_extents.y
		);


		if (!separator.test_axis((p_transform_b.xform(he)-sphereofs).normalized()))
			return;
	}

	if (castA && castB) {

		Vector2 sphereofs = sphere - p_motion_b + p_motion_a;
		Vector2 local_v = p_transform_b.affine_inverse().xform(sphereofs);

		Vector2 he(
			(local_v.x<0) ? -half_extents.x : half_extents.x,
			(local_v.y<0) ? -half_extents.y : half_extents.y
		);


		if (!separator.test_axis((p_transform_b.xform(he)-sphereofs).normalized()))
			return;
	}

	separator.generate_contacts();
}
Ejemplo n.º 15
0
static void _collision_rectangle_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) {

	const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW*>(p_a);
	const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW*>(p_b);


	SeparatorAxisTest2D<RectangleShape2DSW,RectangleShape2DSW,castA,castB,withMargin> separator(rectangle_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B);

	if (!separator.test_previous_axis())
		return;

	if (!separator.test_cast())
		return;

	//box faces A
	if (!separator.test_axis(p_transform_a.elements[0].normalized()))
		return;

	if (!separator.test_axis(p_transform_a.elements[1].normalized()))
		return;

	//box faces B
	if (!separator.test_axis(p_transform_b.elements[0].normalized()))
		return;

	if (!separator.test_axis(p_transform_b.elements[1].normalized()))
		return;

	if (withMargin) {

		Matrix32 invA=p_transform_a.affine_inverse();
		Matrix32 invB=p_transform_b.affine_inverse();

		if (!separator.test_axis( rectangle_A->get_box_axis(p_transform_a,invA,rectangle_B,p_transform_b,invB) ) )
			return;

		if (castA || castB) {

			Matrix32 aofs = p_transform_a;
			aofs.elements[2]+=p_motion_a;

			Matrix32 bofs = p_transform_b;
			bofs.elements[2]+=p_motion_b;

			Matrix32 aofsinv = aofs.affine_inverse();
			Matrix32 bofsinv = bofs.affine_inverse();

			if (castA) {

				if (!separator.test_axis( rectangle_A->get_box_axis(aofs,aofsinv,rectangle_B,p_transform_b,invB) ) )
					return;
			}

			if (castB) {

				if (!separator.test_axis( rectangle_A->get_box_axis(p_transform_a,invA,rectangle_B,bofs,bofsinv) ) )
					return;
			}

			if (castA && castB) {

				if (!separator.test_axis( rectangle_A->get_box_axis(aofs,aofsinv,rectangle_B,bofs,bofsinv) ) )
					return;
			}
		}
	}

	separator.generate_contacts();
}
Ejemplo n.º 16
0
static void _collision_segment_rectangle(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) {

	const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW*>(p_a);
	const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW*>(p_b);

	SeparatorAxisTest2D<SegmentShape2DSW,RectangleShape2DSW,castA,castB,withMargin> separator(segment_A,p_transform_a,rectangle_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B);

	if (!separator.test_previous_axis())
		return;

	if (!separator.test_cast())
		return;

	if (!separator.test_axis(segment_A->get_xformed_normal(p_transform_a)))
		return;

	if (!separator.test_axis(p_transform_b.elements[0].normalized()))
		return;

	if (!separator.test_axis(p_transform_b.elements[1].normalized()))
		return;

	if (withMargin) {

		Matrix32 inv = p_transform_b.affine_inverse();

		Vector2 a = p_transform_a.xform(segment_A->get_a());
		Vector2 b = p_transform_a.xform(segment_A->get_b());

		if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,a)))
			return;
		if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,b)))
			return;

		if (castA) {

			if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,a+p_motion_a)))
				return;
			if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,b+p_motion_a)))
				return;
		}

		if (castB) {

			if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,a-p_motion_b)))
				return;
			if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,b-p_motion_b)))
				return;
		}

		if (castA && castB) {

			if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,a-p_motion_b+p_motion_a)))
				return;
			if (!separator.test_axis( rectangle_B->get_circle_axis(p_transform_b,inv,b-p_motion_b+p_motion_a)))
				return;
		}

	}

	separator.generate_contacts();

}
Ejemplo n.º 17
0
static void _collision_rectangle_capsule(const Shape2DSW* p_a,const Matrix32& p_transform_a,const Shape2DSW* p_b,const Matrix32& p_transform_b,_CollectorCallback2D *p_collector,const Vector2& p_motion_a,const Vector2& p_motion_b,float p_margin_A,float p_margin_B) {

	const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW*>(p_a);
	const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW*>(p_b);


	SeparatorAxisTest2D<RectangleShape2DSW,CapsuleShape2DSW,castA,castB,withMargin> separator(rectangle_A,p_transform_a,capsule_B,p_transform_b,p_collector,p_motion_a,p_motion_b,p_margin_A,p_margin_B);

	if (!separator.test_previous_axis())
		return;

	if (!separator.test_cast())
		return;

	//box faces
	if (!separator.test_axis(p_transform_a.elements[0].normalized()))
		return;

	if (!separator.test_axis(p_transform_a.elements[1].normalized()))
		return;

	//capsule axis
	if (!separator.test_axis(p_transform_b.elements[0].normalized()))
		return;


	//box endpoints to capsule circles

	Matrix32 boxinv = p_transform_a.affine_inverse();

	for(int i=0;i<2;i++) {

		{
			Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5);

			if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,capsule_endpoint)))
				return;
		}


		if (castA) {
			Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5);
			capsule_endpoint-=p_motion_a;

			if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,capsule_endpoint)))
				return;
		}

		if (castB) {
			Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5);
			capsule_endpoint+=p_motion_b;

			if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,capsule_endpoint)))
				return;
		}

		if (castA && castB) {
			Vector2 capsule_endpoint = p_transform_b.get_origin()+p_transform_b.elements[1]*capsule_B->get_height()*(i==0?0.5:-0.5);
			capsule_endpoint-=p_motion_a;
			capsule_endpoint+=p_motion_b;


			if (!separator.test_axis(rectangle_A->get_circle_axis(p_transform_a,boxinv,capsule_endpoint)))
				return;
		}

	}


	separator.generate_contacts();
}
Ejemplo n.º 18
0
void SpriteRegionEditor::_region_draw()
{
	Ref<Texture> base_tex = node->get_texture();
	if (base_tex.is_null())
		return;

	Matrix32 mtx;
	mtx.elements[2]=-draw_ofs;
	mtx.scale_basis(Vector2(draw_zoom,draw_zoom));

	VS::get_singleton()->canvas_item_set_clip(edit_draw->get_canvas_item(),true);
	VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(),mtx);
	edit_draw->draw_texture(base_tex,Point2());
	VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(),Matrix32());

	if (snap_show_grid) {
		Size2 s = edit_draw->get_size();
		int last_cell;

		if (snap_step.x!=0) {
			for(int i=0;i<s.width;i++) {
				int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i,0)).x-snap_offset.x)/snap_step.x));
				if (i==0)
					last_cell=cell;
				if (last_cell!=cell)
					edit_draw->draw_line(Point2(i,0),Point2(i,s.height),Color(0.3,0.7,1,0.3));
				last_cell=cell;
			}
		}

		if (snap_step.y!=0) {
			for(int i=0;i<s.height;i++) {
				int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0,i)).y-snap_offset.y)/snap_step.y));
				if (i==0)
					last_cell=cell;
				if (last_cell!=cell)
					edit_draw->draw_line(Point2(0,i),Point2(s.width,i),Color(0.3,0.7,1,0.3));
				last_cell=cell;
			}
		}
	}

	Ref<Texture> select_handle = get_icon("EditorHandle","EditorIcons");

	Rect2 scroll_rect(Point2(),mtx.basis_xform(base_tex->get_size()));
	scroll_rect.expand_to(mtx.basis_xform(edit_draw->get_size()));

	Vector2 endpoints[4]={
		mtx.basis_xform(rect.pos),
		mtx.basis_xform(rect.pos+Vector2(rect.size.x,0)),
		mtx.basis_xform(rect.pos+rect.size),
		mtx.basis_xform(rect.pos+Vector2(0,rect.size.y))
	};

	for(int i=0;i<4;i++) {

		int prev = (i+3)%4;
		int next = (i+1)%4;

		Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
		ofs*=1.4144*(select_handle->get_size().width/2);

		edit_draw->draw_line(endpoints[i]-draw_ofs, endpoints[next]-draw_ofs, Color(0.9,0.5,0.5), 2);

		edit_draw->draw_texture(select_handle,(endpoints[i]+ofs-(select_handle->get_size()/2)).floor()-draw_ofs);

		ofs = (endpoints[next]-endpoints[i])/2;
		ofs += (endpoints[next]-endpoints[i]).tangent().normalized()*(select_handle->get_size().width/2);

		edit_draw->draw_texture(select_handle,(endpoints[i]+ofs-(select_handle->get_size()/2)).floor()-draw_ofs);

		scroll_rect.expand_to(endpoints[i]);
	}

	scroll_rect=scroll_rect.grow(200);
	updating_scroll=true;
	hscroll->set_min(scroll_rect.pos.x);
	hscroll->set_max(scroll_rect.pos.x+scroll_rect.size.x);
	hscroll->set_page(edit_draw->get_size().x);
	hscroll->set_val(draw_ofs.x);
	hscroll->set_step(0.001);

	vscroll->set_min(scroll_rect.pos.y);
	vscroll->set_max(scroll_rect.pos.y+scroll_rect.size.y);
	vscroll->set_page(edit_draw->get_size().y);
	vscroll->set_val(draw_ofs.y);
	vscroll->set_step(0.001);
	updating_scroll=false;
}
void Polygon2DEditor::_uv_input(const InputEvent& p_input) {


	Matrix32 mtx;
	mtx.elements[2]=-uv_draw_ofs;
	mtx.scale_basis(Vector2(uv_draw_zoom,uv_draw_zoom));

	if (p_input.type==InputEvent::MOUSE_BUTTON) {


		const InputEventMouseButton &mb=p_input.mouse_button;

		if (mb.button_index==BUTTON_LEFT) {


			if (mb.pressed) {

				uv_drag_from=Vector2(mb.x,mb.y);
				uv_drag=true;
				uv_prev=node->get_uv();
				uv_move_current=uv_mode;
				if (uv_move_current==UV_MODE_EDIT_POINT) {

					if (mb.mod.shift && mb.mod.command)
						uv_move_current=UV_MODE_SCALE;
					else if (mb.mod.shift)
						uv_move_current=UV_MODE_MOVE;
					else if (mb.mod.command)
						uv_move_current=UV_MODE_ROTATE;
				}

				if (uv_move_current==UV_MODE_EDIT_POINT) {

					uv_drag_index=-1;
					for(int i=0;i<uv_prev.size();i++) {

						Vector2 tuv=mtx.xform(uv_prev[i]);
						if (tuv.distance_to(Vector2(mb.x,mb.y))<8) {
							uv_drag_from=tuv;
							uv_drag_index=i;
						}
					}

					if (uv_drag_index==-1) {
						uv_drag=false;
					}

				}
			} else if (uv_drag) {

				undo_redo->create_action("Transform UV Map");
				undo_redo->add_do_method(node,"set_uv",node->get_uv());
				undo_redo->add_undo_method(node,"set_uv",uv_prev);
				undo_redo->add_do_method(uv_edit_draw,"update");
				undo_redo->add_undo_method(uv_edit_draw,"update");
				undo_redo->commit_action();

				uv_drag=false;
			}

		} else if (mb.button_index==BUTTON_RIGHT && mb.pressed) {

			if (uv_drag) {

				uv_drag=false;
				node->set_uv(uv_prev);
				uv_edit_draw->update();
			}

		} else if (mb.button_index==BUTTON_WHEEL_UP && mb.pressed) {

			uv_zoom->set_val( uv_zoom->get_val()/0.9 );
		} else if (mb.button_index==BUTTON_WHEEL_DOWN && mb.pressed) {

			uv_zoom->set_val( uv_zoom->get_val()*0.9);
		}

	} else if (p_input.type==InputEvent::MOUSE_MOTION) {

		const InputEventMouseMotion &mm=p_input.mouse_motion;

		if (mm.button_mask&BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {

			Vector2 drag(mm.relative_x,mm.relative_y);
			uv_hscroll->set_val( uv_hscroll->get_val()-drag.x );
			uv_vscroll->set_val( uv_vscroll->get_val()-drag.y );

		} else if (uv_drag) {

			Vector2 uv_drag_to=snap_point(Vector2(mm.x,mm.y));
			Vector2 drag = mtx.affine_inverse().xform(uv_drag_to) - mtx.affine_inverse().xform(uv_drag_from);


			switch(uv_move_current) {

				case UV_MODE_EDIT_POINT: {

					DVector<Vector2> uv_new=uv_prev;
					uv_new.set( uv_drag_index, uv_new[uv_drag_index]+drag );
					node->set_uv(uv_new);
				} break;
				case UV_MODE_MOVE: {

					DVector<Vector2> uv_new=uv_prev;
					for(int i=0;i<uv_new.size();i++)
						uv_new.set( i, uv_new[i]+drag );

					node->set_uv(uv_new);


				} break;
				case UV_MODE_ROTATE: {

					Vector2 center;
					DVector<Vector2> uv_new=uv_prev;

					for(int i=0;i<uv_new.size();i++)
						center+=uv_prev[i];
					center/=uv_new.size();

					float angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to( (uv_drag_to - mtx.xform(center)).normalized() );

					for(int i=0;i<uv_new.size();i++) {
						Vector2 rel = uv_prev[i] - center;
						rel=rel.rotated(angle);
						uv_new.set(i,center+rel);
					}

					node->set_uv(uv_new);

				} break;
				case UV_MODE_SCALE: {

					Vector2 center;
					DVector<Vector2> uv_new=uv_prev;

					for(int i=0;i<uv_new.size();i++)
						center+=uv_prev[i];
					center/=uv_new.size();

					float from_dist = uv_drag_from.distance_to(mtx.xform(center));
					float to_dist = uv_drag_to.distance_to(mtx.xform(center));
					if (from_dist<2)
						break;

					float scale = to_dist/from_dist;


					for(int i=0;i<uv_new.size();i++) {
						Vector2 rel = uv_prev[i] - center;
						rel=rel*scale;
						uv_new.set(i,center+rel);
					}

					node->set_uv(uv_new);
				} break;


			}
			uv_edit_draw->update();
		}

	}

}
Ejemplo n.º 20
0
bool TileMapEditor::forward_input_event(const InputEvent& p_event) {

	if (!node || !node->get_tileset().is_valid() || !node->is_visible())
		return false;

	Matrix32 xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
	Matrix32 xform_inv = xform.affine_inverse();

	switch(p_event.type) {

		case InputEvent::MOUSE_BUTTON: {

			const InputEventMouseButton &mb=p_event.mouse_button;

			if (mb.button_index==BUTTON_LEFT) {

				if (mb.pressed) {

					if (Input::get_singleton()->is_key_pressed(KEY_SPACE))
						return false; //drag

					if (tool==TOOL_NONE) {

						if (mb.mod.shift) {

							if (mb.mod.control)
								tool=TOOL_RECTANGLE_PAINT;
							else
								tool=TOOL_LINE_PAINT;

							selection_active=false;
							rectangle_begin=over_tile;

							return true;
						}

						if (mb.mod.control) {

							tool=TOOL_PICKING;
							_pick_tile(over_tile);

							return true;
						}

						tool=TOOL_PAINTING;
					}

					if (tool==TOOL_PAINTING) {

						int id = get_selected_tile();

						if (id!=TileMap::INVALID_CELL) {

							tool=TOOL_PAINTING;

							paint_undo.clear();
							paint_undo[over_tile]=_get_op_from_cell(over_tile);

							_set_cell(over_tile, id, flip_h, flip_v, transpose);
						}
					} else if (tool==TOOL_PICKING) {

						_pick_tile(over_tile);
					} else if (tool==TOOL_SELECTING) {

						selection_active=true;
						rectangle_begin=over_tile;
					}

					return true;

				} else {

					if (tool!=TOOL_NONE) {

						if (tool==TOOL_PAINTING) {

							int id=get_selected_tile();

							if (id!=TileMap::INVALID_CELL && paint_undo.size()) {

								undo_redo->create_action(TTR("Paint TileMap"));
								for (Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {

									Point2 p=E->key();
									undo_redo->add_do_method(node,"set_cellv",p,id,flip_h,flip_v,transpose);
									undo_redo->add_undo_method(node,"set_cellv",p,E->get().idx,E->get().xf,E->get().yf,E->get().tr);
								}
								undo_redo->commit_action();

								paint_undo.clear();
							}
						} else if (tool==TOOL_LINE_PAINT) {

							int id=get_selected_tile();

							if (id!=TileMap::INVALID_CELL) {

								undo_redo->create_action("Line Draw");
								for (Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {

									_set_cell(E->key(), id, flip_h, flip_v, transpose, true);
								}
								undo_redo->commit_action();

								paint_undo.clear();

								canvas_item_editor->update();
							}
						} else if (tool==TOOL_RECTANGLE_PAINT) {

							int id=get_selected_tile();

							if (id!=TileMap::INVALID_CELL) {

								undo_redo->create_action("Rectangle Paint");
								for (int i=rectangle.pos.y;i<=rectangle.pos.y+rectangle.size.y;i++) {
									for (int j=rectangle.pos.x;j<=rectangle.pos.x+rectangle.size.x;j++) {

										_set_cell(Point2i(j, i), id, flip_h, flip_v, transpose, true);
									}
								}
								undo_redo->commit_action();

								canvas_item_editor->update();
							}
						} else if (tool==TOOL_DUPLICATING) {

							Point2 ofs = over_tile-rectangle.pos;

							undo_redo->create_action(TTR("Duplicate"));
							for (List<TileData>::Element *E=copydata.front();E;E=E->next()) {

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

							copydata.clear();

							canvas_item_editor->update();

						} else if (tool==TOOL_SELECTING) {

							canvas_item_editor->update();

						} else if (tool==TOOL_BUCKET) {

							DVector<Vector2> points = _bucket_fill(over_tile);

							if (points.size() == 0)
								return false;

							Dictionary op;
							op["id"] = get_selected_tile();
							op["flip_h"] = flip_h;
							op["flip_v"] = flip_v;
							op["transpose"] = transpose;

							undo_redo->create_action("Bucket Fill");

							undo_redo->add_do_method(this, "_fill_points", points, op);
							undo_redo->add_undo_method(this, "_erase_points", points);

							undo_redo->commit_action();
						}

						tool=TOOL_NONE;

						return true;
					}
				}
			} else if (mb.button_index==BUTTON_RIGHT) {

				if (mb.pressed) {

					if (tool==TOOL_SELECTING || selection_active) {

						tool=TOOL_NONE;
						selection_active=false;

						canvas_item_editor->update();

						return true;
					}

					if (tool==TOOL_DUPLICATING) {

						tool=TOOL_NONE;
						copydata.clear();

						canvas_item_editor->update();

						return true;
					}

					if (tool==TOOL_NONE) {

						paint_undo.clear();

						Point2 local = node->world_to_map(xform_inv.xform(Point2(mb.x, mb.y)));

						if (mb.mod.shift) {

							if (mb.mod.control)
								tool=TOOL_RECTANGLE_ERASE;
							else
								tool=TOOL_LINE_ERASE;

							selection_active=false;
							rectangle_begin=local;
						} else {

							tool=TOOL_ERASING;

							paint_undo[local]=_get_op_from_cell(local);
							_set_cell(local, TileMap::INVALID_CELL);
						}

						return true;
					}

				} else {
					if (tool==TOOL_ERASING || tool==TOOL_RECTANGLE_ERASE || tool==TOOL_LINE_ERASE) {

						if (paint_undo.size()) {
							undo_redo->create_action(TTR("Erase TileMap"));
							for (Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {

								Point2 p=E->key();
								undo_redo->add_do_method(node,"set_cellv",p,TileMap::INVALID_CELL,false,false,false);
								undo_redo->add_undo_method(node,"set_cellv",p,E->get().idx,E->get().xf,E->get().yf,E->get().tr);
							}

							undo_redo->commit_action();
							paint_undo.clear();
						}

						if (tool==TOOL_RECTANGLE_ERASE || tool==TOOL_LINE_ERASE) {
							canvas_item_editor->update();
						}

						tool=TOOL_NONE;

						return true;
					}
				}
			}
		} break;
		case InputEvent::MOUSE_MOTION: {

			const InputEventMouseMotion &mm=p_event.mouse_motion;

			Point2i new_over_tile = node->world_to_map(xform_inv.xform(Point2(mm.x,mm.y)));

			if (new_over_tile!=over_tile) {

				over_tile=new_over_tile;
				canvas_item_editor->update();
			}

			if (tool==TOOL_PAINTING) {

				int id = get_selected_tile();
				if (id!=TileMap::INVALID_CELL) {

					if (!paint_undo.has(over_tile)) {
						paint_undo[over_tile]=_get_op_from_cell(over_tile);
					}

					_set_cell(over_tile, id, flip_h, flip_v, transpose);

					return true;
				}
			}

			if (tool==TOOL_SELECTING) {

				_select(rectangle_begin, over_tile);

				return true;
			}

			if (tool==TOOL_LINE_PAINT || tool==TOOL_LINE_ERASE) {

				int id = get_selected_tile();
				bool erasing = (tool==TOOL_LINE_ERASE);

				if (erasing && paint_undo.size()) {

					for (Map<Point2i, CellOp>::Element *E=paint_undo.front();E;E=E->next()) {

						_set_cell(E->key(), E->get().idx, E->get().xf, E->get().yf, E->get().tr);
					}
				}

				paint_undo.clear();

				if (id!=TileMap::INVALID_CELL) {

					Vector<Point2i> points = line(rectangle_begin.x, over_tile.x, rectangle_begin.y, over_tile.y);

					for (int i=0;i<points.size();i++) {

						paint_undo[points[i]]=_get_op_from_cell(points[i]);

						if (erasing)
							_set_cell(points[i], TileMap::INVALID_CELL);
					}

					canvas_item_editor->update();
				}

				return true;
			}
			if (tool==TOOL_RECTANGLE_PAINT || tool==TOOL_RECTANGLE_ERASE) {

				_select(rectangle_begin, over_tile);

				if (tool==TOOL_RECTANGLE_ERASE) {

					if (paint_undo.size()) {

						for (Map<Point2i, CellOp>::Element *E=paint_undo.front();E;E=E->next()) {

							_set_cell(E->key(), E->get().idx, E->get().xf, E->get().yf, E->get().tr);
						}
					}

					paint_undo.clear();

					for (int i=rectangle.pos.y;i<=rectangle.pos.y+rectangle.size.y;i++) {
						for (int j=rectangle.pos.x;j<=rectangle.pos.x+rectangle.size.x;j++) {

							Point2i tile = Point2i(j, i);
							paint_undo[tile]=_get_op_from_cell(tile);

							_set_cell(tile, TileMap::INVALID_CELL);
						}
					}
				}

				return true;
			}
			if (tool==TOOL_ERASING) {

				if (!paint_undo.has(over_tile)) {
					paint_undo[over_tile]=_get_op_from_cell(over_tile);
				}

				_set_cell(over_tile, TileMap::INVALID_CELL);

				return true;
			}
			if (tool==TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {

				_pick_tile(over_tile);

				return true;
			}
		} break;
		case InputEvent::KEY: {

			const InputEventKey &k = p_event.key;

			if (!k.pressed)
				break;

			if (k.scancode==KEY_ESCAPE) {

				if (tool==TOOL_DUPLICATING)
					copydata.clear();
				else if (tool==TOOL_SELECTING || selection_active)
					selection_active=false;

				tool=TOOL_NONE;

				canvas_item_editor->update();

				return true;
			}

			if (tool!=TOOL_NONE || !mouse_over)
				return false;

			if (k.scancode==KEY_DELETE) {

				_menu_option(OPTION_ERASE_SELECTION);

				return true;
			}

			if (k.mod.command) {

				if (k.scancode==KEY_F) {

					search_box->select_all();
					search_box->grab_focus();

					return true;
				}
				if (k.scancode==KEY_B) {

					tool=TOOL_SELECTING;
					selection_active=false;

					canvas_item_editor->update();

					return true;
				}
				if (k.scancode==KEY_D) {

					_update_copydata();

					if (selection_active) {
						tool=TOOL_DUPLICATING;

						canvas_item_editor->update();

						return true;
					}
				}
			} else {

				if (k.scancode==KEY_A) {

					flip_h=!flip_h;
					mirror_x->set_pressed(flip_h);
					canvas_item_editor->update();
					return true;
				}
				if (k.scancode==KEY_S) {

					flip_v=!flip_v;
					mirror_y->set_pressed(flip_v);
					canvas_item_editor->update();
					return true;
				}
			}
		} break;
	}

	return false;
}
void Polygon2DEditor::_uv_draw() {

	Ref<Texture> base_tex = node->get_texture();
	if (base_tex.is_null())
		return;

	Matrix32 mtx;
	mtx.elements[2]=-uv_draw_ofs;
	mtx.scale_basis(Vector2(uv_draw_zoom,uv_draw_zoom));

	VS::get_singleton()->canvas_item_set_clip(uv_edit_draw->get_canvas_item(),true);
	VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(),mtx);
	uv_edit_draw->draw_texture(base_tex,Point2());
	VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(),Matrix32());

	if (snap_show_grid) {
		Size2 s = uv_edit_draw->get_size();
		int last_cell;

		if (snap_step.x!=0) {
			for(int i=0;i<s.width;i++) {
				int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i,0)).x-snap_offset.x)/snap_step.x));
				if (i==0)
					last_cell=cell;
				if (last_cell!=cell)
					uv_edit_draw->draw_line(Point2(i,0),Point2(i,s.height),Color(0.3,0.7,1,0.3));
				last_cell=cell;
			}
		}

		if (snap_step.y!=0) {
			for(int i=0;i<s.height;i++) {
				int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0,i)).y-snap_offset.y)/snap_step.y));
				if (i==0)
					last_cell=cell;
				if (last_cell!=cell)
					uv_edit_draw->draw_line(Point2(0,i),Point2(s.width,i),Color(0.3,0.7,1,0.3));
				last_cell=cell;
			}
		}
	}

	DVector<Vector2> uvs = node->get_uv();
	Ref<Texture> handle = get_icon("EditorHandle","EditorIcons");

	Rect2 rect(Point2(),mtx.basis_xform(base_tex->get_size()));
	rect.expand_to(mtx.basis_xform(uv_edit_draw->get_size()));

	for(int i=0;i<uvs.size();i++) {

		int next = (i+1)%uvs.size();
		uv_edit_draw->draw_line(mtx.xform(uvs[i]),mtx.xform(uvs[next]),Color(0.9,0.5,0.5),2);
		uv_edit_draw->draw_texture(handle,mtx.xform(uvs[i])-handle->get_size()*0.5);
		rect.expand_to(mtx.basis_xform(uvs[i]));
	}

	rect=rect.grow(200);
	updating_uv_scroll=true;
	uv_hscroll->set_min(rect.pos.x);
	uv_hscroll->set_max(rect.pos.x+rect.size.x);
	uv_hscroll->set_page(uv_edit_draw->get_size().x);
	uv_hscroll->set_val(uv_draw_ofs.x);
	uv_hscroll->set_step(0.001);

	uv_vscroll->set_min(rect.pos.y);
	uv_vscroll->set_max(rect.pos.y+rect.size.y);
	uv_vscroll->set_page(uv_edit_draw->get_size().y);
	uv_vscroll->set_val(uv_draw_ofs.y);
	uv_vscroll->set_step(0.001);
	updating_uv_scroll=false;

}
bool LightOccluder2DEditor::forward_input_event(const InputEvent& p_event) {


	if (!node)
		return false;

	if (node->get_occluder_polygon().is_null()) {
		if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
			create_poly->set_text("No OccluderPolygon2D resource on this node.\nCreate and assign one?");
			create_poly->popup_centered_minsize();
		}
		return false;
	}
	switch(p_event.type) {

		case InputEvent::MOUSE_BUTTON: {

			const InputEventMouseButton &mb=p_event.mouse_button;

			Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();


			Vector2 gpoint = Point2(mb.x,mb.y);
			Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
			cpoint=snap_point(cpoint);
			cpoint = node->get_global_transform().affine_inverse().xform(cpoint);

			Vector<Vector2> poly = Variant(node->get_occluder_polygon()->get_polygon());

			//first check if a point is to be added (segment split)
			real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);

			switch(mode) {


				case MODE_CREATE: {

					if (mb.button_index==BUTTON_LEFT && mb.pressed) {


						if (!wip_active) {

							wip.clear();
							wip.push_back( cpoint );
							wip_active=true;
							edited_point_pos=cpoint;
							canvas_item_editor->get_viewport_control()->update();
							edited_point=1;
							return true;
						} else {


							if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
								//wip closed
								_wip_close(true);

								return true;
							} else if (wip.size()>1 && xform.xform(wip[wip.size()-1]).distance_to(gpoint)<grab_treshold) {
									//wip closed
									_wip_close(false);
									return true;

							} else {

								wip.push_back( cpoint );
								edited_point=wip.size();
								canvas_item_editor->get_viewport_control()->update();
								return true;

								//add wip point
							}
						}
					} else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) {
						_wip_close(true);
					}



				} break;

				case MODE_EDIT: {

					if (mb.button_index==BUTTON_LEFT) {
						if (mb.pressed) {

							if (mb.mod.control) {


								if (poly.size() < 3) {

									undo_redo->create_action("Edit Poly");
									undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
									poly.push_back(cpoint);
									undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
									undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
									undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
									undo_redo->commit_action();
									return true;
								}

								//search edges
								int closest_idx=-1;
								Vector2 closest_pos;
								real_t closest_dist=1e10;
								for(int i=0;i<poly.size();i++) {

									Vector2 points[2] ={ xform.xform(poly[i]),
										xform.xform(poly[(i+1)%poly.size()]) };

									Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
									if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2)
										continue; //not valid to reuse point

									real_t d = cp.distance_to(gpoint);
									if (d<closest_dist && d<grab_treshold) {
										closest_dist=d;
										closest_pos=cp;
										closest_idx=i;
									}


								}

								if (closest_idx>=0) {

									pre_move_edit=poly;
									poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos));
									edited_point=closest_idx+1;
									edited_point_pos=xform.affine_inverse().xform(closest_pos);
									node->get_occluder_polygon()->set_polygon(Variant(poly));
									canvas_item_editor->get_viewport_control()->update();
									return true;
								}
							} else {

								//look for points to move

								int closest_idx=-1;
								Vector2 closest_pos;
								real_t closest_dist=1e10;
								for(int i=0;i<poly.size();i++) {

									Vector2 cp =xform.xform(poly[i]);

									real_t d = cp.distance_to(gpoint);
									if (d<closest_dist && d<grab_treshold) {
										closest_dist=d;
										closest_pos=cp;
										closest_idx=i;
									}

								}

								if (closest_idx>=0) {

									pre_move_edit=poly;
									edited_point=closest_idx;
									edited_point_pos=xform.affine_inverse().xform(closest_pos);
									canvas_item_editor->get_viewport_control()->update();
									return true;
								}
							}
						} else {

							if (edited_point!=-1) {

								//apply

								ERR_FAIL_INDEX_V(edited_point,poly.size(),false);
								poly[edited_point]=edited_point_pos;
								undo_redo->create_action("Edit Poly");
								undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
								undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",pre_move_edit);
								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
								undo_redo->commit_action();

								edited_point=-1;
								return true;
							}
						}
					} if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) {



						int closest_idx=-1;
						Vector2 closest_pos;
						real_t closest_dist=1e10;
						for(int i=0;i<poly.size();i++) {

							Vector2 cp =xform.xform(poly[i]);

							real_t d = cp.distance_to(gpoint);
							if (d<closest_dist && d<grab_treshold) {
								closest_dist=d;
								closest_pos=cp;
								closest_idx=i;
							}

						}

						if (closest_idx>=0) {


							undo_redo->create_action("Edit Poly (Remove Point)");
							undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
							poly.remove(closest_idx);
							undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly);
							undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
							undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
							undo_redo->commit_action();
							return true;
						}

					}



				} break;
			}



		} break;
		case InputEvent::MOUSE_MOTION: {

			const InputEventMouseMotion &mm=p_event.mouse_motion;

			if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {

				Vector2 gpoint = Point2(mm.x,mm.y);
				Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
				cpoint=snap_point(cpoint);
				edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);

				canvas_item_editor->get_viewport_control()->update();

			}

		} break;
	}

	return false;
}
Ejemplo n.º 23
0
void TileMapEditor::_canvas_draw() {

	if (!node)
		return;

	int cell_size=node->get_cell_size();

	Matrix32 xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
	Matrix32 xform_inv = xform.affine_inverse();


	Size2 screen_size=canvas_item_editor->get_size();
	Rect2 aabb;
	aabb.pos=xform_inv.xform(Vector2());
	aabb.expand_to(xform_inv.xform(Vector2(0,screen_size.height)));
	aabb.expand_to(xform_inv.xform(Vector2(screen_size.width,0)));
	aabb.expand_to(xform_inv.xform(screen_size));
	Rect2i si=aabb;

	for(int i=(si.pos.x/cell_size)-1;i<=(si.pos.x+si.size.x)/cell_size;i++) {

		int ofs = i*cell_size;

		Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
		canvas_item_editor->draw_line(xform.xform(Point2(ofs,si.pos.y)),xform.xform(Point2(ofs,si.pos.y+si.size.y)),col,1);

	}

	for(int i=(si.pos.y/cell_size)-1;i<=(si.pos.y+si.size.y)/cell_size;i++) {

		int ofs = i*cell_size;
		Color col=i==0?Color(1,0.8,0.2,0.5):Color(1,0.3,0.1,0.2);
		canvas_item_editor->draw_line(xform.xform(Point2(si.pos.x,ofs)),xform.xform(Point2(si.pos.x+si.size.x,ofs)),col,1);
	}


	if (selection_active) {

		Vector<Vector2> points;
		points.push_back( xform.xform( selection.pos * cell_size) );
		points.push_back( xform.xform( (selection.pos+Point2(selection.size.x+1,0)) * cell_size) );
		points.push_back( xform.xform( (selection.pos+Point2(selection.size.x+1,selection.size.y+1)) * cell_size) );
		points.push_back( xform.xform( (selection.pos+Point2(0,selection.size.y+1)) * cell_size) );
		Color col=Color(0.2,0.8,1,0.4);

		canvas_item_editor->draw_colored_polygon(points,col);
	}


	if (mouse_over){

		const Vector2 endpoints[4]={

			xform.xform( over_tile * cell_size) ,
			xform.xform( (over_tile+Point2(1,0)) * cell_size) ,
			xform.xform( (over_tile+Point2(1,1)) * cell_size) ,
			xform.xform( (over_tile+Point2(0,1)) * cell_size) ,


		};
		Color col;
		if (node->get_cell(over_tile.x,over_tile.y)!=TileMap::INVALID_CELL)
			col=Color(0.2,0.8,1.0,0.8);
		else
			col=Color(1.0,0.4,0.2,0.8);

		for(int i=0;i<4;i++)
			canvas_item_editor->draw_line(endpoints[i],endpoints[(i+1)%4],col,2);



		if (tool==TOOL_DUPLICATING) {

			Rect2i duplicate=selection;
			duplicate.pos=over_tile;


			Vector<Vector2> points;
			points.push_back( xform.xform( duplicate.pos * cell_size) );
			points.push_back( xform.xform( (duplicate.pos+Point2(duplicate.size.x+1,0)) * cell_size) );
			points.push_back( xform.xform( (duplicate.pos+Point2(duplicate.size.x+1,duplicate.size.y+1)) * cell_size) );
			points.push_back( xform.xform( (duplicate.pos+Point2(0,duplicate.size.y+1)) * cell_size) );
			Color col=Color(0.2,1.0,0.8,0.4);

			canvas_item_editor->draw_colored_polygon(points,col);

		} else {

			Ref<TileSet> ts = node->get_tileset();


			if (ts.is_valid()) {

				int st = get_selected_tile();
				if (ts->has_tile(st)) {

					Ref<Texture> t = ts->tile_get_texture(st);
					if (t.is_valid()) {
						Rect2 r = ts->tile_get_region(st);
						Size2 sc = (endpoints[2]-endpoints[0])/cell_size;
						if (mirror_x->is_pressed())
							sc.x*=-1.0;
						if (mirror_y->is_pressed())
							sc.y*=-1.0;
						if (r==Rect2()) {

							canvas_item_editor->draw_texture_rect(t,Rect2(endpoints[0],t->get_size()*sc),false,Color(1,1,1,0.5));
						} else {

							canvas_item_editor->draw_texture_rect_region(t,Rect2(endpoints[0],r.get_size()*sc),r,Color(1,1,1,0.5));
						}
					}
				}
			}

		}
	}



}