abstract_polygon_2d_editor.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. /**************************************************************************/
  2. /* abstract_polygon_2d_editor.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  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. #include "abstract_polygon_2d_editor.h"
  31. #include "core/math/geometry_2d.h"
  32. #include "core/os/keyboard.h"
  33. #include "editor/editor_node.h"
  34. #include "editor/editor_string_names.h"
  35. #include "editor/editor_undo_redo_manager.h"
  36. #include "editor/scene/canvas_item_editor_plugin.h"
  37. #include "editor/settings/editor_settings.h"
  38. #include "editor/themes/editor_scale.h"
  39. #include "scene/gui/button.h"
  40. #include "scene/gui/dialogs.h"
  41. bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const {
  42. return polygon == p_vertex.polygon && vertex == p_vertex.vertex;
  43. }
  44. bool AbstractPolygon2DEditor::Vertex::operator!=(const AbstractPolygon2DEditor::Vertex &p_vertex) const {
  45. return !(*this == p_vertex);
  46. }
  47. bool AbstractPolygon2DEditor::Vertex::valid() const {
  48. return vertex >= 0;
  49. }
  50. bool AbstractPolygon2DEditor::_is_empty() const {
  51. if (!_get_node()) {
  52. return true;
  53. }
  54. const int n = _get_polygon_count();
  55. for (int i = 0; i < n; i++) {
  56. Vector<Vector2> vertices = _get_polygon(i);
  57. if (vertices.size() != 0) {
  58. return false;
  59. }
  60. }
  61. return true;
  62. }
  63. bool AbstractPolygon2DEditor::_is_line() const {
  64. return false;
  65. }
  66. bool AbstractPolygon2DEditor::_has_uv() const {
  67. return false;
  68. }
  69. int AbstractPolygon2DEditor::_get_polygon_count() const {
  70. return 1;
  71. }
  72. Variant AbstractPolygon2DEditor::_get_polygon(int p_idx) const {
  73. return _get_node()->get("polygon");
  74. }
  75. void AbstractPolygon2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const {
  76. _get_node()->set("polygon", p_polygon);
  77. }
  78. void AbstractPolygon2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
  79. Node2D *node = _get_node();
  80. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
  81. undo_redo->add_do_method(node, "set_polygon", p_polygon);
  82. undo_redo->add_undo_method(node, "set_polygon", p_previous);
  83. }
  84. Vector2 AbstractPolygon2DEditor::_get_offset(int p_idx) const {
  85. return Vector2(0, 0);
  86. }
  87. void AbstractPolygon2DEditor::_commit_action() {
  88. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
  89. undo_redo->add_do_method(canvas_item_editor, "update_viewport");
  90. undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
  91. undo_redo->commit_action();
  92. }
  93. void AbstractPolygon2DEditor::_action_add_polygon(const Variant &p_polygon) {
  94. _action_set_polygon(0, p_polygon);
  95. }
  96. void AbstractPolygon2DEditor::_action_remove_polygon(int p_idx) {
  97. _action_set_polygon(p_idx, _get_polygon(p_idx), Vector<Vector2>());
  98. }
  99. void AbstractPolygon2DEditor::_action_set_polygon(int p_idx, const Variant &p_polygon) {
  100. _action_set_polygon(p_idx, _get_polygon(p_idx), p_polygon);
  101. }
  102. bool AbstractPolygon2DEditor::_has_resource() const {
  103. return true;
  104. }
  105. void AbstractPolygon2DEditor::_create_resource() {
  106. }
  107. Vector2 AbstractPolygon2DEditor::_get_geometric_center() const {
  108. int n_polygons = _get_polygon_count();
  109. double cx = 0.0;
  110. double cy = 0.0;
  111. int n_subs = 0;
  112. for (int i = 0; i < n_polygons; i++) {
  113. const Vector<Vector2> &vertices = _get_polygon(i);
  114. Vector<Vector<Point2>> decomp = ::Geometry2D::decompose_polygon_in_convex(vertices);
  115. if (decomp.is_empty()) {
  116. continue;
  117. }
  118. for (const Vector<Vector2> &sub : decomp) {
  119. int sub_n_points = sub.size();
  120. double sub_area2x = 0.0;
  121. double sub_cx = 0.0;
  122. double sub_cy = 0.0;
  123. for (int n = 0; n < sub_n_points; n++) {
  124. int next = (n + 1 < sub_n_points) ? n + 1 : 0;
  125. sub_area2x += (sub[n].x * sub[next].y) - (sub[next].x * sub[n].y);
  126. sub_cx += (sub[n].x + sub[next].x) * (sub[n].x * sub[next].y - sub[next].x * sub[n].y);
  127. sub_cy += (sub[n].y + sub[next].y) * (sub[n].x * sub[next].y - sub[next].x * sub[n].y);
  128. }
  129. sub_cx /= (sub_area2x * 3);
  130. sub_cy /= (sub_area2x * 3);
  131. cx += sub_cx;
  132. cy += sub_cy;
  133. }
  134. n_subs += decomp.size();
  135. }
  136. cx /= n_subs;
  137. cy /= n_subs;
  138. return Vector2(cx, cy);
  139. }
  140. void AbstractPolygon2DEditor::_menu_option(int p_option) {
  141. switch (p_option) {
  142. case MODE_CREATE: {
  143. mode = MODE_CREATE;
  144. button_create->set_pressed(true);
  145. button_edit->set_pressed(false);
  146. button_delete->set_pressed(false);
  147. } break;
  148. case MODE_EDIT: {
  149. _wip_close();
  150. mode = MODE_EDIT;
  151. button_create->set_pressed(false);
  152. button_edit->set_pressed(true);
  153. button_delete->set_pressed(false);
  154. } break;
  155. case MODE_DELETE: {
  156. _wip_close();
  157. mode = MODE_DELETE;
  158. button_create->set_pressed(false);
  159. button_edit->set_pressed(false);
  160. button_delete->set_pressed(true);
  161. } break;
  162. case CENTER_POLY: {
  163. _wip_close();
  164. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
  165. undo_redo->create_action(TTR("Move Origin to Geometric Center"));
  166. Vector2 center = _get_geometric_center();
  167. int n_polygons = _get_polygon_count();
  168. for (int i = 0; i < n_polygons; i++) {
  169. const Vector<Vector2> &vertices = _get_polygon(i);
  170. int n_points = vertices.size();
  171. Vector<Vector2> new_vertices;
  172. new_vertices.resize(n_points);
  173. for (int n = 0; n < n_points; n++) {
  174. new_vertices.write[n] = vertices[n] - center;
  175. }
  176. _action_set_polygon(i, vertices, new_vertices);
  177. }
  178. Node2D *node = _get_node();
  179. Vector2 node_pos = node->get_position();
  180. undo_redo->add_do_method(node, "set_position", node_pos + node->get_transform().basis_xform(center));
  181. undo_redo->add_undo_method(node, "set_position", node_pos);
  182. _commit_action();
  183. } break;
  184. }
  185. }
  186. void AbstractPolygon2DEditor::_notification(int p_what) {
  187. switch (p_what) {
  188. case NOTIFICATION_THEME_CHANGED: {
  189. button_create->set_button_icon(get_editor_theme_icon(SNAME("CurveCreate")));
  190. button_edit->set_button_icon(get_editor_theme_icon(SNAME("CurveEdit")));
  191. button_delete->set_button_icon(get_editor_theme_icon(SNAME("CurveDelete")));
  192. button_center->set_button_icon(get_editor_theme_icon(SNAME("CurveCenter")));
  193. } break;
  194. case NOTIFICATION_READY: {
  195. disable_polygon_editing(false, String());
  196. button_edit->set_pressed(true);
  197. get_tree()->connect("node_removed", callable_mp(this, &AbstractPolygon2DEditor::_node_removed));
  198. create_resource->connect(SceneStringName(confirmed), callable_mp(this, &AbstractPolygon2DEditor::_create_resource));
  199. } break;
  200. }
  201. }
  202. void AbstractPolygon2DEditor::_node_removed(Node *p_node) {
  203. if (p_node == _get_node()) {
  204. edit(nullptr);
  205. hide();
  206. canvas_item_editor->update_viewport();
  207. }
  208. }
  209. void AbstractPolygon2DEditor::_wip_changed() {
  210. if (wip_active && _is_line()) {
  211. _set_polygon(0, wip);
  212. }
  213. }
  214. void AbstractPolygon2DEditor::_wip_cancel() {
  215. wip.clear();
  216. wip_active = false;
  217. edited_point = PosVertex();
  218. hover_point = Vertex();
  219. selected_point = Vertex();
  220. center_drag = false;
  221. canvas_item_editor->update_viewport();
  222. }
  223. void AbstractPolygon2DEditor::_wip_close() {
  224. if (!wip_active) {
  225. return;
  226. }
  227. if (_is_line()) {
  228. _set_polygon(0, wip);
  229. } else if (wip.size() >= (_is_line() ? 2 : 3)) {
  230. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
  231. undo_redo->create_action(TTR("Create Polygon"));
  232. _action_add_polygon(wip);
  233. if (_has_uv()) {
  234. undo_redo->add_do_method(_get_node(), "set_uv", Vector<Vector2>());
  235. undo_redo->add_undo_method(_get_node(), "set_uv", _get_node()->get("uv"));
  236. }
  237. _commit_action();
  238. } else {
  239. return;
  240. }
  241. mode = MODE_EDIT;
  242. button_edit->set_pressed(true);
  243. button_create->set_pressed(false);
  244. button_delete->set_pressed(false);
  245. wip.clear();
  246. wip_active = false;
  247. edited_point = PosVertex();
  248. hover_point = Vertex();
  249. selected_point = Vertex();
  250. center_drag = false;
  251. }
  252. void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, const String &p_reason) {
  253. _polygon_editing_enabled = !p_disable;
  254. button_create->set_disabled(p_disable);
  255. button_edit->set_disabled(p_disable);
  256. button_delete->set_disabled(p_disable);
  257. button_center->set_disabled(p_disable);
  258. if (p_disable) {
  259. button_create->set_tooltip_text(p_reason);
  260. button_edit->set_tooltip_text(p_reason);
  261. button_delete->set_tooltip_text(p_reason);
  262. button_center->set_tooltip_text(p_reason);
  263. } else {
  264. button_create->set_tooltip_text(TTRC("Create points."));
  265. button_edit->set_tooltip_text(TTRC("Edit points.\nLMB: Move Point\nRMB: Erase Point"));
  266. button_delete->set_tooltip_text(TTRC("Erase points."));
  267. button_center->set_tooltip_text(TTRC("Move center of gravity to geometric center."));
  268. }
  269. }
  270. bool AbstractPolygon2DEditor::_commit_drag() {
  271. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
  272. center_drag = false;
  273. int n_polygons = _get_polygon_count();
  274. ERR_FAIL_COND_V(pre_center_move_edit.size() != n_polygons, false);
  275. undo_redo->create_action(TTR("Move Geometric Center"));
  276. for (int i = 0; i < n_polygons; i++) {
  277. _action_set_polygon(i, pre_center_move_edit[i], _get_polygon(i));
  278. }
  279. pre_center_move_edit.clear();
  280. _commit_action();
  281. return true;
  282. }
  283. bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
  284. if (!_get_node() || !_polygon_editing_enabled) {
  285. return false;
  286. }
  287. if (!_get_node()->is_visible_in_tree()) {
  288. return false;
  289. }
  290. Viewport *vp = _get_node()->get_viewport();
  291. if (vp && !vp->is_visible_subviewport()) {
  292. return false;
  293. }
  294. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
  295. Ref<InputEventMouseButton> mb = p_event;
  296. if (!_has_resource()) {
  297. if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
  298. create_resource->set_text(String("No polygon resource on this node.\nCreate and assign one?"));
  299. create_resource->popup_centered();
  300. }
  301. return (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT);
  302. }
  303. CanvasItemEditor::Tool tool = CanvasItemEditor::get_singleton()->get_current_tool();
  304. if (tool != CanvasItemEditor::TOOL_SELECT) {
  305. return false;
  306. }
  307. if (mb.is_valid()) {
  308. Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_screen_transform();
  309. Vector2 gpoint = mb->get_position();
  310. Vector2 cpoint = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint));
  311. cpoint = _get_node()->get_screen_transform().affine_inverse().xform(cpoint);
  312. if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
  313. if (mb->get_button_index() == MouseButton::LEFT) {
  314. if (mb->is_pressed()) {
  315. if (mb->is_meta_pressed() || mb->is_ctrl_pressed() || mb->is_shift_pressed() || mb->is_alt_pressed()) {
  316. return false;
  317. }
  318. const PosVertex closest = closest_point(gpoint);
  319. if (closest.valid()) {
  320. original_mouse_pos = gpoint;
  321. pre_move_edit = _get_polygon(closest.polygon);
  322. edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos));
  323. selected_point = closest;
  324. edge_point = PosVertex();
  325. canvas_item_editor->update_viewport();
  326. return true;
  327. } else {
  328. selected_point = Vertex();
  329. const PosVertex insert = closest_edge_point(gpoint);
  330. if (insert.valid()) {
  331. Vector<Vector2> vertices = _get_polygon(insert.polygon);
  332. if (vertices.size() < (_is_line() ? 2 : 3)) {
  333. vertices.push_back(cpoint);
  334. undo_redo->create_action(TTR("Edit Polygon"));
  335. selected_point = Vertex(insert.polygon, vertices.size());
  336. _action_set_polygon(insert.polygon, vertices);
  337. _commit_action();
  338. return true;
  339. } else {
  340. edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos));
  341. vertices.insert(edited_point.vertex, edited_point.pos);
  342. pre_move_edit = vertices;
  343. selected_point = Vertex(edited_point.polygon, edited_point.vertex);
  344. edge_point = PosVertex();
  345. undo_redo->create_action(TTR("Insert Point"));
  346. _action_set_polygon(insert.polygon, vertices);
  347. _commit_action();
  348. return true;
  349. }
  350. }
  351. }
  352. } else {
  353. if (edited_point.valid()) {
  354. if (original_mouse_pos != gpoint) {
  355. Vector<Vector2> vertices = _get_polygon(edited_point.polygon);
  356. ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false);
  357. vertices.write[edited_point.vertex] = edited_point.pos - _get_offset(edited_point.polygon);
  358. undo_redo->create_action(TTR("Edit Polygon"));
  359. _action_set_polygon(edited_point.polygon, pre_move_edit, vertices);
  360. _commit_action();
  361. }
  362. edited_point = PosVertex();
  363. return true;
  364. }
  365. }
  366. } else if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed() && !edited_point.valid()) {
  367. const PosVertex closest = closest_point(gpoint);
  368. if (closest.valid()) {
  369. remove_point(closest);
  370. return true;
  371. }
  372. }
  373. } else if (mode == MODE_DELETE) {
  374. if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
  375. const PosVertex closest = closest_point(gpoint);
  376. if (closest.valid()) {
  377. remove_point(closest);
  378. return true;
  379. }
  380. }
  381. }
  382. if (mode == MODE_CREATE) {
  383. if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
  384. if (_is_line()) {
  385. // for lines, we don't have a wip mode, and we can undo each single add point.
  386. Vector<Vector2> vertices = _get_polygon(0);
  387. vertices.push_back(cpoint);
  388. undo_redo->create_action(TTR("Insert Point"));
  389. _action_set_polygon(0, vertices);
  390. _commit_action();
  391. return true;
  392. } else if (!wip_active) {
  393. wip.clear();
  394. wip.push_back(cpoint);
  395. wip_active = true;
  396. _wip_changed();
  397. edited_point = PosVertex(-1, 1, cpoint);
  398. canvas_item_editor->update_viewport();
  399. hover_point = Vertex();
  400. selected_point = Vertex(0);
  401. edge_point = PosVertex();
  402. return true;
  403. } else {
  404. const real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
  405. if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(xform.xform(cpoint)) < grab_threshold) {
  406. //wip closed
  407. _wip_close();
  408. return true;
  409. } else {
  410. //add wip point
  411. wip.push_back(cpoint);
  412. _wip_changed();
  413. edited_point = PosVertex(-1, wip.size(), cpoint);
  414. selected_point = Vertex(wip.size() - 1);
  415. canvas_item_editor->update_viewport();
  416. return true;
  417. }
  418. }
  419. } else if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed() && wip_active) {
  420. _wip_cancel();
  421. }
  422. }
  423. // Center drag.
  424. if (edit_origin_and_center) {
  425. real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
  426. if (mb->get_button_index() == MouseButton::LEFT) {
  427. if (mb->is_meta_pressed() || mb->is_ctrl_pressed() || mb->is_shift_pressed() || mb->is_alt_pressed()) {
  428. return false;
  429. }
  430. if (mb->is_pressed() && !center_drag) {
  431. Vector2 center_point = xform.xform(_get_geometric_center());
  432. if ((gpoint - center_point).length() < grab_threshold) {
  433. pre_center_move_edit.clear();
  434. int n_polygons = _get_polygon_count();
  435. for (int i = 0; i < n_polygons; i++) {
  436. pre_center_move_edit.push_back(_get_polygon(i));
  437. }
  438. center_drag_origin = cpoint;
  439. center_drag = true;
  440. return true;
  441. }
  442. } else if (center_drag) {
  443. return _commit_drag();
  444. }
  445. } else if (mb->get_button_index() == MouseButton::RIGHT && center_drag) {
  446. _commit_drag();
  447. }
  448. }
  449. }
  450. Ref<InputEventMouseMotion> mm = p_event;
  451. if (mm.is_valid()) {
  452. Vector2 gpoint = mm->get_position();
  453. if (center_drag) {
  454. Vector2 cpoint = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint));
  455. cpoint = _get_node()->get_screen_transform().affine_inverse().xform(cpoint);
  456. Vector2 delta = center_drag_origin - cpoint;
  457. int n_polygons = _get_polygon_count();
  458. for (int i = 0; i < n_polygons; i++) {
  459. const Vector<Vector2> &vertices = _get_polygon(i);
  460. int n_points = vertices.size();
  461. Vector<Vector2> new_vertices;
  462. new_vertices.resize(n_points);
  463. for (int n = 0; n < n_points; n++) {
  464. new_vertices.write[n] = vertices[n] - delta;
  465. }
  466. _set_polygon(i, new_vertices);
  467. }
  468. center_drag_origin = cpoint;
  469. } else if (edited_point.valid() && (wip_active || mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
  470. Vector2 cpoint = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint));
  471. cpoint = _get_node()->get_screen_transform().affine_inverse().xform(cpoint);
  472. //Move the point in a single axis. Should only work when editing a polygon and while holding shift.
  473. if (mode == MODE_EDIT && mm->is_shift_pressed()) {
  474. Vector2 old_point = pre_move_edit.get(selected_point.vertex);
  475. if (Math::abs(cpoint.x - old_point.x) > Math::abs(cpoint.y - old_point.y)) {
  476. cpoint.y = old_point.y;
  477. } else {
  478. cpoint.x = old_point.x;
  479. }
  480. }
  481. edited_point = PosVertex(edited_point, cpoint);
  482. if (!wip_active) {
  483. Vector<Vector2> vertices = _get_polygon(edited_point.polygon);
  484. ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false);
  485. vertices.write[edited_point.vertex] = cpoint - _get_offset(edited_point.polygon);
  486. _set_polygon(edited_point.polygon, vertices);
  487. }
  488. canvas_item_editor->update_viewport();
  489. } else if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
  490. const PosVertex new_hover_point = closest_point(gpoint);
  491. if (hover_point != new_hover_point) {
  492. hover_point = new_hover_point;
  493. canvas_item_editor->update_viewport();
  494. }
  495. bool edge_hover = false;
  496. if (!hover_point.valid()) {
  497. const PosVertex on_edge_vertex = closest_edge_point(gpoint);
  498. if (on_edge_vertex.valid()) {
  499. hover_point = Vertex();
  500. edge_point = on_edge_vertex;
  501. canvas_item_editor->update_viewport();
  502. edge_hover = true;
  503. }
  504. }
  505. if (!edge_hover && edge_point.valid()) {
  506. edge_point = PosVertex();
  507. canvas_item_editor->update_viewport();
  508. }
  509. }
  510. }
  511. Ref<InputEventKey> k = p_event;
  512. if (k.is_valid() && k->is_pressed()) {
  513. if (k->get_keycode() == Key::KEY_DELETE || k->get_keycode() == Key::BACKSPACE) {
  514. if (wip_active && selected_point.polygon == -1) {
  515. if (wip.size() > selected_point.vertex) {
  516. wip.remove_at(selected_point.vertex);
  517. _wip_changed();
  518. selected_point = wip.size() - 1;
  519. canvas_item_editor->update_viewport();
  520. return true;
  521. }
  522. } else {
  523. const Vertex active_point = get_active_point();
  524. if (active_point.valid()) {
  525. remove_point(active_point);
  526. return true;
  527. }
  528. }
  529. } else if (wip_active && k->get_keycode() == Key::ENTER) {
  530. _wip_close();
  531. } else if (wip_active && k->get_keycode() == Key::ESCAPE) {
  532. _wip_cancel();
  533. }
  534. }
  535. return false;
  536. }
  537. void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
  538. if (!_get_node()) {
  539. return;
  540. }
  541. if (!_get_node()->is_visible_in_tree()) {
  542. return;
  543. }
  544. Viewport *vp = _get_node()->get_viewport();
  545. if (vp && !vp->is_visible_subviewport()) {
  546. return;
  547. }
  548. Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_screen_transform();
  549. // All polygon points are sharp, so use the sharp handle icon
  550. const Ref<Texture2D> handle = get_editor_theme_icon(SNAME("EditorPathSharpHandle"));
  551. const Ref<Texture2D> nhandle = get_editor_theme_icon(SNAME("EditorPathNullHandle"));
  552. Ref<Font> font = get_theme_font(SNAME("bold"), EditorStringName(EditorFonts));
  553. int font_size = 1.3 * get_theme_font_size(SNAME("bold_size"), EditorStringName(EditorFonts));
  554. const float outline_size = 4 * EDSCALE;
  555. Color font_color = get_theme_color(SceneStringName(font_color), EditorStringName(Editor));
  556. Color outline_color = font_color.inverted();
  557. const Vertex active_point = get_active_point();
  558. const int n_polygons = _get_polygon_count();
  559. const bool is_closed = !_is_line();
  560. if (edit_origin_and_center) {
  561. const Vector2 &center = _get_geometric_center();
  562. if (!center.is_zero_approx()) {
  563. const Vector2 point = xform.xform(center);
  564. p_overlay->draw_texture(nhandle, point - nhandle->get_size() * 0.5, Color(1, 1, 0.4));
  565. Size2 lbl_size = font->get_string_size("c", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
  566. p_overlay->draw_string_outline(font, point - lbl_size * 0.5, "c", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
  567. p_overlay->draw_string(font, point - lbl_size * 0.5, "c", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
  568. }
  569. {
  570. const Vector2 point = xform.xform(Vector2());
  571. p_overlay->draw_texture(nhandle, point - nhandle->get_size() * 0.5, center.is_equal_approx(Vector2()) ? Color(1, 1, 0.4) : Color(1, 0.4, 1));
  572. Size2 lbl_size = font->get_string_size("o", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
  573. p_overlay->draw_string_outline(font, point - lbl_size * 0.5, "o", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
  574. p_overlay->draw_string(font, point - lbl_size * 0.5, "o", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
  575. }
  576. }
  577. for (int j = -1; j < n_polygons; j++) {
  578. if (wip_active && wip_destructive && j != -1) {
  579. continue;
  580. }
  581. Vector<Vector2> points;
  582. Vector2 offset;
  583. if (wip_active && j == edited_point.polygon) {
  584. points = Variant(wip);
  585. offset = Vector2(0, 0);
  586. } else {
  587. if (j == -1) {
  588. continue;
  589. }
  590. points = _get_polygon(j);
  591. offset = _get_offset(j);
  592. }
  593. if (!wip_active && j == edited_point.polygon && EDITOR_GET("editors/polygon_editor/show_previous_outline")) {
  594. const Color col = Color(0.5, 0.5, 0.5); // FIXME polygon->get_outline_color();
  595. const int n = pre_move_edit.size();
  596. for (int i = 0; i < n - (is_closed ? 0 : 1); i++) {
  597. Vector2 p, p2;
  598. p = pre_move_edit[i] + offset;
  599. p2 = pre_move_edit[(i + 1) % n] + offset;
  600. Vector2 point = xform.xform(p);
  601. Vector2 next_point = xform.xform(p2);
  602. p_overlay->draw_line(point, next_point, col, Math::round(2 * EDSCALE));
  603. }
  604. }
  605. const int n_points = points.size();
  606. const Color col = Color(1, 0.3, 0.1, 0.8);
  607. for (int i = 0; i < n_points; i++) {
  608. const Vertex vertex(j, i);
  609. const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset);
  610. const Vector2 point = xform.xform(p);
  611. if (is_closed || i < n_points - 1) {
  612. Vector2 p2;
  613. if (j == edited_point.polygon &&
  614. ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point.vertex))) {
  615. p2 = edited_point.pos;
  616. } else {
  617. p2 = points[(i + 1) % n_points] + offset;
  618. }
  619. const Vector2 next_point = xform.xform(p2);
  620. p_overlay->draw_line(point, next_point, col, Math::round(2 * EDSCALE));
  621. }
  622. }
  623. for (int i = 0; i < n_points; i++) {
  624. const Vertex vertex(j, i);
  625. const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset);
  626. const Vector2 point = xform.xform(p);
  627. const Color overlay_modulate = vertex == active_point ? Color(0.4, 1, 1) : Color(1, 1, 1);
  628. p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, overlay_modulate);
  629. if (vertex == hover_point) {
  630. String num = String::num_int64(vertex.vertex);
  631. Size2 num_size = font->get_string_size(num, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
  632. p_overlay->draw_string_outline(font, point - num_size * 0.5, num, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
  633. p_overlay->draw_string(font, point - num_size * 0.5, num, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
  634. }
  635. }
  636. }
  637. if (edge_point.valid()) {
  638. Ref<Texture2D> add_handle = get_editor_theme_icon(SNAME("EditorHandleAdd"));
  639. p_overlay->draw_texture(add_handle, edge_point.pos - add_handle->get_size() * 0.5);
  640. }
  641. }
  642. void AbstractPolygon2DEditor::set_edit_origin_and_center(bool p_enabled) {
  643. edit_origin_and_center = p_enabled;
  644. if (button_center) {
  645. button_center->set_visible(edit_origin_and_center);
  646. }
  647. }
  648. void AbstractPolygon2DEditor::edit(Node *p_polygon) {
  649. if (!canvas_item_editor) {
  650. canvas_item_editor = CanvasItemEditor::get_singleton();
  651. }
  652. if (p_polygon) {
  653. _set_node(p_polygon);
  654. // Enable the pencil tool if the polygon is empty.
  655. if (_is_empty()) {
  656. _menu_option(MODE_CREATE);
  657. } else {
  658. _menu_option(MODE_EDIT);
  659. }
  660. wip.clear();
  661. wip_active = false;
  662. edited_point = PosVertex();
  663. hover_point = Vertex();
  664. selected_point = Vertex();
  665. center_drag = false;
  666. } else {
  667. _set_node(nullptr);
  668. }
  669. canvas_item_editor->update_viewport();
  670. }
  671. void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) {
  672. EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
  673. Vector<Vector2> vertices = _get_polygon(p_vertex.polygon);
  674. if (vertices.size() > (_is_line() ? 2 : 3)) {
  675. vertices.remove_at(p_vertex.vertex);
  676. undo_redo->create_action(TTR("Edit Polygon (Remove Point)"));
  677. _action_set_polygon(p_vertex.polygon, vertices);
  678. _commit_action();
  679. } else {
  680. undo_redo->create_action(TTR("Remove Polygon And Point"));
  681. _action_remove_polygon(p_vertex.polygon);
  682. _commit_action();
  683. }
  684. if (_is_empty()) {
  685. _menu_option(MODE_CREATE);
  686. }
  687. hover_point = Vertex();
  688. if (selected_point == p_vertex) {
  689. selected_point = Vertex();
  690. }
  691. }
  692. AbstractPolygon2DEditor::Vertex AbstractPolygon2DEditor::get_active_point() const {
  693. return hover_point.valid() ? hover_point : selected_point;
  694. }
  695. AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_point(const Vector2 &p_pos) const {
  696. const real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
  697. const int n_polygons = _get_polygon_count();
  698. const Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_screen_transform();
  699. PosVertex closest;
  700. real_t closest_dist = 1e10;
  701. for (int j = 0; j < n_polygons; j++) {
  702. Vector<Vector2> points = _get_polygon(j);
  703. const Vector2 offset = _get_offset(j);
  704. const int n_points = points.size();
  705. for (int i = 0; i < n_points; i++) {
  706. Vector2 cp = xform.xform(points[i] + offset);
  707. real_t d = cp.distance_to(p_pos);
  708. if (d < closest_dist && d < grab_threshold) {
  709. closest_dist = d;
  710. closest = PosVertex(j, i, cp);
  711. }
  712. }
  713. }
  714. return closest;
  715. }
  716. AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(const Vector2 &p_pos) const {
  717. const real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
  718. const real_t eps = grab_threshold * 2;
  719. const real_t eps2 = eps * eps;
  720. const int n_polygons = _get_polygon_count();
  721. const Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_screen_transform();
  722. PosVertex closest;
  723. real_t closest_dist = 1e10;
  724. for (int j = 0; j < n_polygons; j++) {
  725. Vector<Vector2> points = _get_polygon(j);
  726. const Vector2 offset = _get_offset(j);
  727. const int n_points = points.size();
  728. const int n_segments = n_points - (_is_line() ? 1 : 0);
  729. for (int i = 0; i < n_segments; i++) {
  730. const Vector2 segment_a = xform.xform(points[i] + offset);
  731. const Vector2 segment_b = xform.xform(points[(i + 1) % n_points] + offset);
  732. Vector2 cp = Geometry2D::get_closest_point_to_segment(p_pos, segment_a, segment_b);
  733. if (cp.distance_squared_to(segment_a) < eps2 || cp.distance_squared_to(segment_b) < eps2) {
  734. continue; //not valid to reuse point
  735. }
  736. real_t d = cp.distance_to(p_pos);
  737. if (d < closest_dist && d < grab_threshold) {
  738. closest_dist = d;
  739. closest = PosVertex(j, i, cp);
  740. }
  741. }
  742. }
  743. return closest;
  744. }
  745. AbstractPolygon2DEditor::AbstractPolygon2DEditor(bool p_wip_destructive) {
  746. edited_point = PosVertex();
  747. center_drag = false;
  748. wip_destructive = p_wip_destructive;
  749. hover_point = Vertex();
  750. selected_point = Vertex();
  751. edge_point = PosVertex();
  752. button_create = memnew(Button);
  753. button_create->set_theme_type_variation(SceneStringName(FlatButton));
  754. button_create->set_accessibility_name(TTRC("Create Polygon Points"));
  755. add_child(button_create);
  756. button_create->connect(SceneStringName(pressed), callable_mp(this, &AbstractPolygon2DEditor::_menu_option).bind(MODE_CREATE));
  757. button_create->set_toggle_mode(true);
  758. button_edit = memnew(Button);
  759. button_edit->set_theme_type_variation(SceneStringName(FlatButton));
  760. button_edit->set_accessibility_name(TTRC("Edit Polygon Points"));
  761. add_child(button_edit);
  762. button_edit->connect(SceneStringName(pressed), callable_mp(this, &AbstractPolygon2DEditor::_menu_option).bind(MODE_EDIT));
  763. button_edit->set_toggle_mode(true);
  764. button_delete = memnew(Button);
  765. button_delete->set_theme_type_variation(SceneStringName(FlatButton));
  766. button_delete->set_accessibility_name(TTRC("Delete Polygon Points"));
  767. add_child(button_delete);
  768. button_delete->connect(SceneStringName(pressed), callable_mp(this, &AbstractPolygon2DEditor::_menu_option).bind(MODE_DELETE));
  769. button_delete->set_toggle_mode(true);
  770. button_center = memnew(Button);
  771. button_center->set_theme_type_variation(SceneStringName(FlatButton));
  772. add_child(button_center);
  773. button_center->connect(SceneStringName(pressed), callable_mp(this, &AbstractPolygon2DEditor::_menu_option).bind(CENTER_POLY));
  774. button_center->set_visible(edit_origin_and_center);
  775. create_resource = memnew(ConfirmationDialog);
  776. add_child(create_resource);
  777. create_resource->set_ok_button_text(TTR("Create"));
  778. }
  779. void AbstractPolygon2DEditorPlugin::edit(Object *p_object) {
  780. Node *polygon_node = Object::cast_to<Node>(p_object);
  781. polygon_editor->edit(polygon_node);
  782. make_visible(polygon_node != nullptr);
  783. }
  784. bool AbstractPolygon2DEditorPlugin::handles(Object *p_object) const {
  785. return p_object->is_class(klass);
  786. }
  787. void AbstractPolygon2DEditorPlugin::make_visible(bool p_visible) {
  788. if (p_visible) {
  789. polygon_editor->show();
  790. } else {
  791. polygon_editor->hide();
  792. polygon_editor->edit(nullptr);
  793. }
  794. }
  795. AbstractPolygon2DEditorPlugin::AbstractPolygon2DEditorPlugin(AbstractPolygon2DEditor *p_polygon_editor, const String &p_class) :
  796. polygon_editor(p_polygon_editor),
  797. klass(p_class) {
  798. CanvasItemEditor::get_singleton()->add_control_to_menu_panel(polygon_editor);
  799. polygon_editor->hide();
  800. }