tile_atlas_view.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /*************************************************************************/
  2. /* tile_atlas_view.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 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. #include "tile_atlas_view.h"
  31. #include "core/input/input.h"
  32. #include "core/os/keyboard.h"
  33. #include "scene/2d/tile_map.h"
  34. #include "scene/gui/box_container.h"
  35. #include "scene/gui/label.h"
  36. #include "scene/gui/panel.h"
  37. #include "scene/gui/view_panner.h"
  38. #include "editor/editor_scale.h"
  39. #include "editor/editor_settings.h"
  40. void TileAtlasView::gui_input(const Ref<InputEvent> &p_event) {
  41. if (panner->gui_input(p_event)) {
  42. accept_event();
  43. }
  44. }
  45. void TileAtlasView::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
  46. _pan_callback(-p_scroll_vec * 32);
  47. }
  48. void TileAtlasView::_pan_callback(Vector2 p_scroll_vec) {
  49. panning += p_scroll_vec;
  50. emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
  51. _update_zoom_and_panning(true);
  52. }
  53. void TileAtlasView::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
  54. zoom_widget->set_zoom_by_increments(-p_scroll_vec.y * 2);
  55. emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
  56. _update_zoom_and_panning(true);
  57. }
  58. Size2i TileAtlasView::_compute_base_tiles_control_size() {
  59. // Update the texture.
  60. Vector2i size;
  61. Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
  62. if (texture.is_valid()) {
  63. size = texture->get_size();
  64. }
  65. return size;
  66. }
  67. Size2i TileAtlasView::_compute_alternative_tiles_control_size() {
  68. Vector2i size;
  69. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  70. Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
  71. int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(tile_id);
  72. Vector2i line_size;
  73. Size2i texture_region_size = tile_set_atlas_source->get_tile_texture_region(tile_id).size;
  74. for (int j = 1; j < alternatives_count; j++) {
  75. int alternative_id = tile_set_atlas_source->get_alternative_tile_id(tile_id, j);
  76. bool transposed = tile_set_atlas_source->get_tile_data(tile_id, alternative_id)->get_transpose();
  77. line_size.x += transposed ? texture_region_size.y : texture_region_size.x;
  78. line_size.y = MAX(line_size.y, transposed ? texture_region_size.x : texture_region_size.y);
  79. }
  80. size.x = MAX(size.x, line_size.x);
  81. size.y += line_size.y;
  82. }
  83. return size;
  84. }
  85. void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
  86. // Don't allow zoom to go below 1% or above 10000%
  87. zoom_widget->set_zoom(CLAMP(zoom_widget->get_zoom(), 0.01f, 100.f));
  88. float zoom = zoom_widget->get_zoom();
  89. // Compute the minimum sizes.
  90. Size2i base_tiles_control_size = _compute_base_tiles_control_size();
  91. base_tiles_root_control->set_custom_minimum_size(Vector2(base_tiles_control_size) * zoom);
  92. Size2i alternative_tiles_control_size = _compute_alternative_tiles_control_size();
  93. alternative_tiles_root_control->set_custom_minimum_size(Vector2(alternative_tiles_control_size) * zoom);
  94. // Set the texture for the base tiles.
  95. Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
  96. // Set the scales.
  97. if (base_tiles_control_size.x > 0 && base_tiles_control_size.y > 0) {
  98. base_tiles_drawing_root->set_scale(Vector2(zoom, zoom));
  99. } else {
  100. base_tiles_drawing_root->set_scale(Vector2(1, 1));
  101. }
  102. if (alternative_tiles_control_size.x > 0 && alternative_tiles_control_size.y > 0) {
  103. alternative_tiles_drawing_root->set_scale(Vector2(zoom, zoom));
  104. } else {
  105. alternative_tiles_drawing_root->set_scale(Vector2(1, 1));
  106. }
  107. // Update the margin container's margins.
  108. const char *constants[] = { "margin_left", "margin_top", "margin_right", "margin_bottom" };
  109. for (int i = 0; i < 4; i++) {
  110. margin_container->add_theme_constant_override(constants[i], margin_container_paddings[i] * zoom);
  111. }
  112. // Update the backgrounds.
  113. background_left->set_size(base_tiles_root_control->get_custom_minimum_size());
  114. background_right->set_size(alternative_tiles_root_control->get_custom_minimum_size());
  115. // Zoom on the position.
  116. if (p_zoom_on_mouse_pos) {
  117. // Offset the panning relative to the center of panel.
  118. Vector2 relative_mpos = get_local_mouse_position() - get_size() / 2;
  119. panning = (panning - relative_mpos) * zoom / previous_zoom + relative_mpos;
  120. } else {
  121. // Center of panel.
  122. panning = panning * zoom / previous_zoom;
  123. }
  124. button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
  125. previous_zoom = zoom;
  126. center_container->set_begin(panning - center_container->get_minimum_size() / 2);
  127. center_container->set_size(center_container->get_minimum_size());
  128. }
  129. void TileAtlasView::_zoom_widget_changed() {
  130. _update_zoom_and_panning();
  131. emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
  132. }
  133. void TileAtlasView::_center_view() {
  134. panning = Vector2();
  135. button_center_view->set_disabled(true);
  136. _update_zoom_and_panning();
  137. emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
  138. }
  139. void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
  140. base_tiles_root_control->set_tooltip_text("");
  141. Ref<InputEventMouseMotion> mm = p_event;
  142. if (mm.is_valid()) {
  143. Transform2D xform = base_tiles_drawing_root->get_transform().affine_inverse();
  144. Vector2i coords = get_atlas_tile_coords_at_pos(xform.xform(mm->get_position()));
  145. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  146. coords = tile_set_atlas_source->get_tile_at_coords(coords);
  147. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  148. base_tiles_root_control->set_tooltip_text(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: 0"), source_id, coords));
  149. }
  150. }
  151. }
  152. }
  153. void TileAtlasView::_draw_base_tiles() {
  154. Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
  155. if (texture.is_valid()) {
  156. Vector2i margins = tile_set_atlas_source->get_margins();
  157. Vector2i separation = tile_set_atlas_source->get_separation();
  158. Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
  159. Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
  160. // Draw the texture where there is no tile.
  161. for (int x = 0; x < grid_size.x; x++) {
  162. for (int y = 0; y < grid_size.y; y++) {
  163. Vector2i coords = Vector2i(x, y);
  164. if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
  165. Rect2i rect = Rect2i((texture_region_size + separation) * coords + margins, texture_region_size + separation);
  166. rect = rect.intersection(Rect2i(Vector2(), texture->get_size()));
  167. if (rect.size.x > 0 && rect.size.y > 0) {
  168. base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
  169. base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
  170. }
  171. }
  172. }
  173. }
  174. // Draw the texture around the grid.
  175. Rect2i rect;
  176. // Top.
  177. rect.position = Vector2i();
  178. rect.set_end(Vector2i(texture->get_size().x, margins.y));
  179. base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
  180. base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
  181. // Bottom
  182. int bottom_border = margins.y + (grid_size.y * (texture_region_size.y + separation.y));
  183. if (bottom_border < texture->get_size().y) {
  184. rect.position = Vector2i(0, bottom_border);
  185. rect.set_end(texture->get_size());
  186. base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
  187. base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
  188. }
  189. // Left
  190. rect.position = Vector2i(0, margins.y);
  191. rect.set_end(Vector2i(margins.x, margins.y + (grid_size.y * (texture_region_size.y + separation.y))));
  192. base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
  193. base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
  194. // Right.
  195. int right_border = margins.x + (grid_size.x * (texture_region_size.x + separation.x));
  196. if (right_border < texture->get_size().x) {
  197. rect.position = Vector2i(right_border, margins.y);
  198. rect.set_end(Vector2i(texture->get_size().x, margins.y + (grid_size.y * (texture_region_size.y + separation.y))));
  199. base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
  200. base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
  201. }
  202. // Draw actual tiles, using their properties (modulation, etc...)
  203. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  204. Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i);
  205. for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(atlas_coords); frame++) {
  206. // Update the y to max value.
  207. Rect2i base_frame_rect = tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame);
  208. Vector2i offset_pos = base_frame_rect.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0);
  209. // Draw the tile.
  210. TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0, frame);
  211. // Draw, the texture in the separation areas
  212. if (separation.x > 0) {
  213. Rect2i right_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(base_frame_rect.size.x, 0), Vector2i(separation.x, base_frame_rect.size.y));
  214. right_sep_rect = right_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
  215. if (right_sep_rect.size.x > 0 && right_sep_rect.size.y > 0) {
  216. base_tiles_draw->draw_texture_rect_region(texture, right_sep_rect, right_sep_rect);
  217. base_tiles_draw->draw_rect(right_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
  218. }
  219. }
  220. if (separation.y > 0) {
  221. Rect2i bottom_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(0, base_frame_rect.size.y), Vector2i(base_frame_rect.size.x + separation.x, separation.y));
  222. bottom_sep_rect = bottom_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
  223. if (bottom_sep_rect.size.x > 0 && bottom_sep_rect.size.y > 0) {
  224. base_tiles_draw->draw_texture_rect_region(texture, bottom_sep_rect, bottom_sep_rect);
  225. base_tiles_draw->draw_rect(bottom_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
  226. }
  227. }
  228. }
  229. }
  230. }
  231. }
  232. void TileAtlasView::_draw_base_tiles_texture_grid() {
  233. Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
  234. if (texture.is_valid()) {
  235. Vector2i margins = tile_set_atlas_source->get_margins();
  236. Vector2i separation = tile_set_atlas_source->get_separation();
  237. Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
  238. Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
  239. // Draw each tile texture region.
  240. for (int x = 0; x < grid_size.x; x++) {
  241. for (int y = 0; y < grid_size.y; y++) {
  242. Vector2i origin = margins + (Vector2i(x, y) * (texture_region_size + separation));
  243. Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
  244. if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
  245. if (base_tile_coords == Vector2i(x, y)) {
  246. // Draw existing tile.
  247. Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(base_tile_coords);
  248. Vector2 region_size = texture_region_size * size_in_atlas + separation * (size_in_atlas - Vector2i(1, 1));
  249. base_tiles_texture_grid->draw_rect(Rect2i(origin, region_size), Color(1.0, 1.0, 1.0, 0.8), false);
  250. }
  251. } else {
  252. // Draw the grid.
  253. base_tiles_texture_grid->draw_rect(Rect2i(origin, texture_region_size), Color(0.7, 0.7, 0.7, 0.1), false);
  254. }
  255. }
  256. }
  257. }
  258. }
  259. void TileAtlasView::_draw_base_tiles_shape_grid() {
  260. // Draw the shapes.
  261. Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
  262. Vector2i tile_shape_size = tile_set->get_tile_size();
  263. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  264. Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
  265. Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_effective_texture_offset(tile_id, 0);
  266. for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(tile_id); frame++) {
  267. Color color = grid_color;
  268. if (frame > 0) {
  269. color.a *= 0.3;
  270. }
  271. Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id);
  272. Transform2D tile_xform;
  273. tile_xform.set_origin(texture_region.get_center() + in_tile_base_offset);
  274. tile_xform.set_scale(tile_shape_size);
  275. tile_set->draw_tile_shape(base_tiles_shape_grid, tile_xform, color);
  276. }
  277. }
  278. }
  279. void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
  280. alternative_tiles_root_control->set_tooltip_text("");
  281. Ref<InputEventMouseMotion> mm = p_event;
  282. if (mm.is_valid()) {
  283. Transform2D xform = alternative_tiles_drawing_root->get_transform().affine_inverse();
  284. Vector3i coords3 = get_alternative_tile_at_pos(xform.xform(mm->get_position()));
  285. Vector2i coords = Vector2i(coords3.x, coords3.y);
  286. int alternative_id = coords3.z;
  287. if (coords != TileSetSource::INVALID_ATLAS_COORDS && alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
  288. alternative_tiles_root_control->set_tooltip_text(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: %d"), source_id, coords, alternative_id));
  289. }
  290. }
  291. }
  292. void TileAtlasView::_draw_alternatives() {
  293. // Draw the alternative tiles.
  294. Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
  295. if (texture.is_valid()) {
  296. Vector2 current_pos;
  297. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  298. Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i);
  299. current_pos.x = 0;
  300. int y_increment = 0;
  301. Size2i texture_region_size = tile_set_atlas_source->get_tile_texture_region(atlas_coords).size;
  302. int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(atlas_coords);
  303. for (int j = 1; j < alternatives_count; j++) {
  304. int alternative_id = tile_set_atlas_source->get_alternative_tile_id(atlas_coords, j);
  305. TileData *tile_data = tile_set_atlas_source->get_tile_data(atlas_coords, alternative_id);
  306. bool transposed = tile_data->get_transpose();
  307. // Update the y to max value.
  308. Vector2i offset_pos;
  309. if (transposed) {
  310. offset_pos = (current_pos + Vector2(texture_region_size.y, texture_region_size.x) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
  311. y_increment = MAX(y_increment, texture_region_size.x);
  312. } else {
  313. offset_pos = (current_pos + texture_region_size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
  314. y_increment = MAX(y_increment, texture_region_size.y);
  315. }
  316. // Draw the tile.
  317. TileMap::draw_tile(alternatives_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, alternative_id);
  318. // Increment the x position.
  319. current_pos.x += transposed ? texture_region_size.y : texture_region_size.x;
  320. }
  321. if (alternatives_count > 1) {
  322. current_pos.y += y_increment;
  323. }
  324. }
  325. }
  326. }
  327. void TileAtlasView::_draw_background_left() {
  328. Ref<Texture2D> texture = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
  329. background_left->draw_texture_rect(texture, Rect2(Vector2(), background_left->get_size()), true);
  330. }
  331. void TileAtlasView::_draw_background_right() {
  332. Ref<Texture2D> texture = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
  333. background_right->draw_texture_rect(texture, Rect2(Vector2(), background_right->get_size()), true);
  334. }
  335. void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
  336. ERR_FAIL_COND(!p_tile_set);
  337. ERR_FAIL_COND(!p_tile_set_atlas_source);
  338. ERR_FAIL_COND(p_source_id < 0);
  339. ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
  340. tile_set = p_tile_set;
  341. tile_set_atlas_source = p_tile_set_atlas_source;
  342. source_id = p_source_id;
  343. // Show or hide the view.
  344. bool valid = tile_set_atlas_source->get_texture().is_valid();
  345. hbox->set_visible(valid);
  346. missing_source_label->set_visible(!valid);
  347. // Update the rect cache.
  348. _update_alternative_tiles_rect_cache();
  349. // Update everything.
  350. _update_zoom_and_panning();
  351. // Update.
  352. base_tiles_draw->queue_redraw();
  353. base_tiles_texture_grid->queue_redraw();
  354. base_tiles_shape_grid->queue_redraw();
  355. alternatives_draw->queue_redraw();
  356. background_left->queue_redraw();
  357. background_right->queue_redraw();
  358. }
  359. float TileAtlasView::get_zoom() const {
  360. return zoom_widget->get_zoom();
  361. };
  362. void TileAtlasView::set_transform(float p_zoom, Vector2i p_panning) {
  363. zoom_widget->set_zoom(p_zoom);
  364. panning = p_panning;
  365. _update_zoom_and_panning();
  366. };
  367. void TileAtlasView::set_padding(Side p_side, int p_padding) {
  368. ERR_FAIL_COND(p_padding < 0);
  369. margin_container_paddings[p_side] = p_padding;
  370. }
  371. Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos) const {
  372. Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
  373. if (texture.is_valid()) {
  374. Vector2i margins = tile_set_atlas_source->get_margins();
  375. Vector2i separation = tile_set_atlas_source->get_separation();
  376. Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
  377. // Compute index in atlas
  378. Vector2 pos = p_pos - margins;
  379. Vector2i ret = (pos / (texture_region_size + separation)).floor();
  380. return ret;
  381. }
  382. return TileSetSource::INVALID_ATLAS_COORDS;
  383. }
  384. void TileAtlasView::_update_alternative_tiles_rect_cache() {
  385. alternative_tiles_rect_cache.clear();
  386. Rect2i current;
  387. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  388. Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
  389. int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(tile_id);
  390. Size2i texture_region_size = tile_set_atlas_source->get_tile_texture_region(tile_id).size;
  391. int line_height = 0;
  392. for (int j = 1; j < alternatives_count; j++) {
  393. int alternative_id = tile_set_atlas_source->get_alternative_tile_id(tile_id, j);
  394. TileData *tile_data = tile_set_atlas_source->get_tile_data(tile_id, alternative_id);
  395. bool transposed = tile_data->get_transpose();
  396. current.size = transposed ? Vector2i(texture_region_size.y, texture_region_size.x) : texture_region_size;
  397. // Update the rect.
  398. if (!alternative_tiles_rect_cache.has(tile_id)) {
  399. alternative_tiles_rect_cache[tile_id] = HashMap<int, Rect2i>();
  400. }
  401. alternative_tiles_rect_cache[tile_id][alternative_id] = current;
  402. current.position.x += transposed ? texture_region_size.y : texture_region_size.x;
  403. line_height = MAX(line_height, transposed ? texture_region_size.x : texture_region_size.y);
  404. }
  405. current.position.x = 0;
  406. current.position.y += line_height;
  407. }
  408. }
  409. Vector3i TileAtlasView::get_alternative_tile_at_pos(const Vector2 p_pos) const {
  410. for (const KeyValue<Vector2, HashMap<int, Rect2i>> &E_coords : alternative_tiles_rect_cache) {
  411. for (const KeyValue<int, Rect2i> &E_alternative : E_coords.value) {
  412. if (E_alternative.value.has_point(p_pos)) {
  413. return Vector3i(E_coords.key.x, E_coords.key.y, E_alternative.key);
  414. }
  415. }
  416. }
  417. return Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
  418. }
  419. Rect2i TileAtlasView::get_alternative_tile_rect(const Vector2i p_coords, int p_alternative_tile) {
  420. ERR_FAIL_COND_V_MSG(!alternative_tiles_rect_cache.has(p_coords), Rect2i(), vformat("No cached rect for tile coords:%s", p_coords));
  421. ERR_FAIL_COND_V_MSG(!alternative_tiles_rect_cache[p_coords].has(p_alternative_tile), Rect2i(), vformat("No cached rect for tile coords:%s alternative_id:%d", p_coords, p_alternative_tile));
  422. return alternative_tiles_rect_cache[p_coords][p_alternative_tile];
  423. }
  424. void TileAtlasView::queue_redraw() {
  425. base_tiles_draw->queue_redraw();
  426. base_tiles_texture_grid->queue_redraw();
  427. base_tiles_shape_grid->queue_redraw();
  428. alternatives_draw->queue_redraw();
  429. background_left->queue_redraw();
  430. background_right->queue_redraw();
  431. }
  432. void TileAtlasView::_notification(int p_what) {
  433. switch (p_what) {
  434. case NOTIFICATION_ENTER_TREE:
  435. case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
  436. panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
  437. } break;
  438. case NOTIFICATION_READY: {
  439. button_center_view->set_icon(get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons")));
  440. } break;
  441. }
  442. }
  443. void TileAtlasView::_bind_methods() {
  444. ADD_SIGNAL(MethodInfo("transform_changed", PropertyInfo(Variant::FLOAT, "zoom"), PropertyInfo(Variant::VECTOR2, "scroll")));
  445. }
  446. TileAtlasView::TileAtlasView() {
  447. set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
  448. Panel *panel = memnew(Panel);
  449. panel->set_clip_contents(true);
  450. panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  451. panel->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
  452. panel->set_h_size_flags(SIZE_EXPAND_FILL);
  453. panel->set_v_size_flags(SIZE_EXPAND_FILL);
  454. add_child(panel);
  455. // Scrollingsc
  456. zoom_widget = memnew(EditorZoomWidget);
  457. add_child(zoom_widget);
  458. zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
  459. zoom_widget->connect("zoom_changed", callable_mp(this, &TileAtlasView::_zoom_widget_changed).unbind(1));
  460. button_center_view = memnew(Button);
  461. button_center_view->set_icon(get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons")));
  462. button_center_view->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT, Control::PRESET_MODE_MINSIZE, 5);
  463. button_center_view->connect("pressed", callable_mp(this, &TileAtlasView::_center_view));
  464. button_center_view->set_flat(true);
  465. button_center_view->set_disabled(true);
  466. button_center_view->set_tooltip_text(TTR("Center View"));
  467. add_child(button_center_view);
  468. panner.instantiate();
  469. panner->set_callbacks(callable_mp(this, &TileAtlasView::_scroll_callback), callable_mp(this, &TileAtlasView::_pan_callback), callable_mp(this, &TileAtlasView::_zoom_callback));
  470. panner->set_enable_rmb(true);
  471. center_container = memnew(CenterContainer);
  472. center_container->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  473. center_container->set_anchors_preset(Control::PRESET_CENTER);
  474. center_container->connect("gui_input", callable_mp(this, &TileAtlasView::gui_input));
  475. center_container->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key));
  476. center_container->set_focus_mode(FOCUS_CLICK);
  477. panel->add_child(center_container);
  478. missing_source_label = memnew(Label);
  479. missing_source_label->set_text(TTR("No atlas source with a valid texture selected."));
  480. center_container->add_child(missing_source_label);
  481. margin_container = memnew(MarginContainer);
  482. margin_container->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  483. center_container->add_child(margin_container);
  484. hbox = memnew(HBoxContainer);
  485. hbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  486. hbox->add_theme_constant_override("separation", 10);
  487. hbox->hide();
  488. margin_container->add_child(hbox);
  489. VBoxContainer *left_vbox = memnew(VBoxContainer);
  490. left_vbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  491. hbox->add_child(left_vbox);
  492. VBoxContainer *right_vbox = memnew(VBoxContainer);
  493. right_vbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  494. hbox->add_child(right_vbox);
  495. // Base tiles.
  496. Label *base_tile_label = memnew(Label);
  497. base_tile_label->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  498. base_tile_label->set_text(TTR("Base Tiles"));
  499. base_tile_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
  500. left_vbox->add_child(base_tile_label);
  501. base_tiles_root_control = memnew(Control);
  502. base_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  503. base_tiles_root_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  504. base_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_base_tiles_root_control_gui_input));
  505. left_vbox->add_child(base_tiles_root_control);
  506. background_left = memnew(Control);
  507. background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  508. background_left->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT);
  509. background_left->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
  510. background_left->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_left));
  511. base_tiles_root_control->add_child(background_left);
  512. base_tiles_drawing_root = memnew(Control);
  513. base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  514. base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
  515. base_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
  516. base_tiles_root_control->add_child(base_tiles_drawing_root);
  517. base_tiles_draw = memnew(Control);
  518. base_tiles_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  519. base_tiles_draw->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
  520. base_tiles_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles));
  521. base_tiles_drawing_root->add_child(base_tiles_draw);
  522. base_tiles_texture_grid = memnew(Control);
  523. base_tiles_texture_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  524. base_tiles_texture_grid->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
  525. base_tiles_texture_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_texture_grid));
  526. base_tiles_drawing_root->add_child(base_tiles_texture_grid);
  527. base_tiles_shape_grid = memnew(Control);
  528. base_tiles_shape_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  529. base_tiles_shape_grid->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
  530. base_tiles_shape_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_shape_grid));
  531. base_tiles_drawing_root->add_child(base_tiles_shape_grid);
  532. // Alternative tiles.
  533. Label *alternative_tiles_label = memnew(Label);
  534. alternative_tiles_label->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  535. alternative_tiles_label->set_text(TTR("Alternative Tiles"));
  536. alternative_tiles_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
  537. right_vbox->add_child(alternative_tiles_label);
  538. alternative_tiles_root_control = memnew(Control);
  539. alternative_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  540. alternative_tiles_root_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  541. alternative_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_alternative_tiles_root_control_gui_input));
  542. right_vbox->add_child(alternative_tiles_root_control);
  543. background_right = memnew(Control);
  544. background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  545. background_right->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT);
  546. background_right->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
  547. background_right->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_right));
  548. alternative_tiles_root_control->add_child(background_right);
  549. alternative_tiles_drawing_root = memnew(Control);
  550. alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  551. alternative_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
  552. alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
  553. alternative_tiles_root_control->add_child(alternative_tiles_drawing_root);
  554. alternatives_draw = memnew(Control);
  555. alternatives_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  556. alternatives_draw->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
  557. alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives));
  558. alternative_tiles_drawing_root->add_child(alternatives_draw);
  559. }