1 /*************************************************************************/
2 /*  polygon_2d_editor_plugin.cpp                                         */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "polygon_2d_editor_plugin.h"
32 #include "canvas_item_editor_plugin.h"
33 #include "editor/editor_settings.h"
34 #include "os/file_access.h"
35 #include "os/input.h"
36 #include "os/keyboard.h"
37 
_notification(int p_what)38 void Polygon2DEditor::_notification(int p_what) {
39 
40 	switch (p_what) {
41 
42 		case NOTIFICATION_READY: {
43 
44 			button_create->set_icon(get_icon("Edit", "EditorIcons"));
45 			button_edit->set_icon(get_icon("MovePoint", "EditorIcons"));
46 			button_edit->set_pressed(true);
47 			button_uv->set_icon(get_icon("Uv", "EditorIcons"));
48 
49 			uv_button[UV_MODE_EDIT_POINT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
50 			uv_button[UV_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons"));
51 			uv_button[UV_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));
52 			uv_button[UV_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
53 
54 			b_snap_grid->set_icon(get_icon("Grid", "EditorIcons"));
55 			b_snap_enable->set_icon(get_icon("Snap", "EditorIcons"));
56 			uv_icon_zoom->set_texture(get_icon("Zoom", "EditorIcons"));
57 
58 			get_tree()->connect("node_removed", this, "_node_removed");
59 
60 		} break;
61 		case NOTIFICATION_FIXED_PROCESS: {
62 
63 		} break;
64 	}
65 }
_node_removed(Node * p_node)66 void Polygon2DEditor::_node_removed(Node *p_node) {
67 
68 	if (p_node == node) {
69 		edit(NULL);
70 		hide();
71 
72 		canvas_item_editor->get_viewport_control()->update();
73 	}
74 }
75 
_menu_option(int p_option)76 void Polygon2DEditor::_menu_option(int p_option) {
77 
78 	switch (p_option) {
79 
80 		case MODE_CREATE: {
81 
82 			mode = MODE_CREATE;
83 			button_create->set_pressed(true);
84 			button_edit->set_pressed(false);
85 		} break;
86 		case MODE_EDIT: {
87 
88 			mode = MODE_EDIT;
89 			button_create->set_pressed(false);
90 			button_edit->set_pressed(true);
91 		} break;
92 		case MODE_EDIT_UV: {
93 
94 			if (node->get_texture().is_null()) {
95 
96 				error->set_text("No texture in this polygon.\nSet a texture to be able to edit UV.");
97 				error->popup_centered_minsize();
98 				return;
99 			}
100 
101 			DVector<Vector2> points = node->get_polygon();
102 			DVector<Vector2> uvs = node->get_uv();
103 			if (uvs.size() != points.size()) {
104 				undo_redo->create_action(TTR("Create UV Map"));
105 				undo_redo->add_do_method(node, "set_uv", points);
106 				undo_redo->add_undo_method(node, "set_uv", uvs);
107 				undo_redo->add_do_method(uv_edit_draw, "update");
108 				undo_redo->add_undo_method(uv_edit_draw, "update");
109 				undo_redo->commit_action();
110 			}
111 
112 			uv_edit->popup_centered_ratio(0.85);
113 		} break;
114 		case UVEDIT_POLYGON_TO_UV: {
115 
116 			DVector<Vector2> points = node->get_polygon();
117 			if (points.size() == 0)
118 				break;
119 			DVector<Vector2> uvs = node->get_uv();
120 			undo_redo->create_action(TTR("Create UV Map"));
121 			undo_redo->add_do_method(node, "set_uv", points);
122 			undo_redo->add_undo_method(node, "set_uv", uvs);
123 			undo_redo->add_do_method(uv_edit_draw, "update");
124 			undo_redo->add_undo_method(uv_edit_draw, "update");
125 			undo_redo->commit_action();
126 
127 		} break;
128 		case UVEDIT_UV_TO_POLYGON: {
129 
130 			DVector<Vector2> points = node->get_polygon();
131 			DVector<Vector2> uvs = node->get_uv();
132 			if (uvs.size() == 0)
133 				break;
134 
135 			undo_redo->create_action(TTR("Create UV Map"));
136 			undo_redo->add_do_method(node, "set_polygon", uvs);
137 			undo_redo->add_undo_method(node, "set_polygon", points);
138 			undo_redo->add_do_method(uv_edit_draw, "update");
139 			undo_redo->add_undo_method(uv_edit_draw, "update");
140 			undo_redo->commit_action();
141 
142 		} break;
143 		case UVEDIT_UV_CLEAR: {
144 
145 			DVector<Vector2> uvs = node->get_uv();
146 			if (uvs.size() == 0)
147 				break;
148 			undo_redo->create_action(TTR("Create UV Map"));
149 			undo_redo->add_do_method(node, "set_uv", DVector<Vector2>());
150 			undo_redo->add_undo_method(node, "set_uv", uvs);
151 			undo_redo->add_do_method(uv_edit_draw, "update");
152 			undo_redo->add_undo_method(uv_edit_draw, "update");
153 			undo_redo->commit_action();
154 
155 		} break;
156 	}
157 }
158 
_set_use_snap(bool p_use)159 void Polygon2DEditor::_set_use_snap(bool p_use) {
160 	use_snap = p_use;
161 }
162 
_set_show_grid(bool p_show)163 void Polygon2DEditor::_set_show_grid(bool p_show) {
164 	snap_show_grid = p_show;
165 	uv_edit_draw->update();
166 }
167 
_set_snap_off_x(float p_val)168 void Polygon2DEditor::_set_snap_off_x(float p_val) {
169 	snap_offset.x = p_val;
170 	uv_edit_draw->update();
171 }
172 
_set_snap_off_y(float p_val)173 void Polygon2DEditor::_set_snap_off_y(float p_val) {
174 	snap_offset.y = p_val;
175 	uv_edit_draw->update();
176 }
177 
_set_snap_step_x(float p_val)178 void Polygon2DEditor::_set_snap_step_x(float p_val) {
179 	snap_step.x = p_val;
180 	uv_edit_draw->update();
181 }
182 
_set_snap_step_y(float p_val)183 void Polygon2DEditor::_set_snap_step_y(float p_val) {
184 	snap_step.y = p_val;
185 	uv_edit_draw->update();
186 }
187 
_wip_close()188 void Polygon2DEditor::_wip_close() {
189 
190 	undo_redo->create_action(TTR("Create Poly"));
191 	undo_redo->add_undo_method(node, "set_polygon", node->get_polygon());
192 	undo_redo->add_do_method(node, "set_polygon", wip);
193 	undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
194 	undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
195 	undo_redo->commit_action();
196 	wip.clear();
197 	wip_active = false;
198 	mode = MODE_EDIT;
199 	button_edit->set_pressed(true);
200 	button_create->set_pressed(false);
201 	edited_point = -1;
202 }
203 
forward_input_event(const InputEvent & p_event)204 bool Polygon2DEditor::forward_input_event(const InputEvent &p_event) {
205 
206 	if (node == NULL)
207 		return false;
208 
209 	switch (p_event.type) {
210 
211 		case InputEvent::MOUSE_BUTTON: {
212 
213 			const InputEventMouseButton &mb = p_event.mouse_button;
214 
215 			Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
216 
217 			Vector2 gpoint = Point2(mb.x, mb.y);
218 			Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
219 			cpoint = canvas_item_editor->snap_point(cpoint);
220 			cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
221 
222 			Vector<Vector2> poly = Variant(node->get_polygon());
223 
224 			//first check if a point is to be added (segment split)
225 			real_t grab_treshold = EDITOR_DEF("poly_editor/point_grab_radius", 8);
226 
227 			switch (mode) {
228 
229 				case MODE_CREATE: {
230 
231 					if (mb.button_index == BUTTON_LEFT && mb.pressed) {
232 
233 						if (!wip_active) {
234 
235 							wip.clear();
236 							wip.push_back(cpoint - node->get_offset());
237 							wip_active = true;
238 							edited_point_pos = cpoint;
239 							canvas_item_editor->get_viewport_control()->update();
240 							edited_point = 1;
241 							return true;
242 						} else {
243 
244 							if (wip.size() > 1 && xform.xform(wip[0] + node->get_offset()).distance_to(gpoint) < grab_treshold) {
245 								//wip closed
246 								_wip_close();
247 
248 								return true;
249 							} else {
250 
251 								wip.push_back(cpoint - node->get_offset());
252 								edited_point = wip.size();
253 								canvas_item_editor->get_viewport_control()->update();
254 								return true;
255 
256 								//add wip point
257 							}
258 						}
259 					} else if (mb.button_index == BUTTON_RIGHT && mb.pressed && wip_active) {
260 						_wip_close();
261 					}
262 
263 				} break;
264 
265 				case MODE_EDIT: {
266 
267 					if (mb.button_index == BUTTON_LEFT) {
268 						if (mb.pressed) {
269 
270 							if (mb.mod.control) {
271 
272 								if (poly.size() < 3) {
273 
274 									undo_redo->create_action(TTR("Edit Poly"));
275 									undo_redo->add_undo_method(node, "set_polygon", poly);
276 									poly.push_back(cpoint);
277 									undo_redo->add_do_method(node, "set_polygon", poly);
278 									undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
279 									undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
280 									undo_redo->commit_action();
281 									return true;
282 								}
283 
284 								//search edges
285 								int closest_idx = -1;
286 								Vector2 closest_pos;
287 								real_t closest_dist = 1e10;
288 								for (int i = 0; i < poly.size(); i++) {
289 
290 									Vector2 points[2] = { xform.xform(poly[i] + node->get_offset()),
291 										xform.xform(poly[(i + 1) % poly.size()] + node->get_offset()) };
292 
293 									Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint, points);
294 									if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2)
295 										continue; //not valid to reuse point
296 
297 									real_t d = cp.distance_to(gpoint);
298 									if (d < closest_dist && d < grab_treshold) {
299 										closest_dist = d;
300 										closest_pos = cp;
301 										closest_idx = i;
302 									}
303 								}
304 
305 								if (closest_idx >= 0) {
306 
307 									pre_move_edit = poly;
308 									poly.insert(closest_idx + 1, xform.affine_inverse().xform(closest_pos) - node->get_offset());
309 									edited_point = closest_idx + 1;
310 									edited_point_pos = xform.affine_inverse().xform(closest_pos);
311 									node->set_polygon(Variant(poly));
312 									canvas_item_editor->get_viewport_control()->update();
313 									return true;
314 								}
315 							} else {
316 
317 								//look for points to move
318 
319 								int closest_idx = -1;
320 								Vector2 closest_pos;
321 								real_t closest_dist = 1e10;
322 								for (int i = 0; i < poly.size(); i++) {
323 
324 									Vector2 cp = xform.xform(poly[i] + node->get_offset());
325 
326 									real_t d = cp.distance_to(gpoint);
327 									if (d < closest_dist && d < grab_treshold) {
328 										closest_dist = d;
329 										closest_pos = cp;
330 										closest_idx = i;
331 									}
332 								}
333 
334 								if (closest_idx >= 0) {
335 
336 									pre_move_edit = poly;
337 									edited_point = closest_idx;
338 									edited_point_pos = xform.affine_inverse().xform(closest_pos);
339 									canvas_item_editor->get_viewport_control()->update();
340 									return true;
341 								}
342 							}
343 						} else {
344 
345 							if (edited_point != -1) {
346 
347 								//apply
348 
349 								ERR_FAIL_INDEX_V(edited_point, poly.size(), false);
350 								poly[edited_point] = edited_point_pos - node->get_offset();
351 								undo_redo->create_action(TTR("Edit Poly"));
352 								undo_redo->add_do_method(node, "set_polygon", poly);
353 								undo_redo->add_undo_method(node, "set_polygon", pre_move_edit);
354 								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
355 								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
356 								undo_redo->commit_action();
357 
358 								edited_point = -1;
359 								return true;
360 							}
361 						}
362 					}
363 					if (mb.button_index == BUTTON_RIGHT && mb.pressed && edited_point == -1) {
364 
365 						int closest_idx = -1;
366 						Vector2 closest_pos;
367 						real_t closest_dist = 1e10;
368 						for (int i = 0; i < poly.size(); i++) {
369 
370 							Vector2 cp = xform.xform(poly[i] + node->get_offset());
371 
372 							real_t d = cp.distance_to(gpoint);
373 							if (d < closest_dist && d < grab_treshold) {
374 								closest_dist = d;
375 								closest_pos = cp;
376 								closest_idx = i;
377 							}
378 						}
379 
380 						if (closest_idx >= 0) {
381 
382 							undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
383 							undo_redo->add_undo_method(node, "set_polygon", poly);
384 							poly.remove(closest_idx);
385 							undo_redo->add_do_method(node, "set_polygon", poly);
386 							undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
387 							undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
388 							undo_redo->commit_action();
389 							return true;
390 						}
391 					}
392 
393 				} break;
394 			}
395 
396 		} break;
397 		case InputEvent::MOUSE_MOTION: {
398 
399 			const InputEventMouseMotion &mm = p_event.mouse_motion;
400 
401 			if (edited_point != -1 && (wip_active || mm.button_mask & BUTTON_MASK_LEFT)) {
402 
403 				Vector2 gpoint = Point2(mm.x, mm.y);
404 				Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
405 				cpoint = canvas_item_editor->snap_point(cpoint);
406 				edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
407 
408 				canvas_item_editor->get_viewport_control()->update();
409 			}
410 
411 		} break;
412 	}
413 
414 	return false;
415 }
_canvas_draw()416 void Polygon2DEditor::_canvas_draw() {
417 
418 	if (!node)
419 		return;
420 
421 	Control *vpc = canvas_item_editor->get_viewport_control();
422 
423 	Vector<Vector2> poly;
424 
425 	if (wip_active)
426 		poly = wip;
427 	else
428 		poly = Variant(node->get_polygon());
429 
430 	Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
431 	Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
432 
433 	for (int i = 0; i < poly.size(); i++) {
434 
435 		Vector2 p, p2;
436 		p = i == edited_point ? edited_point_pos : (poly[i] + node->get_offset());
437 		if ((wip_active && i == poly.size() - 1) || (((i + 1) % poly.size()) == edited_point))
438 			p2 = edited_point_pos;
439 		else
440 			p2 = poly[(i + 1) % poly.size()] + node->get_offset();
441 
442 		Vector2 point = xform.xform(p);
443 		Vector2 next_point = xform.xform(p2);
444 
445 		Color col = Color(1, 0.3, 0.1, 0.8);
446 		vpc->draw_line(point, next_point, col, 2);
447 		vpc->draw_texture(handle, point - handle->get_size() * 0.5);
448 	}
449 }
450 
_uv_mode(int p_mode)451 void Polygon2DEditor::_uv_mode(int p_mode) {
452 
453 	uv_mode = UVMode(p_mode);
454 	for (int i = 0; i < UV_MODE_MAX; i++) {
455 		uv_button[i]->set_pressed(p_mode == i);
456 	}
457 }
458 
_uv_input(const InputEvent & p_input)459 void Polygon2DEditor::_uv_input(const InputEvent &p_input) {
460 
461 	Matrix32 mtx;
462 	mtx.elements[2] = -uv_draw_ofs;
463 	mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
464 
465 	if (p_input.type == InputEvent::MOUSE_BUTTON) {
466 
467 		const InputEventMouseButton &mb = p_input.mouse_button;
468 
469 		if (mb.button_index == BUTTON_LEFT) {
470 
471 			if (mb.pressed) {
472 
473 				uv_drag_from = Vector2(mb.x, mb.y);
474 				uv_drag = true;
475 				uv_prev = node->get_uv();
476 				uv_move_current = uv_mode;
477 				if (uv_move_current == UV_MODE_EDIT_POINT) {
478 
479 					if (mb.mod.shift && mb.mod.command)
480 						uv_move_current = UV_MODE_SCALE;
481 					else if (mb.mod.shift)
482 						uv_move_current = UV_MODE_MOVE;
483 					else if (mb.mod.command)
484 						uv_move_current = UV_MODE_ROTATE;
485 				}
486 
487 				if (uv_move_current == UV_MODE_EDIT_POINT) {
488 
489 					uv_drag_index = -1;
490 					for (int i = 0; i < uv_prev.size(); i++) {
491 
492 						Vector2 tuv = mtx.xform(uv_prev[i]);
493 						if (tuv.distance_to(Vector2(mb.x, mb.y)) < 8) {
494 							uv_drag_from = tuv;
495 							uv_drag_index = i;
496 						}
497 					}
498 
499 					if (uv_drag_index == -1) {
500 						uv_drag = false;
501 					}
502 				}
503 			} else if (uv_drag) {
504 
505 				undo_redo->create_action(TTR("Transform UV Map"));
506 				undo_redo->add_do_method(node, "set_uv", node->get_uv());
507 				undo_redo->add_undo_method(node, "set_uv", uv_prev);
508 				undo_redo->add_do_method(uv_edit_draw, "update");
509 				undo_redo->add_undo_method(uv_edit_draw, "update");
510 				undo_redo->commit_action();
511 
512 				uv_drag = false;
513 			}
514 
515 		} else if (mb.button_index == BUTTON_RIGHT && mb.pressed) {
516 
517 			if (uv_drag) {
518 
519 				uv_drag = false;
520 				node->set_uv(uv_prev);
521 				uv_edit_draw->update();
522 			}
523 
524 		} else if (mb.button_index == BUTTON_WHEEL_UP && mb.pressed) {
525 
526 			uv_zoom->set_val(uv_zoom->get_val() / (1 - (0.1 * mb.factor)));
527 		} else if (mb.button_index == BUTTON_WHEEL_DOWN && mb.pressed) {
528 
529 			uv_zoom->set_val(uv_zoom->get_val() * (1 - (0.1 * mb.factor)));
530 		}
531 
532 	} else if (p_input.type == InputEvent::MOUSE_MOTION) {
533 
534 		const InputEventMouseMotion &mm = p_input.mouse_motion;
535 
536 		if (mm.button_mask & BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
537 
538 			Vector2 drag(mm.relative_x, mm.relative_y);
539 			uv_hscroll->set_val(uv_hscroll->get_val() - drag.x);
540 			uv_vscroll->set_val(uv_vscroll->get_val() - drag.y);
541 
542 		} else if (uv_drag) {
543 
544 			Vector2 uv_drag_to = snap_point(Vector2(mm.x, mm.y));
545 			Vector2 drag = mtx.affine_inverse().xform(uv_drag_to) - mtx.affine_inverse().xform(uv_drag_from);
546 
547 			switch (uv_move_current) {
548 
549 				case UV_MODE_EDIT_POINT: {
550 
551 					DVector<Vector2> uv_new = uv_prev;
552 					uv_new.set(uv_drag_index, uv_new[uv_drag_index] + drag);
553 					node->set_uv(uv_new);
554 				} break;
555 				case UV_MODE_MOVE: {
556 
557 					DVector<Vector2> uv_new = uv_prev;
558 					for (int i = 0; i < uv_new.size(); i++)
559 						uv_new.set(i, uv_new[i] + drag);
560 
561 					node->set_uv(uv_new);
562 
563 				} break;
564 				case UV_MODE_ROTATE: {
565 
566 					Vector2 center;
567 					DVector<Vector2> uv_new = uv_prev;
568 
569 					for (int i = 0; i < uv_new.size(); i++)
570 						center += uv_prev[i];
571 					center /= uv_new.size();
572 
573 					float angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to((uv_drag_to - mtx.xform(center)).normalized());
574 
575 					for (int i = 0; i < uv_new.size(); i++) {
576 						Vector2 rel = uv_prev[i] - center;
577 						rel = rel.rotated(angle);
578 						uv_new.set(i, center + rel);
579 					}
580 
581 					node->set_uv(uv_new);
582 
583 				} break;
584 				case UV_MODE_SCALE: {
585 
586 					Vector2 center;
587 					DVector<Vector2> uv_new = uv_prev;
588 
589 					for (int i = 0; i < uv_new.size(); i++)
590 						center += uv_prev[i];
591 					center /= uv_new.size();
592 
593 					float from_dist = uv_drag_from.distance_to(mtx.xform(center));
594 					float to_dist = uv_drag_to.distance_to(mtx.xform(center));
595 					if (from_dist < 2)
596 						break;
597 
598 					float scale = to_dist / from_dist;
599 
600 					for (int i = 0; i < uv_new.size(); i++) {
601 						Vector2 rel = uv_prev[i] - center;
602 						rel = rel * scale;
603 						uv_new.set(i, center + rel);
604 					}
605 
606 					node->set_uv(uv_new);
607 				} break;
608 			}
609 			uv_edit_draw->update();
610 		}
611 	}
612 }
613 
_uv_scroll_changed(float)614 void Polygon2DEditor::_uv_scroll_changed(float) {
615 
616 	if (updating_uv_scroll)
617 		return;
618 
619 	uv_draw_ofs.x = uv_hscroll->get_val();
620 	uv_draw_ofs.y = uv_vscroll->get_val();
621 	uv_draw_zoom = uv_zoom->get_val();
622 	uv_edit_draw->update();
623 }
624 
_uv_draw()625 void Polygon2DEditor::_uv_draw() {
626 
627 	Ref<Texture> base_tex = node->get_texture();
628 	if (base_tex.is_null())
629 		return;
630 
631 	Matrix32 mtx;
632 	mtx.elements[2] = -uv_draw_ofs;
633 	mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
634 
635 	VS::get_singleton()->canvas_item_set_clip(uv_edit_draw->get_canvas_item(), true);
636 	VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx);
637 	uv_edit_draw->draw_texture(base_tex, Point2());
638 	VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Matrix32());
639 
640 	if (snap_show_grid) {
641 		Size2 s = uv_edit_draw->get_size();
642 		int last_cell;
643 
644 		if (snap_step.x != 0) {
645 			for (int i = 0; i < s.width; i++) {
646 				int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i, 0)).x - snap_offset.x) / snap_step.x));
647 				if (i == 0)
648 					last_cell = cell;
649 				if (last_cell != cell)
650 					uv_edit_draw->draw_line(Point2(i, 0), Point2(i, s.height), Color(0.3, 0.7, 1, 0.3));
651 				last_cell = cell;
652 			}
653 		}
654 
655 		if (snap_step.y != 0) {
656 			for (int i = 0; i < s.height; i++) {
657 				int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0, i)).y - snap_offset.y) / snap_step.y));
658 				if (i == 0)
659 					last_cell = cell;
660 				if (last_cell != cell)
661 					uv_edit_draw->draw_line(Point2(0, i), Point2(s.width, i), Color(0.3, 0.7, 1, 0.3));
662 				last_cell = cell;
663 			}
664 		}
665 	}
666 
667 	DVector<Vector2> uvs = node->get_uv();
668 	Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
669 
670 	Rect2 rect(Point2(), mtx.basis_xform(base_tex->get_size()));
671 	rect.expand_to(mtx.basis_xform(uv_edit_draw->get_size()));
672 
673 	for (int i = 0; i < uvs.size(); i++) {
674 
675 		int next = (i + 1) % uvs.size();
676 		uv_edit_draw->draw_line(mtx.xform(uvs[i]), mtx.xform(uvs[next]), Color(0.9, 0.5, 0.5), 2);
677 		uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5);
678 		rect.expand_to(mtx.basis_xform(uvs[i]));
679 	}
680 
681 	rect = rect.grow(200);
682 	updating_uv_scroll = true;
683 	uv_hscroll->set_min(rect.pos.x);
684 	uv_hscroll->set_max(rect.pos.x + rect.size.x);
685 	uv_hscroll->set_page(uv_edit_draw->get_size().x);
686 	uv_hscroll->set_val(uv_draw_ofs.x);
687 	uv_hscroll->set_step(0.001);
688 
689 	uv_vscroll->set_min(rect.pos.y);
690 	uv_vscroll->set_max(rect.pos.y + rect.size.y);
691 	uv_vscroll->set_page(uv_edit_draw->get_size().y);
692 	uv_vscroll->set_val(uv_draw_ofs.y);
693 	uv_vscroll->set_step(0.001);
694 	updating_uv_scroll = false;
695 }
696 
edit(Node * p_collision_polygon)697 void Polygon2DEditor::edit(Node *p_collision_polygon) {
698 
699 	if (!canvas_item_editor) {
700 		canvas_item_editor = CanvasItemEditor::get_singleton();
701 	}
702 
703 	if (p_collision_polygon) {
704 
705 		node = p_collision_polygon->cast_to<Polygon2D>();
706 		if (!canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
707 			canvas_item_editor->get_viewport_control()->connect("draw", this, "_canvas_draw");
708 
709 		wip.clear();
710 		wip_active = false;
711 		edited_point = -1;
712 
713 	} else {
714 
715 		node = NULL;
716 
717 		if (canvas_item_editor->get_viewport_control()->is_connected("draw", this, "_canvas_draw"))
718 			canvas_item_editor->get_viewport_control()->disconnect("draw", this, "_canvas_draw");
719 	}
720 }
721 
_bind_methods()722 void Polygon2DEditor::_bind_methods() {
723 
724 	ObjectTypeDB::bind_method(_MD("_menu_option"), &Polygon2DEditor::_menu_option);
725 	ObjectTypeDB::bind_method(_MD("_canvas_draw"), &Polygon2DEditor::_canvas_draw);
726 	ObjectTypeDB::bind_method(_MD("_uv_mode"), &Polygon2DEditor::_uv_mode);
727 	ObjectTypeDB::bind_method(_MD("_uv_draw"), &Polygon2DEditor::_uv_draw);
728 	ObjectTypeDB::bind_method(_MD("_uv_input"), &Polygon2DEditor::_uv_input);
729 	ObjectTypeDB::bind_method(_MD("_uv_scroll_changed"), &Polygon2DEditor::_uv_scroll_changed);
730 	ObjectTypeDB::bind_method(_MD("_node_removed"), &Polygon2DEditor::_node_removed);
731 	ObjectTypeDB::bind_method(_MD("_set_use_snap"), &Polygon2DEditor::_set_use_snap);
732 	ObjectTypeDB::bind_method(_MD("_set_show_grid"), &Polygon2DEditor::_set_show_grid);
733 	ObjectTypeDB::bind_method(_MD("_set_snap_off_x"), &Polygon2DEditor::_set_snap_off_x);
734 	ObjectTypeDB::bind_method(_MD("_set_snap_off_y"), &Polygon2DEditor::_set_snap_off_y);
735 	ObjectTypeDB::bind_method(_MD("_set_snap_step_x"), &Polygon2DEditor::_set_snap_step_x);
736 	ObjectTypeDB::bind_method(_MD("_set_snap_step_y"), &Polygon2DEditor::_set_snap_step_y);
737 }
738 
_snap_scalar(float p_offset,float p_step,float p_target)739 inline float _snap_scalar(float p_offset, float p_step, float p_target) {
740 	return p_step != 0 ? Math::stepify(p_target - p_offset, p_step) + p_offset : p_target;
741 }
742 
snap_point(Vector2 p_target) const743 Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
744 	if (use_snap) {
745 		p_target.x = _snap_scalar(snap_offset.x * uv_draw_zoom - uv_draw_ofs.x, snap_step.x * uv_draw_zoom, p_target.x);
746 		p_target.y = _snap_scalar(snap_offset.y * uv_draw_zoom - uv_draw_ofs.y, snap_step.y * uv_draw_zoom, p_target.y);
747 	}
748 
749 	return p_target;
750 }
751 
Polygon2DEditor(EditorNode * p_editor)752 Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) {
753 
754 	node = NULL;
755 	canvas_item_editor = NULL;
756 	editor = p_editor;
757 	undo_redo = editor->get_undo_redo();
758 
759 	snap_step = Vector2(10, 10);
760 	use_snap = false;
761 	snap_show_grid = false;
762 
763 	add_child(memnew(VSeparator));
764 	button_create = memnew(ToolButton);
765 	add_child(button_create);
766 	button_create->connect("pressed", this, "_menu_option", varray(MODE_CREATE));
767 	button_create->set_toggle_mode(true);
768 
769 	button_edit = memnew(ToolButton);
770 	add_child(button_edit);
771 	button_edit->connect("pressed", this, "_menu_option", varray(MODE_EDIT));
772 	button_edit->set_toggle_mode(true);
773 
774 	button_uv = memnew(ToolButton);
775 	add_child(button_uv);
776 	button_uv->connect("pressed", this, "_menu_option", varray(MODE_EDIT_UV));
777 
778 	//add_constant_override("separation",0);
779 
780 #if 0
781 	options = memnew( MenuButton );
782 	add_child(options);
783 	options->set_area_as_parent_rect();
784 	options->set_text("Polygon");
785 	//options->get_popup()->add_item("Parse BBCode",PARSE_BBCODE);
786 	options->get_popup()->connect("item_pressed", this,"_menu_option");
787 #endif
788 
789 	mode = MODE_EDIT;
790 	wip_active = false;
791 
792 	uv_mode = UV_MODE_EDIT_POINT;
793 	uv_edit = memnew(AcceptDialog);
794 	add_child(uv_edit);
795 	uv_edit->set_title(TTR("Polygon 2D UV Editor"));
796 	uv_edit->set_self_opacity(0.9);
797 
798 	VBoxContainer *uv_main_vb = memnew(VBoxContainer);
799 	uv_edit->add_child(uv_main_vb);
800 	uv_edit->set_child_rect(uv_main_vb);
801 	HBoxContainer *uv_mode_hb = memnew(HBoxContainer);
802 	uv_main_vb->add_child(uv_mode_hb);
803 	for (int i = 0; i < UV_MODE_MAX; i++) {
804 
805 		uv_button[i] = memnew(ToolButton);
806 		uv_button[i]->set_toggle_mode(true);
807 		uv_mode_hb->add_child(uv_button[i]);
808 		uv_button[i]->connect("pressed", this, "_uv_mode", varray(i));
809 		uv_button[i]->set_focus_mode(FOCUS_NONE);
810 	}
811 
812 	uv_button[0]->set_tooltip(TTR("Move Point") + "\n" + TTR("Ctrl: Rotate") + "\n" + TTR("Shift: Move All") + "\n" + TTR("Shift+Ctrl: Scale"));
813 	uv_button[1]->set_tooltip(TTR("Move Polygon"));
814 	uv_button[2]->set_tooltip(TTR("Rotate Polygon"));
815 	uv_button[3]->set_tooltip(TTR("Scale Polygon"));
816 
817 	uv_button[0]->set_pressed(true);
818 	HBoxContainer *uv_main_hb = memnew(HBoxContainer);
819 	uv_main_vb->add_child(uv_main_hb);
820 	uv_edit_draw = memnew(Control);
821 	uv_main_hb->add_child(uv_edit_draw);
822 	uv_main_hb->set_v_size_flags(SIZE_EXPAND_FILL);
823 	uv_edit_draw->set_h_size_flags(SIZE_EXPAND_FILL);
824 	uv_menu = memnew(MenuButton);
825 	uv_mode_hb->add_child(uv_menu);
826 	uv_menu->set_text(TTR("Edit"));
827 	uv_menu->get_popup()->add_item(TTR("Polygon->UV"), UVEDIT_POLYGON_TO_UV);
828 	uv_menu->get_popup()->add_item(TTR("UV->Polygon"), UVEDIT_UV_TO_POLYGON);
829 	uv_menu->get_popup()->add_separator();
830 	uv_menu->get_popup()->add_item(TTR("Clear UV"), UVEDIT_UV_CLEAR);
831 	uv_menu->get_popup()->connect("item_pressed", this, "_menu_option");
832 
833 	uv_mode_hb->add_child(memnew(VSeparator));
834 
835 	b_snap_enable = memnew(ToolButton);
836 	uv_mode_hb->add_child(b_snap_enable);
837 	b_snap_enable->set_text(TTR("Snap"));
838 	b_snap_enable->set_focus_mode(FOCUS_NONE);
839 	b_snap_enable->set_toggle_mode(true);
840 	b_snap_enable->set_pressed(use_snap);
841 	b_snap_enable->set_tooltip(TTR("Enable Snap"));
842 	b_snap_enable->connect("toggled", this, "_set_use_snap");
843 
844 	b_snap_grid = memnew(ToolButton);
845 	uv_mode_hb->add_child(b_snap_grid);
846 	b_snap_grid->set_text(TTR("Grid"));
847 	b_snap_grid->set_focus_mode(FOCUS_NONE);
848 	b_snap_grid->set_toggle_mode(true);
849 	b_snap_grid->set_pressed(snap_show_grid);
850 	b_snap_grid->set_tooltip(TTR("Show Grid"));
851 	b_snap_grid->connect("toggled", this, "_set_show_grid");
852 
853 	uv_mode_hb->add_child(memnew(VSeparator));
854 	uv_mode_hb->add_child(memnew(Label(TTR("Grid Offset:"))));
855 
856 	SpinBox *sb_off_x = memnew(SpinBox);
857 	sb_off_x->set_min(-256);
858 	sb_off_x->set_max(256);
859 	sb_off_x->set_step(1);
860 	sb_off_x->set_val(snap_offset.x);
861 	sb_off_x->set_suffix("px");
862 	sb_off_x->connect("value_changed", this, "_set_snap_off_x");
863 	uv_mode_hb->add_child(sb_off_x);
864 
865 	SpinBox *sb_off_y = memnew(SpinBox);
866 	sb_off_y->set_min(-256);
867 	sb_off_y->set_max(256);
868 	sb_off_y->set_step(1);
869 	sb_off_y->set_val(snap_offset.y);
870 	sb_off_y->set_suffix("px");
871 	sb_off_y->connect("value_changed", this, "_set_snap_off_y");
872 	uv_mode_hb->add_child(sb_off_y);
873 
874 	uv_mode_hb->add_child(memnew(VSeparator));
875 	uv_mode_hb->add_child(memnew(Label(TTR("Grid Step:"))));
876 
877 	SpinBox *sb_step_x = memnew(SpinBox);
878 	sb_step_x->set_min(-256);
879 	sb_step_x->set_max(256);
880 	sb_step_x->set_step(1);
881 	sb_step_x->set_val(snap_step.x);
882 	sb_step_x->set_suffix("px");
883 	sb_step_x->connect("value_changed", this, "_set_snap_step_x");
884 	uv_mode_hb->add_child(sb_step_x);
885 
886 	SpinBox *sb_step_y = memnew(SpinBox);
887 	sb_step_y->set_min(-256);
888 	sb_step_y->set_max(256);
889 	sb_step_y->set_step(1);
890 	sb_step_y->set_val(snap_step.y);
891 	sb_step_y->set_suffix("px");
892 	sb_step_y->connect("value_changed", this, "_set_snap_step_y");
893 	uv_mode_hb->add_child(sb_step_y);
894 
895 	uv_mode_hb->add_child(memnew(VSeparator));
896 	uv_icon_zoom = memnew(TextureFrame);
897 	uv_mode_hb->add_child(uv_icon_zoom);
898 	uv_zoom = memnew(HSlider);
899 	uv_zoom->set_min(0.01);
900 	uv_zoom->set_max(4);
901 	uv_zoom->set_val(1);
902 	uv_zoom->set_step(0.01);
903 	uv_mode_hb->add_child(uv_zoom);
904 	uv_zoom->set_custom_minimum_size(Size2(200, 0));
905 	uv_zoom_value = memnew(SpinBox);
906 	uv_zoom->share(uv_zoom_value);
907 	uv_zoom_value->set_custom_minimum_size(Size2(50, 0));
908 	uv_mode_hb->add_child(uv_zoom_value);
909 	uv_zoom->connect("value_changed", this, "_uv_scroll_changed");
910 
911 	uv_vscroll = memnew(VScrollBar);
912 	uv_main_hb->add_child(uv_vscroll);
913 	uv_vscroll->connect("value_changed", this, "_uv_scroll_changed");
914 	uv_hscroll = memnew(HScrollBar);
915 	uv_main_vb->add_child(uv_hscroll);
916 	uv_hscroll->connect("value_changed", this, "_uv_scroll_changed");
917 
918 	uv_edit_draw->connect("draw", this, "_uv_draw");
919 	uv_edit_draw->connect("input_event", this, "_uv_input");
920 	uv_draw_zoom = 1.0;
921 	uv_drag_index = -1;
922 	uv_drag = false;
923 	updating_uv_scroll = false;
924 
925 	error = memnew(AcceptDialog);
926 	add_child(error);
927 }
928 
edit(Object * p_object)929 void Polygon2DEditorPlugin::edit(Object *p_object) {
930 
931 	collision_polygon_editor->edit(p_object->cast_to<Node>());
932 }
933 
handles(Object * p_object) const934 bool Polygon2DEditorPlugin::handles(Object *p_object) const {
935 
936 	return p_object->is_type("Polygon2D");
937 }
938 
make_visible(bool p_visible)939 void Polygon2DEditorPlugin::make_visible(bool p_visible) {
940 
941 	if (p_visible) {
942 		collision_polygon_editor->show();
943 	} else {
944 
945 		collision_polygon_editor->hide();
946 		collision_polygon_editor->edit(NULL);
947 	}
948 }
949 
Polygon2DEditorPlugin(EditorNode * p_node)950 Polygon2DEditorPlugin::Polygon2DEditorPlugin(EditorNode *p_node) {
951 
952 	editor = p_node;
953 	collision_polygon_editor = memnew(Polygon2DEditor(p_node));
954 	CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
955 
956 	collision_polygon_editor->hide();
957 }
958 
~Polygon2DEditorPlugin()959 Polygon2DEditorPlugin::~Polygon2DEditorPlugin() {
960 }
961