1/**************************************************************************/
2/* tile_set.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
31#include "tile_set.h"
32
33#include "core/io/marshalls.h"
34#include "core/math/geometry_2d.h"
35#include "core/templates/local_vector.h"
36#include "core/templates/rb_set.h"
37#include "scene/gui/control.h"
38#include "scene/resources/convex_polygon_shape_2d.h"
39#include "scene/resources/image_texture.h"
40#include "servers/navigation_server_2d.h"
41
42/////////////////////////////// TileMapPattern //////////////////////////////////////
43
44void TileMapPattern::_set_tile_data(const Vector<int> &p_data) {
45 int c = p_data.size();
46 const int *r = p_data.ptr();
47
48 int offset = 3;
49 ERR_FAIL_COND_MSG(c % offset != 0, "Corrupted tile data.");
50
51 clear();
52
53 for (int i = 0; i < c; i += offset) {
54 const uint8_t *ptr = (const uint8_t *)&r[i];
55 uint8_t local[12];
56 for (int j = 0; j < 12; j++) {
57 local[j] = ptr[j];
58 }
59
60#ifdef BIG_ENDIAN_ENABLED
61 SWAP(local[0], local[3]);
62 SWAP(local[1], local[2]);
63 SWAP(local[4], local[7]);
64 SWAP(local[5], local[6]);
65 SWAP(local[8], local[11]);
66 SWAP(local[9], local[10]);
67#endif
68
69 int16_t x = decode_uint16(&local[0]);
70 int16_t y = decode_uint16(&local[2]);
71 uint16_t source_id = decode_uint16(&local[4]);
72 uint16_t atlas_coords_x = decode_uint16(&local[6]);
73 uint16_t atlas_coords_y = decode_uint16(&local[8]);
74 uint16_t alternative_tile = decode_uint16(&local[10]);
75 set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
76 }
77 emit_signal(SNAME("changed"));
78}
79
80Vector<int> TileMapPattern::_get_tile_data() const {
81 // Export tile data to raw format
82 Vector<int> data;
83 data.resize(pattern.size() * 3);
84 int *w = data.ptrw();
85
86 // Save in highest format
87
88 int idx = 0;
89 for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
90 uint8_t *ptr = (uint8_t *)&w[idx];
91 encode_uint16((int16_t)(E.key.x), &ptr[0]);
92 encode_uint16((int16_t)(E.key.y), &ptr[2]);
93 encode_uint16(E.value.source_id, &ptr[4]);
94 encode_uint16(E.value.coord_x, &ptr[6]);
95 encode_uint16(E.value.coord_y, &ptr[8]);
96 encode_uint16(E.value.alternative_tile, &ptr[10]);
97 idx += 3;
98 }
99
100 return data;
101}
102
103void TileMapPattern::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
104 ERR_FAIL_COND_MSG(p_coords.x < 0 || p_coords.y < 0, vformat("Cannot set cell with negative coords in a TileMapPattern. Wrong coords: %s", p_coords));
105
106 size = size.max(p_coords + Vector2i(1, 1));
107 pattern[p_coords] = TileMapCell(p_source_id, p_atlas_coords, p_alternative_tile);
108 emit_changed();
109}
110
111bool TileMapPattern::has_cell(const Vector2i &p_coords) const {
112 return pattern.has(p_coords);
113}
114
115void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) {
116 ERR_FAIL_COND(!pattern.has(p_coords));
117
118 pattern.erase(p_coords);
119 if (p_update_size) {
120 size = Size2i();
121 for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
122 size = size.max(E.key + Vector2i(1, 1));
123 }
124 }
125 emit_changed();
126}
127
128int TileMapPattern::get_cell_source_id(const Vector2i &p_coords) const {
129 ERR_FAIL_COND_V(!pattern.has(p_coords), TileSet::INVALID_SOURCE);
130
131 return pattern[p_coords].source_id;
132}
133
134Vector2i TileMapPattern::get_cell_atlas_coords(const Vector2i &p_coords) const {
135 ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_ATLAS_COORDS);
136
137 return pattern[p_coords].get_atlas_coords();
138}
139
140int TileMapPattern::get_cell_alternative_tile(const Vector2i &p_coords) const {
141 ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_TILE_ALTERNATIVE);
142
143 return pattern[p_coords].alternative_tile;
144}
145
146TypedArray<Vector2i> TileMapPattern::get_used_cells() const {
147 // Returns the cells used in the tilemap.
148 TypedArray<Vector2i> a;
149 a.resize(pattern.size());
150 int i = 0;
151 for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
152 Vector2i p(E.key.x, E.key.y);
153 a[i++] = p;
154 }
155
156 return a;
157}
158
159Size2i TileMapPattern::get_size() const {
160 return size;
161}
162
163void TileMapPattern::set_size(const Size2i &p_size) {
164 for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
165 Vector2i coords = E.key;
166 if (p_size.x <= coords.x || p_size.y <= coords.y) {
167 ERR_FAIL_MSG(vformat("Cannot set pattern size to %s, it contains a tile at %s. Size can only be increased.", p_size, coords));
168 };
169 }
170
171 size = p_size;
172 emit_changed();
173}
174
175bool TileMapPattern::is_empty() const {
176 return pattern.is_empty();
177};
178
179void TileMapPattern::clear() {
180 size = Size2i();
181 pattern.clear();
182 emit_changed();
183};
184
185bool TileMapPattern::_set(const StringName &p_name, const Variant &p_value) {
186 if (p_name == "tile_data") {
187 if (p_value.is_array()) {
188 _set_tile_data(p_value);
189 return true;
190 }
191 return false;
192 }
193 return false;
194}
195
196bool TileMapPattern::_get(const StringName &p_name, Variant &r_ret) const {
197 if (p_name == "tile_data") {
198 r_ret = _get_tile_data();
199 return true;
200 }
201 return false;
202}
203
204void TileMapPattern::_get_property_list(List<PropertyInfo> *p_list) const {
205 p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
206}
207
208void TileMapPattern::_bind_methods() {
209 ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
210 ClassDB::bind_method(D_METHOD("has_cell", "coords"), &TileMapPattern::has_cell);
211 ClassDB::bind_method(D_METHOD("remove_cell", "coords", "update_size"), &TileMapPattern::remove_cell);
212 ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMapPattern::get_cell_source_id);
213 ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMapPattern::get_cell_atlas_coords);
214 ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMapPattern::get_cell_alternative_tile);
215
216 ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMapPattern::get_used_cells);
217 ClassDB::bind_method(D_METHOD("get_size"), &TileMapPattern::get_size);
218 ClassDB::bind_method(D_METHOD("set_size", "size"), &TileMapPattern::set_size);
219 ClassDB::bind_method(D_METHOD("is_empty"), &TileMapPattern::is_empty);
220}
221
222/////////////////////////////// TileSet //////////////////////////////////////
223
224bool TileSet::TerrainsPattern::is_valid() const {
225 return valid;
226}
227
228bool TileSet::TerrainsPattern::is_erase_pattern() const {
229 return not_empty_terrains_count == 0;
230}
231
232bool TileSet::TerrainsPattern::operator<(const TerrainsPattern &p_terrains_pattern) const {
233 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
234 if (is_valid_bit[i] != p_terrains_pattern.is_valid_bit[i]) {
235 return is_valid_bit[i] < p_terrains_pattern.is_valid_bit[i];
236 }
237 }
238 if (terrain != p_terrains_pattern.terrain) {
239 return terrain < p_terrains_pattern.terrain;
240 }
241 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
242 if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
243 return bits[i] < p_terrains_pattern.bits[i];
244 }
245 }
246 return false;
247}
248
249bool TileSet::TerrainsPattern::operator==(const TerrainsPattern &p_terrains_pattern) const {
250 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
251 if (is_valid_bit[i] != p_terrains_pattern.is_valid_bit[i]) {
252 return false;
253 }
254 if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
255 return false;
256 }
257 }
258 if (terrain != p_terrains_pattern.terrain) {
259 return false;
260 }
261 return true;
262}
263
264void TileSet::TerrainsPattern::set_terrain(int p_terrain) {
265 ERR_FAIL_COND(p_terrain < -1);
266
267 terrain = p_terrain;
268}
269
270int TileSet::TerrainsPattern::get_terrain() const {
271 return terrain;
272}
273
274void TileSet::TerrainsPattern::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
275 ERR_FAIL_COND(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX);
276 ERR_FAIL_COND(!is_valid_bit[p_peering_bit]);
277 ERR_FAIL_COND(p_terrain < -1);
278
279 // Update the "is_erase_pattern" status.
280 if (p_terrain >= 0 && bits[p_peering_bit] < 0) {
281 not_empty_terrains_count++;
282 } else if (p_terrain < 0 && bits[p_peering_bit] >= 0) {
283 not_empty_terrains_count--;
284 }
285
286 bits[p_peering_bit] = p_terrain;
287}
288
289int TileSet::TerrainsPattern::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
290 ERR_FAIL_COND_V(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX, -1);
291 ERR_FAIL_COND_V(!is_valid_bit[p_peering_bit], -1);
292 return bits[p_peering_bit];
293}
294
295void TileSet::TerrainsPattern::from_array(Array p_terrains) {
296 set_terrain(p_terrains[0]);
297 int in_array_index = 1;
298 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
299 if (is_valid_bit[i]) {
300 ERR_FAIL_INDEX(in_array_index, p_terrains.size());
301 set_terrain_peering_bit(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
302 in_array_index++;
303 }
304 }
305}
306
307Array TileSet::TerrainsPattern::as_array() const {
308 Array output;
309 output.push_back(get_terrain());
310 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
311 if (is_valid_bit[i]) {
312 output.push_back(bits[i]);
313 }
314 }
315 return output;
316}
317
318TileSet::TerrainsPattern::TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set) {
319 ERR_FAIL_COND(p_terrain_set < 0);
320 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
321 is_valid_bit[i] = (p_tile_set->is_valid_terrain_peering_bit(p_terrain_set, TileSet::CellNeighbor(i)));
322 bits[i] = -1;
323 }
324 valid = true;
325}
326
327const int TileSet::INVALID_SOURCE = -1;
328
329const char *TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[] = {
330 "right_side",
331 "right_corner",
332 "bottom_right_side",
333 "bottom_right_corner",
334 "bottom_side",
335 "bottom_corner",
336 "bottom_left_side",
337 "bottom_left_corner",
338 "left_side",
339 "left_corner",
340 "top_left_side",
341 "top_left_corner",
342 "top_side",
343 "top_corner",
344 "top_right_side",
345 "top_right_corner"
346};
347
348// -- Shape and layout --
349void TileSet::set_tile_shape(TileSet::TileShape p_shape) {
350 tile_shape = p_shape;
351
352 for (KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
353 E_source.value->notify_tile_data_properties_should_change();
354 }
355
356 terrain_bits_meshes_dirty = true;
357 tile_meshes_dirty = true;
358 notify_property_list_changed();
359 emit_changed();
360}
361TileSet::TileShape TileSet::get_tile_shape() const {
362 return tile_shape;
363}
364
365void TileSet::set_tile_layout(TileSet::TileLayout p_layout) {
366 tile_layout = p_layout;
367 emit_changed();
368}
369TileSet::TileLayout TileSet::get_tile_layout() const {
370 return tile_layout;
371}
372
373void TileSet::set_tile_offset_axis(TileSet::TileOffsetAxis p_alignment) {
374 tile_offset_axis = p_alignment;
375
376 for (KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
377 E_source.value->notify_tile_data_properties_should_change();
378 }
379
380 terrain_bits_meshes_dirty = true;
381 tile_meshes_dirty = true;
382 emit_changed();
383}
384TileSet::TileOffsetAxis TileSet::get_tile_offset_axis() const {
385 return tile_offset_axis;
386}
387
388void TileSet::set_tile_size(Size2i p_size) {
389 ERR_FAIL_COND(p_size.x < 1 || p_size.y < 1);
390 tile_size = p_size;
391 terrain_bits_meshes_dirty = true;
392 tile_meshes_dirty = true;
393 emit_changed();
394}
395Size2i TileSet::get_tile_size() const {
396 return tile_size;
397}
398
399int TileSet::get_next_source_id() const {
400 return next_source_id;
401}
402
403void TileSet::_update_terrains_cache() {
404 if (terrains_cache_dirty) {
405 // Organizes tiles into structures.
406 per_terrain_pattern_tiles.resize(terrain_sets.size());
407 for (RBMap<TileSet::TerrainsPattern, RBSet<TileMapCell>> &tiles : per_terrain_pattern_tiles) {
408 tiles.clear();
409 }
410
411 for (const KeyValue<int, Ref<TileSetSource>> &kv : sources) {
412 Ref<TileSetSource> source = kv.value;
413 Ref<TileSetAtlasSource> atlas_source = source;
414 if (atlas_source.is_valid()) {
415 for (int tile_index = 0; tile_index < source->get_tiles_count(); tile_index++) {
416 Vector2i tile_id = source->get_tile_id(tile_index);
417 for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) {
418 int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index);
419
420 // Executed for each tile_data.
421 TileData *tile_data = atlas_source->get_tile_data(tile_id, alternative_id);
422 int terrain_set = tile_data->get_terrain_set();
423 if (terrain_set >= 0) {
424 TileMapCell cell;
425 cell.source_id = kv.key;
426 cell.set_atlas_coords(tile_id);
427 cell.alternative_tile = alternative_id;
428
429 TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
430
431 // Main terrain.
432 if (terrains_pattern.get_terrain() >= 0) {
433 per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
434 }
435
436 // Terrain bits.
437 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
438 CellNeighbor bit = CellNeighbor(i);
439 if (is_valid_terrain_peering_bit(terrain_set, bit)) {
440 int terrain = terrains_pattern.get_terrain_peering_bit(bit);
441 if (terrain >= 0) {
442 per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
443 }
444 }
445 }
446 }
447 }
448 }
449 }
450 }
451
452 // Add the empty cell in the possible patterns and cells.
453 for (int i = 0; i < terrain_sets.size(); i++) {
454 TileSet::TerrainsPattern empty_pattern(this, i);
455
456 TileMapCell empty_cell;
457 empty_cell.source_id = TileSet::INVALID_SOURCE;
458 empty_cell.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
459 empty_cell.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
460 per_terrain_pattern_tiles[i][empty_pattern].insert(empty_cell);
461 }
462 terrains_cache_dirty = false;
463 }
464}
465
466void TileSet::_compute_next_source_id() {
467 while (sources.has(next_source_id)) {
468 next_source_id = (next_source_id + 1) % 1073741824; // 2 ** 30
469 };
470}
471
472// Sources management
473int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source_id_override) {
474 ERR_FAIL_COND_V(!p_tile_set_source.is_valid(), TileSet::INVALID_SOURCE);
475 ERR_FAIL_COND_V_MSG(p_atlas_source_id_override >= 0 && (sources.has(p_atlas_source_id_override)), TileSet::INVALID_SOURCE, vformat("Cannot create TileSet atlas source. Another atlas source exists with id %d.", p_atlas_source_id_override));
476 ERR_FAIL_COND_V_MSG(p_atlas_source_id_override < 0 && p_atlas_source_id_override != TileSet::INVALID_SOURCE, TileSet::INVALID_SOURCE, vformat("Provided source ID %d is not valid. Negative source IDs are not allowed.", p_atlas_source_id_override));
477
478 int new_source_id = p_atlas_source_id_override >= 0 ? p_atlas_source_id_override : next_source_id;
479 sources[new_source_id] = p_tile_set_source;
480 source_ids.push_back(new_source_id);
481 source_ids.sort();
482 TileSet *old_tileset = p_tile_set_source->get_tile_set();
483 if (old_tileset != this && old_tileset != nullptr) {
484 // If the source is already in a TileSet (might happen when duplicating), remove it from the other TileSet.
485 old_tileset->remove_source_ptr(p_tile_set_source.ptr());
486 }
487 p_tile_set_source->set_tile_set(this);
488 _compute_next_source_id();
489
490 sources[new_source_id]->connect_changed(callable_mp(this, &TileSet::_source_changed));
491
492 terrains_cache_dirty = true;
493 emit_changed();
494
495 return new_source_id;
496}
497
498void TileSet::remove_source(int p_source_id) {
499 ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot remove TileSet atlas source. No tileset atlas source with id %d.", p_source_id));
500
501 sources[p_source_id]->disconnect_changed(callable_mp(this, &TileSet::_source_changed));
502
503 sources[p_source_id]->set_tile_set(nullptr);
504 sources.erase(p_source_id);
505 source_ids.erase(p_source_id);
506 source_ids.sort();
507
508 terrains_cache_dirty = true;
509 emit_changed();
510}
511
512void TileSet::remove_source_ptr(TileSetSource *p_tile_set_source) {
513 for (const KeyValue<int, Ref<TileSetSource>> &kv : sources) {
514 if (kv.value.ptr() == p_tile_set_source) {
515 remove_source(kv.key);
516 return;
517 }
518 }
519 ERR_FAIL_MSG(vformat("Attempting to remove source from a tileset, but the tileset doesn't have it: %s", p_tile_set_source));
520}
521
522void TileSet::set_source_id(int p_source_id, int p_new_source_id) {
523 ERR_FAIL_COND(p_new_source_id < 0);
524 ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot change TileSet atlas source ID. No tileset atlas source with id %d.", p_source_id));
525 if (p_source_id == p_new_source_id) {
526 return;
527 }
528
529 ERR_FAIL_COND_MSG(sources.has(p_new_source_id), vformat("Cannot change TileSet atlas source ID. Another atlas source exists with id %d.", p_new_source_id));
530
531 sources[p_new_source_id] = sources[p_source_id];
532 sources.erase(p_source_id);
533
534 source_ids.erase(p_source_id);
535 source_ids.push_back(p_new_source_id);
536 source_ids.sort();
537
538 _compute_next_source_id();
539
540 terrains_cache_dirty = true;
541 emit_changed();
542}
543
544bool TileSet::has_source(int p_source_id) const {
545 return sources.has(p_source_id);
546}
547
548Ref<TileSetSource> TileSet::get_source(int p_source_id) const {
549 ERR_FAIL_COND_V_MSG(!sources.has(p_source_id), nullptr, vformat("No TileSet atlas source with id %d.", p_source_id));
550
551 return sources[p_source_id];
552}
553
554int TileSet::get_source_count() const {
555 return source_ids.size();
556}
557
558int TileSet::get_source_id(int p_index) const {
559 ERR_FAIL_INDEX_V(p_index, source_ids.size(), TileSet::INVALID_SOURCE);
560 return source_ids[p_index];
561}
562
563// Rendering
564void TileSet::set_uv_clipping(bool p_uv_clipping) {
565 if (uv_clipping == p_uv_clipping) {
566 return;
567 }
568 uv_clipping = p_uv_clipping;
569 emit_changed();
570}
571
572bool TileSet::is_uv_clipping() const {
573 return uv_clipping;
574};
575
576int TileSet::get_occlusion_layers_count() const {
577 return occlusion_layers.size();
578};
579
580void TileSet::add_occlusion_layer(int p_index) {
581 if (p_index < 0) {
582 p_index = occlusion_layers.size();
583 }
584 ERR_FAIL_INDEX(p_index, occlusion_layers.size() + 1);
585 occlusion_layers.insert(p_index, OcclusionLayer());
586
587 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
588 source.value->add_occlusion_layer(p_index);
589 }
590
591 notify_property_list_changed();
592 emit_changed();
593}
594
595void TileSet::move_occlusion_layer(int p_from_index, int p_to_pos) {
596 ERR_FAIL_INDEX(p_from_index, occlusion_layers.size());
597 ERR_FAIL_INDEX(p_to_pos, occlusion_layers.size() + 1);
598 occlusion_layers.insert(p_to_pos, occlusion_layers[p_from_index]);
599 occlusion_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
600 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
601 source.value->move_occlusion_layer(p_from_index, p_to_pos);
602 }
603 notify_property_list_changed();
604 emit_changed();
605}
606
607void TileSet::remove_occlusion_layer(int p_index) {
608 ERR_FAIL_INDEX(p_index, occlusion_layers.size());
609 occlusion_layers.remove_at(p_index);
610 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
611 source.value->remove_occlusion_layer(p_index);
612 }
613 notify_property_list_changed();
614 emit_changed();
615}
616
617void TileSet::set_occlusion_layer_light_mask(int p_layer_index, int p_light_mask) {
618 ERR_FAIL_INDEX(p_layer_index, occlusion_layers.size());
619 occlusion_layers.write[p_layer_index].light_mask = p_light_mask;
620 emit_changed();
621}
622
623int TileSet::get_occlusion_layer_light_mask(int p_layer_index) const {
624 ERR_FAIL_INDEX_V(p_layer_index, occlusion_layers.size(), 0);
625 return occlusion_layers[p_layer_index].light_mask;
626}
627
628void TileSet::set_occlusion_layer_sdf_collision(int p_layer_index, bool p_sdf_collision) {
629 ERR_FAIL_INDEX(p_layer_index, occlusion_layers.size());
630 occlusion_layers.write[p_layer_index].sdf_collision = p_sdf_collision;
631 emit_changed();
632}
633
634bool TileSet::get_occlusion_layer_sdf_collision(int p_layer_index) const {
635 ERR_FAIL_INDEX_V(p_layer_index, occlusion_layers.size(), false);
636 return occlusion_layers[p_layer_index].sdf_collision;
637}
638
639int TileSet::get_physics_layers_count() const {
640 return physics_layers.size();
641}
642
643void TileSet::add_physics_layer(int p_index) {
644 if (p_index < 0) {
645 p_index = physics_layers.size();
646 }
647 ERR_FAIL_INDEX(p_index, physics_layers.size() + 1);
648 physics_layers.insert(p_index, PhysicsLayer());
649
650 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
651 source.value->add_physics_layer(p_index);
652 }
653
654 notify_property_list_changed();
655 emit_changed();
656}
657
658void TileSet::move_physics_layer(int p_from_index, int p_to_pos) {
659 ERR_FAIL_INDEX(p_from_index, physics_layers.size());
660 ERR_FAIL_INDEX(p_to_pos, physics_layers.size() + 1);
661 physics_layers.insert(p_to_pos, physics_layers[p_from_index]);
662 physics_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
663 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
664 source.value->move_physics_layer(p_from_index, p_to_pos);
665 }
666 notify_property_list_changed();
667 emit_changed();
668}
669
670void TileSet::remove_physics_layer(int p_index) {
671 ERR_FAIL_INDEX(p_index, physics_layers.size());
672 physics_layers.remove_at(p_index);
673 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
674 source.value->remove_physics_layer(p_index);
675 }
676 notify_property_list_changed();
677 emit_changed();
678}
679
680void TileSet::set_physics_layer_collision_layer(int p_layer_index, uint32_t p_layer) {
681 ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
682 physics_layers.write[p_layer_index].collision_layer = p_layer;
683 emit_changed();
684}
685
686uint32_t TileSet::get_physics_layer_collision_layer(int p_layer_index) const {
687 ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), 0);
688 return physics_layers[p_layer_index].collision_layer;
689}
690
691void TileSet::set_physics_layer_collision_mask(int p_layer_index, uint32_t p_mask) {
692 ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
693 physics_layers.write[p_layer_index].collision_mask = p_mask;
694 emit_changed();
695}
696
697uint32_t TileSet::get_physics_layer_collision_mask(int p_layer_index) const {
698 ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), 0);
699 return physics_layers[p_layer_index].collision_mask;
700}
701
702void TileSet::set_physics_layer_physics_material(int p_layer_index, Ref<PhysicsMaterial> p_physics_material) {
703 ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
704 physics_layers.write[p_layer_index].physics_material = p_physics_material;
705}
706
707Ref<PhysicsMaterial> TileSet::get_physics_layer_physics_material(int p_layer_index) const {
708 ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), Ref<PhysicsMaterial>());
709 return physics_layers[p_layer_index].physics_material;
710}
711
712// Terrains
713int TileSet::get_terrain_sets_count() const {
714 return terrain_sets.size();
715}
716
717void TileSet::add_terrain_set(int p_index) {
718 if (p_index < 0) {
719 p_index = terrain_sets.size();
720 }
721 ERR_FAIL_INDEX(p_index, terrain_sets.size() + 1);
722 terrain_sets.insert(p_index, TerrainSet());
723
724 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
725 source.value->add_terrain_set(p_index);
726 }
727
728 notify_property_list_changed();
729 terrains_cache_dirty = true;
730 emit_changed();
731}
732
733void TileSet::move_terrain_set(int p_from_index, int p_to_pos) {
734 ERR_FAIL_INDEX(p_from_index, terrain_sets.size());
735 ERR_FAIL_INDEX(p_to_pos, terrain_sets.size() + 1);
736 terrain_sets.insert(p_to_pos, terrain_sets[p_from_index]);
737 terrain_sets.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
738 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
739 source.value->move_terrain_set(p_from_index, p_to_pos);
740 }
741 notify_property_list_changed();
742 terrains_cache_dirty = true;
743 emit_changed();
744}
745
746void TileSet::remove_terrain_set(int p_index) {
747 ERR_FAIL_INDEX(p_index, terrain_sets.size());
748 terrain_sets.remove_at(p_index);
749 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
750 source.value->remove_terrain_set(p_index);
751 }
752 notify_property_list_changed();
753 terrains_cache_dirty = true;
754 emit_changed();
755}
756
757void TileSet::set_terrain_set_mode(int p_terrain_set, TerrainMode p_terrain_mode) {
758 ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
759 terrain_sets.write[p_terrain_set].mode = p_terrain_mode;
760 for (KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
761 E_source.value->notify_tile_data_properties_should_change();
762 }
763
764 notify_property_list_changed();
765 terrains_cache_dirty = true;
766 emit_changed();
767}
768
769TileSet::TerrainMode TileSet::get_terrain_set_mode(int p_terrain_set) const {
770 ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES);
771 return terrain_sets[p_terrain_set].mode;
772}
773
774int TileSet::get_terrains_count(int p_terrain_set) const {
775 ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), -1);
776 return terrain_sets[p_terrain_set].terrains.size();
777}
778
779void TileSet::add_terrain(int p_terrain_set, int p_index) {
780 ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
781 Vector<Terrain> &terrains = terrain_sets.write[p_terrain_set].terrains;
782 if (p_index < 0) {
783 p_index = terrains.size();
784 }
785 ERR_FAIL_INDEX(p_index, terrains.size() + 1);
786 terrains.insert(p_index, Terrain());
787
788 // Default name and color
789 float hue_rotate = (terrains.size() % 16) / 16.0;
790 Color c;
791 c.set_hsv(Math::fmod(float(hue_rotate), float(1.0)), 0.5, 0.5);
792 terrains.write[p_index].color = c;
793 terrains.write[p_index].name = String(vformat("Terrain %d", p_index));
794
795 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
796 source.value->add_terrain(p_terrain_set, p_index);
797 }
798
799 notify_property_list_changed();
800 terrains_cache_dirty = true;
801 emit_changed();
802}
803
804void TileSet::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
805 ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
806 Vector<Terrain> &terrains = terrain_sets.write[p_terrain_set].terrains;
807
808 ERR_FAIL_INDEX(p_from_index, terrains.size());
809 ERR_FAIL_INDEX(p_to_pos, terrains.size() + 1);
810 terrains.insert(p_to_pos, terrains[p_from_index]);
811 terrains.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
812 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
813 source.value->move_terrain(p_terrain_set, p_from_index, p_to_pos);
814 }
815 notify_property_list_changed();
816 terrains_cache_dirty = true;
817 emit_changed();
818}
819
820void TileSet::remove_terrain(int p_terrain_set, int p_index) {
821 ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
822 Vector<Terrain> &terrains = terrain_sets.write[p_terrain_set].terrains;
823
824 ERR_FAIL_INDEX(p_index, terrains.size());
825 terrains.remove_at(p_index);
826 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
827 source.value->remove_terrain(p_terrain_set, p_index);
828 }
829 notify_property_list_changed();
830 terrains_cache_dirty = true;
831 emit_changed();
832}
833
834void TileSet::set_terrain_name(int p_terrain_set, int p_terrain_index, String p_name) {
835 ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
836 ERR_FAIL_INDEX(p_terrain_index, terrain_sets[p_terrain_set].terrains.size());
837 terrain_sets.write[p_terrain_set].terrains.write[p_terrain_index].name = p_name;
838 emit_changed();
839}
840
841String TileSet::get_terrain_name(int p_terrain_set, int p_terrain_index) const {
842 ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), String());
843 ERR_FAIL_INDEX_V(p_terrain_index, terrain_sets[p_terrain_set].terrains.size(), String());
844 return terrain_sets[p_terrain_set].terrains[p_terrain_index].name;
845}
846
847void TileSet::set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color) {
848 ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
849 ERR_FAIL_INDEX(p_terrain_index, terrain_sets[p_terrain_set].terrains.size());
850 if (p_color.a != 1.0) {
851 WARN_PRINT("Terrain color should have alpha == 1.0");
852 p_color.a = 1.0;
853 }
854 terrain_sets.write[p_terrain_set].terrains.write[p_terrain_index].color = p_color;
855 emit_changed();
856}
857
858Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const {
859 ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), Color());
860 ERR_FAIL_INDEX_V(p_terrain_index, terrain_sets[p_terrain_set].terrains.size(), Color());
861 return terrain_sets[p_terrain_set].terrains[p_terrain_index].color;
862}
863
864bool TileSet::is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
865 if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
866 if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
867 if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
868 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
869 p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
870 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_SIDE) {
871 return true;
872 }
873 }
874 if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
875 if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
876 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
877 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
878 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
879 return true;
880 }
881 }
882 } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
883 if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
884 if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
885 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
886 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
887 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
888 return true;
889 }
890 }
891 if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
892 if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
893 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
894 p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
895 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
896 return true;
897 }
898 }
899 } else {
900 if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
901 if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
902 if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
903 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
904 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
905 p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
906 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
907 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
908 return true;
909 }
910 }
911 if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
912 if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
913 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
914 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
915 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
916 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_CORNER ||
917 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
918 return true;
919 }
920 }
921 } else {
922 if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
923 if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
924 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
925 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
926 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
927 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
928 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
929 return true;
930 }
931 }
932 if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
933 if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
934 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
935 p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
936 p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
937 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
938 p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
939 return true;
940 }
941 }
942 }
943 }
944 return false;
945}
946
947bool TileSet::is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
948 if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) {
949 return false;
950 }
951
952 TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
953 return is_valid_terrain_peering_bit_for_mode(terrain_mode, p_peering_bit);
954}
955
956// Navigation
957int TileSet::get_navigation_layers_count() const {
958 return navigation_layers.size();
959}
960
961void TileSet::add_navigation_layer(int p_index) {
962 if (p_index < 0) {
963 p_index = navigation_layers.size();
964 }
965 ERR_FAIL_INDEX(p_index, navigation_layers.size() + 1);
966 navigation_layers.insert(p_index, NavigationLayer());
967
968 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
969 source.value->add_navigation_layer(p_index);
970 }
971
972 notify_property_list_changed();
973 emit_changed();
974}
975
976void TileSet::move_navigation_layer(int p_from_index, int p_to_pos) {
977 ERR_FAIL_INDEX(p_from_index, navigation_layers.size());
978 ERR_FAIL_INDEX(p_to_pos, navigation_layers.size() + 1);
979 navigation_layers.insert(p_to_pos, navigation_layers[p_from_index]);
980 navigation_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
981 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
982 source.value->move_navigation_layer(p_from_index, p_to_pos);
983 }
984 notify_property_list_changed();
985 emit_changed();
986}
987
988void TileSet::remove_navigation_layer(int p_index) {
989 ERR_FAIL_INDEX(p_index, navigation_layers.size());
990 navigation_layers.remove_at(p_index);
991 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
992 source.value->remove_navigation_layer(p_index);
993 }
994 notify_property_list_changed();
995 emit_changed();
996}
997
998void TileSet::set_navigation_layer_layers(int p_layer_index, uint32_t p_layers) {
999 ERR_FAIL_INDEX(p_layer_index, navigation_layers.size());
1000 navigation_layers.write[p_layer_index].layers = p_layers;
1001 emit_changed();
1002}
1003
1004uint32_t TileSet::get_navigation_layer_layers(int p_layer_index) const {
1005 ERR_FAIL_INDEX_V(p_layer_index, navigation_layers.size(), 0);
1006 return navigation_layers[p_layer_index].layers;
1007}
1008
1009void TileSet::set_navigation_layer_layer_value(int p_layer_index, int p_layer_number, bool p_value) {
1010 ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
1011 ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
1012
1013 uint32_t _navigation_layers = get_navigation_layer_layers(p_layer_index);
1014
1015 if (p_value) {
1016 _navigation_layers |= 1 << (p_layer_number - 1);
1017 } else {
1018 _navigation_layers &= ~(1 << (p_layer_number - 1));
1019 }
1020
1021 set_navigation_layer_layers(p_layer_index, _navigation_layers);
1022}
1023
1024bool TileSet::get_navigation_layer_layer_value(int p_layer_index, int p_layer_number) const {
1025 ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
1026 ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
1027
1028 return get_navigation_layer_layers(p_layer_index) & (1 << (p_layer_number - 1));
1029}
1030
1031// Custom data.
1032int TileSet::get_custom_data_layers_count() const {
1033 return custom_data_layers.size();
1034}
1035
1036void TileSet::add_custom_data_layer(int p_index) {
1037 if (p_index < 0) {
1038 p_index = custom_data_layers.size();
1039 }
1040 ERR_FAIL_INDEX(p_index, custom_data_layers.size() + 1);
1041 custom_data_layers.insert(p_index, CustomDataLayer());
1042
1043 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
1044 source.value->add_custom_data_layer(p_index);
1045 }
1046
1047 notify_property_list_changed();
1048 emit_changed();
1049}
1050
1051void TileSet::move_custom_data_layer(int p_from_index, int p_to_pos) {
1052 ERR_FAIL_INDEX(p_from_index, custom_data_layers.size());
1053 ERR_FAIL_INDEX(p_to_pos, custom_data_layers.size() + 1);
1054 custom_data_layers.insert(p_to_pos, custom_data_layers[p_from_index]);
1055 custom_data_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
1056 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
1057 source.value->move_custom_data_layer(p_from_index, p_to_pos);
1058 }
1059 notify_property_list_changed();
1060 emit_changed();
1061}
1062
1063void TileSet::remove_custom_data_layer(int p_index) {
1064 ERR_FAIL_INDEX(p_index, custom_data_layers.size());
1065 custom_data_layers.remove_at(p_index);
1066
1067 String to_erase;
1068 for (KeyValue<String, int> &E : custom_data_layers_by_name) {
1069 if (E.value == p_index) {
1070 to_erase = E.key;
1071 } else if (E.value > p_index) {
1072 E.value--;
1073 }
1074 }
1075 custom_data_layers_by_name.erase(to_erase);
1076
1077 for (KeyValue<int, Ref<TileSetSource>> source : sources) {
1078 source.value->remove_custom_data_layer(p_index);
1079 }
1080 notify_property_list_changed();
1081 emit_changed();
1082}
1083
1084int TileSet::get_custom_data_layer_by_name(String p_value) const {
1085 if (custom_data_layers_by_name.has(p_value)) {
1086 return custom_data_layers_by_name[p_value];
1087 } else {
1088 return -1;
1089 }
1090}
1091
1092void TileSet::set_custom_data_layer_name(int p_layer_id, String p_value) {
1093 ERR_FAIL_INDEX(p_layer_id, custom_data_layers.size());
1094
1095 // Exit if another property has the same name.
1096 if (!p_value.is_empty()) {
1097 for (int other_layer_id = 0; other_layer_id < get_custom_data_layers_count(); other_layer_id++) {
1098 if (other_layer_id != p_layer_id && get_custom_data_layer_name(other_layer_id) == p_value) {
1099 ERR_FAIL_MSG(vformat("There is already a custom property named %s", p_value));
1100 }
1101 }
1102 }
1103
1104 if (p_value.is_empty() && custom_data_layers_by_name.has(p_value)) {
1105 custom_data_layers_by_name.erase(p_value);
1106 } else {
1107 custom_data_layers_by_name[p_value] = p_layer_id;
1108 }
1109
1110 custom_data_layers.write[p_layer_id].name = p_value;
1111 emit_changed();
1112}
1113
1114String TileSet::get_custom_data_layer_name(int p_layer_id) const {
1115 ERR_FAIL_INDEX_V(p_layer_id, custom_data_layers.size(), "");
1116 return custom_data_layers[p_layer_id].name;
1117}
1118
1119void TileSet::set_custom_data_layer_type(int p_layer_id, Variant::Type p_value) {
1120 ERR_FAIL_INDEX(p_layer_id, custom_data_layers.size());
1121 custom_data_layers.write[p_layer_id].type = p_value;
1122
1123 for (KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
1124 E_source.value->notify_tile_data_properties_should_change();
1125 }
1126
1127 emit_changed();
1128}
1129
1130Variant::Type TileSet::get_custom_data_layer_type(int p_layer_id) const {
1131 ERR_FAIL_INDEX_V(p_layer_id, custom_data_layers.size(), Variant::NIL);
1132 return custom_data_layers[p_layer_id].type;
1133}
1134
1135void TileSet::set_source_level_tile_proxy(int p_source_from, int p_source_to) {
1136 ERR_FAIL_COND(p_source_from == TileSet::INVALID_SOURCE || p_source_to == TileSet::INVALID_SOURCE);
1137
1138 source_level_proxies[p_source_from] = p_source_to;
1139
1140 emit_changed();
1141}
1142
1143int TileSet::get_source_level_tile_proxy(int p_source_from) {
1144 ERR_FAIL_COND_V(!source_level_proxies.has(p_source_from), TileSet::INVALID_SOURCE);
1145
1146 return source_level_proxies[p_source_from];
1147}
1148
1149bool TileSet::has_source_level_tile_proxy(int p_source_from) {
1150 return source_level_proxies.has(p_source_from);
1151}
1152
1153void TileSet::remove_source_level_tile_proxy(int p_source_from) {
1154 ERR_FAIL_COND(!source_level_proxies.has(p_source_from));
1155
1156 source_level_proxies.erase(p_source_from);
1157
1158 emit_changed();
1159}
1160
1161void TileSet::set_coords_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_source_to, Vector2i p_coords_to) {
1162 ERR_FAIL_COND(p_source_from == TileSet::INVALID_SOURCE || p_source_to == TileSet::INVALID_SOURCE);
1163 ERR_FAIL_COND(p_coords_from == TileSetSource::INVALID_ATLAS_COORDS || p_coords_to == TileSetSource::INVALID_ATLAS_COORDS);
1164
1165 Array from;
1166 from.push_back(p_source_from);
1167 from.push_back(p_coords_from);
1168
1169 Array to;
1170 to.push_back(p_source_to);
1171 to.push_back(p_coords_to);
1172
1173 coords_level_proxies[from] = to;
1174
1175 emit_changed();
1176}
1177
1178Array TileSet::get_coords_level_tile_proxy(int p_source_from, Vector2i p_coords_from) {
1179 Array from;
1180 from.push_back(p_source_from);
1181 from.push_back(p_coords_from);
1182
1183 ERR_FAIL_COND_V(!coords_level_proxies.has(from), Array());
1184
1185 return coords_level_proxies[from];
1186}
1187
1188bool TileSet::has_coords_level_tile_proxy(int p_source_from, Vector2i p_coords_from) {
1189 Array from;
1190 from.push_back(p_source_from);
1191 from.push_back(p_coords_from);
1192
1193 return coords_level_proxies.has(from);
1194}
1195
1196void TileSet::remove_coords_level_tile_proxy(int p_source_from, Vector2i p_coords_from) {
1197 Array from;
1198 from.push_back(p_source_from);
1199 from.push_back(p_coords_from);
1200
1201 ERR_FAIL_COND(!coords_level_proxies.has(from));
1202
1203 coords_level_proxies.erase(from);
1204
1205 emit_changed();
1206}
1207
1208void TileSet::set_alternative_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from, int p_source_to, Vector2i p_coords_to, int p_alternative_to) {
1209 ERR_FAIL_COND(p_source_from == TileSet::INVALID_SOURCE || p_source_to == TileSet::INVALID_SOURCE);
1210 ERR_FAIL_COND(p_coords_from == TileSetSource::INVALID_ATLAS_COORDS || p_coords_to == TileSetSource::INVALID_ATLAS_COORDS);
1211
1212 Array from;
1213 from.push_back(p_source_from);
1214 from.push_back(p_coords_from);
1215 from.push_back(p_alternative_from);
1216
1217 Array to;
1218 to.push_back(p_source_to);
1219 to.push_back(p_coords_to);
1220 to.push_back(p_alternative_to);
1221
1222 alternative_level_proxies[from] = to;
1223
1224 emit_changed();
1225}
1226
1227Array TileSet::get_alternative_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from) {
1228 Array from;
1229 from.push_back(p_source_from);
1230 from.push_back(p_coords_from);
1231 from.push_back(p_alternative_from);
1232
1233 ERR_FAIL_COND_V(!alternative_level_proxies.has(from), Array());
1234
1235 return alternative_level_proxies[from];
1236}
1237
1238bool TileSet::has_alternative_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from) {
1239 Array from;
1240 from.push_back(p_source_from);
1241 from.push_back(p_coords_from);
1242 from.push_back(p_alternative_from);
1243
1244 return alternative_level_proxies.has(from);
1245}
1246
1247void TileSet::remove_alternative_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from) {
1248 Array from;
1249 from.push_back(p_source_from);
1250 from.push_back(p_coords_from);
1251 from.push_back(p_alternative_from);
1252
1253 ERR_FAIL_COND(!alternative_level_proxies.has(from));
1254
1255 alternative_level_proxies.erase(from);
1256
1257 emit_changed();
1258}
1259
1260Array TileSet::get_source_level_tile_proxies() const {
1261 Array output;
1262 for (const KeyValue<int, int> &E : source_level_proxies) {
1263 Array proxy;
1264 proxy.push_back(E.key);
1265 proxy.push_back(E.value);
1266 output.push_back(proxy);
1267 }
1268 return output;
1269}
1270
1271Array TileSet::get_coords_level_tile_proxies() const {
1272 Array output;
1273 for (const KeyValue<Array, Array> &E : coords_level_proxies) {
1274 Array proxy;
1275 proxy.append_array(E.key);
1276 proxy.append_array(E.value);
1277 output.push_back(proxy);
1278 }
1279 return output;
1280}
1281
1282Array TileSet::get_alternative_level_tile_proxies() const {
1283 Array output;
1284 for (const KeyValue<Array, Array> &E : alternative_level_proxies) {
1285 Array proxy;
1286 proxy.append_array(E.key);
1287 proxy.append_array(E.value);
1288 output.push_back(proxy);
1289 }
1290 return output;
1291}
1292
1293Array TileSet::map_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from) const {
1294 Array from;
1295 from.push_back(p_source_from);
1296 from.push_back(p_coords_from);
1297 from.push_back(p_alternative_from);
1298
1299 // Check if the tile is valid, and if so, don't map the tile and return the input.
1300 if (has_source(p_source_from)) {
1301 Ref<TileSetSource> source = get_source(p_source_from);
1302 if (source->has_tile(p_coords_from) && source->has_alternative_tile(p_coords_from, p_alternative_from)) {
1303 return from;
1304 }
1305 }
1306
1307 // Source, coords and alternative match.
1308 if (alternative_level_proxies.has(from)) {
1309 return alternative_level_proxies[from].duplicate();
1310 }
1311
1312 // Source and coords match.
1313 from.pop_back();
1314 if (coords_level_proxies.has(from)) {
1315 Array output = coords_level_proxies[from].duplicate();
1316 output.push_back(p_alternative_from);
1317 return output;
1318 }
1319
1320 // Source matches.
1321 if (source_level_proxies.has(p_source_from)) {
1322 Array output;
1323 output.push_back(source_level_proxies[p_source_from]);
1324 output.push_back(p_coords_from);
1325 output.push_back(p_alternative_from);
1326 return output;
1327 }
1328
1329 Array output;
1330 output.push_back(p_source_from);
1331 output.push_back(p_coords_from);
1332 output.push_back(p_alternative_from);
1333 return output;
1334}
1335
1336void TileSet::cleanup_invalid_tile_proxies() {
1337 // Source level.
1338 Vector<int> source_to_remove;
1339 for (const KeyValue<int, int> &E : source_level_proxies) {
1340 if (has_source(E.key)) {
1341 source_to_remove.push_back(E.key);
1342 }
1343 }
1344 for (int i = 0; i < source_to_remove.size(); i++) {
1345 remove_source_level_tile_proxy(source_to_remove[i]);
1346 }
1347
1348 // Coords level.
1349 Vector<Array> coords_to_remove;
1350 for (const KeyValue<Array, Array> &E : coords_level_proxies) {
1351 Array a = E.key;
1352 if (has_source(a[0]) && get_source(a[0])->has_tile(a[1])) {
1353 coords_to_remove.push_back(a);
1354 }
1355 }
1356 for (int i = 0; i < coords_to_remove.size(); i++) {
1357 Array a = coords_to_remove[i];
1358 remove_coords_level_tile_proxy(a[0], a[1]);
1359 }
1360
1361 // Alternative level.
1362 Vector<Array> alternative_to_remove;
1363 for (const KeyValue<Array, Array> &E : alternative_level_proxies) {
1364 Array a = E.key;
1365 if (has_source(a[0]) && get_source(a[0])->has_tile(a[1]) && get_source(a[0])->has_alternative_tile(a[1], a[2])) {
1366 alternative_to_remove.push_back(a);
1367 }
1368 }
1369 for (int i = 0; i < alternative_to_remove.size(); i++) {
1370 Array a = alternative_to_remove[i];
1371 remove_alternative_level_tile_proxy(a[0], a[1], a[2]);
1372 }
1373}
1374
1375void TileSet::clear_tile_proxies() {
1376 source_level_proxies.clear();
1377 coords_level_proxies.clear();
1378 alternative_level_proxies.clear();
1379
1380 emit_changed();
1381}
1382
1383int TileSet::add_pattern(Ref<TileMapPattern> p_pattern, int p_index) {
1384 ERR_FAIL_COND_V(!p_pattern.is_valid(), -1);
1385 ERR_FAIL_COND_V_MSG(p_pattern->is_empty(), -1, "Cannot add an empty pattern to the TileSet.");
1386 for (const Ref<TileMapPattern> &pattern : patterns) {
1387 ERR_FAIL_COND_V_MSG(pattern == p_pattern, -1, "TileSet has already this pattern.");
1388 }
1389 ERR_FAIL_COND_V(p_index > (int)patterns.size(), -1);
1390 if (p_index < 0) {
1391 p_index = patterns.size();
1392 }
1393 patterns.insert(p_index, p_pattern);
1394 emit_changed();
1395 return p_index;
1396}
1397
1398Ref<TileMapPattern> TileSet::get_pattern(int p_index) {
1399 ERR_FAIL_INDEX_V(p_index, (int)patterns.size(), Ref<TileMapPattern>());
1400 return patterns[p_index];
1401}
1402
1403void TileSet::remove_pattern(int p_index) {
1404 ERR_FAIL_INDEX(p_index, (int)patterns.size());
1405 patterns.remove_at(p_index);
1406 emit_changed();
1407}
1408
1409int TileSet::get_patterns_count() {
1410 return patterns.size();
1411}
1412
1413RBSet<TileSet::TerrainsPattern> TileSet::get_terrains_pattern_set(int p_terrain_set) {
1414 ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), RBSet<TileSet::TerrainsPattern>());
1415 _update_terrains_cache();
1416
1417 RBSet<TileSet::TerrainsPattern> output;
1418 for (KeyValue<TileSet::TerrainsPattern, RBSet<TileMapCell>> kv : per_terrain_pattern_tiles[p_terrain_set]) {
1419 output.insert(kv.key);
1420 }
1421 return output;
1422}
1423
1424RBSet<TileMapCell> TileSet::get_tiles_for_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern) {
1425 ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), RBSet<TileMapCell>());
1426 _update_terrains_cache();
1427 return per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
1428}
1429
1430TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, TileSet::TerrainsPattern p_terrain_tile_pattern) {
1431 ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), TileMapCell());
1432 _update_terrains_cache();
1433
1434 // Count the sum of probabilities.
1435 double sum = 0.0;
1436 RBSet<TileMapCell> set = per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
1437 for (const TileMapCell &E : set) {
1438 if (E.source_id >= 0) {
1439 Ref<TileSetSource> source = sources[E.source_id];
1440 Ref<TileSetAtlasSource> atlas_source = source;
1441 if (atlas_source.is_valid()) {
1442 TileData *tile_data = atlas_source->get_tile_data(E.get_atlas_coords(), E.alternative_tile);
1443 sum += tile_data->get_probability();
1444 } else {
1445 sum += 1.0;
1446 }
1447 } else {
1448 sum += 1.0;
1449 }
1450 }
1451
1452 // Generate a random number.
1453 double count = 0.0;
1454 double picked = Math::random(0.0, sum);
1455
1456 // Pick the tile.
1457 for (const TileMapCell &E : set) {
1458 if (E.source_id >= 0) {
1459 Ref<TileSetSource> source = sources[E.source_id];
1460
1461 Ref<TileSetAtlasSource> atlas_source = source;
1462 if (atlas_source.is_valid()) {
1463 TileData *tile_data = atlas_source->get_tile_data(E.get_atlas_coords(), E.alternative_tile);
1464 count += tile_data->get_probability();
1465 } else {
1466 count += 1.0;
1467 }
1468 } else {
1469 count += 1.0;
1470 }
1471
1472 if (count >= picked) {
1473 return E;
1474 }
1475 }
1476
1477 ERR_FAIL_V(TileMapCell());
1478}
1479
1480Vector<Vector2> TileSet::get_tile_shape_polygon() {
1481 Vector<Vector2> points;
1482 if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
1483 points.push_back(Vector2(-0.5, -0.5));
1484 points.push_back(Vector2(0.5, -0.5));
1485 points.push_back(Vector2(0.5, 0.5));
1486 points.push_back(Vector2(-0.5, 0.5));
1487 } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1488 points.push_back(Vector2(0.0, -0.5));
1489 points.push_back(Vector2(-0.5, 0.0));
1490 points.push_back(Vector2(0.0, 0.5));
1491 points.push_back(Vector2(0.5, 0.0));
1492 } else {
1493 float overlap = 0.0;
1494 switch (tile_shape) {
1495 case TileSet::TILE_SHAPE_HEXAGON:
1496 overlap = 0.25;
1497 break;
1498 case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
1499 overlap = 0.0;
1500 break;
1501 default:
1502 break;
1503 }
1504
1505 points.push_back(Vector2(0.0, -0.5));
1506 points.push_back(Vector2(-0.5, overlap - 0.5));
1507 points.push_back(Vector2(-0.5, 0.5 - overlap));
1508 points.push_back(Vector2(0.0, 0.5));
1509 points.push_back(Vector2(0.5, 0.5 - overlap));
1510 points.push_back(Vector2(0.5, overlap - 0.5));
1511
1512 if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
1513 for (int i = 0; i < points.size(); i++) {
1514 points.write[i] = Vector2(points[i].y, points[i].x);
1515 }
1516 }
1517 }
1518 return points;
1519}
1520
1521void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled, Ref<Texture2D> p_texture) {
1522 if (tile_meshes_dirty) {
1523 Vector<Vector2> shape = get_tile_shape_polygon();
1524 Vector<Vector2> uvs;
1525 uvs.resize(shape.size());
1526 for (int i = 0; i < shape.size(); i++) {
1527 uvs.write[i] = shape[i] + Vector2(0.5, 0.5);
1528 }
1529
1530 Vector<Color> colors;
1531 colors.resize(shape.size());
1532 colors.fill(Color(1.0, 1.0, 1.0, 1.0));
1533
1534 // Filled mesh.
1535 tile_filled_mesh->clear_surfaces();
1536 Array a;
1537 a.resize(Mesh::ARRAY_MAX);
1538 a[Mesh::ARRAY_VERTEX] = shape;
1539 a[Mesh::ARRAY_TEX_UV] = uvs;
1540 a[Mesh::ARRAY_COLOR] = colors;
1541 a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(shape);
1542 tile_filled_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
1543
1544 // Lines mesh.
1545 tile_lines_mesh->clear_surfaces();
1546 a.clear();
1547 a.resize(Mesh::ARRAY_MAX);
1548 // Add the first point again when drawing lines.
1549 shape.push_back(shape[0]);
1550 colors.push_back(colors[0]);
1551 a[Mesh::ARRAY_VERTEX] = shape;
1552 a[Mesh::ARRAY_COLOR] = colors;
1553 tile_lines_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINE_STRIP, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
1554
1555 tile_meshes_dirty = false;
1556 }
1557
1558 if (p_filled) {
1559 p_canvas_item->draw_mesh(tile_filled_mesh, p_texture, p_transform, p_color);
1560 } else {
1561 p_canvas_item->draw_mesh(tile_lines_mesh, Ref<Texture2D>(), p_transform, p_color);
1562 }
1563}
1564
1565Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) {
1566 if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
1567 return _get_square_terrain_polygon(tile_size);
1568 } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1569 return _get_isometric_terrain_polygon(tile_size);
1570 } else {
1571 float overlap = 0.0;
1572 switch (tile_shape) {
1573 case TileSet::TILE_SHAPE_HEXAGON:
1574 overlap = 0.25;
1575 break;
1576 case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
1577 overlap = 0.0;
1578 break;
1579 default:
1580 break;
1581 }
1582 return _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
1583 }
1584}
1585
1586Vector<Point2> TileSet::get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
1587 ERR_FAIL_COND_V(p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count(), Vector<Point2>());
1588
1589 TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
1590
1591 if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
1592 if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
1593 return _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
1594 } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
1595 return _get_square_corner_terrain_peering_bit_polygon(tile_size, p_bit);
1596 } else { // TileData::TERRAIN_MODE_MATCH_SIDES
1597 return _get_square_side_terrain_peering_bit_polygon(tile_size, p_bit);
1598 }
1599 } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1600 if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
1601 return _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
1602 } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
1603 return _get_isometric_corner_terrain_peering_bit_polygon(tile_size, p_bit);
1604 } else { // TileData::TERRAIN_MODE_MATCH_SIDES
1605 return _get_isometric_side_terrain_peering_bit_polygon(tile_size, p_bit);
1606 }
1607 } else {
1608 float overlap = 0.0;
1609 switch (tile_shape) {
1610 case TileSet::TILE_SHAPE_HEXAGON:
1611 overlap = 0.25;
1612 break;
1613 case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
1614 overlap = 0.0;
1615 break;
1616 default:
1617 break;
1618 }
1619 if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
1620 return _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
1621 } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
1622 return _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
1623 } else { // TileData::TERRAIN_MODE_MATCH_SIDES
1624 return _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
1625 }
1626 }
1627}
1628
1629#define TERRAIN_ALPHA 0.6
1630
1631void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data) {
1632 ERR_FAIL_NULL(p_tile_data);
1633
1634 if (terrain_bits_meshes_dirty) {
1635 // Recompute the meshes.
1636 terrain_peering_bits_meshes.clear();
1637
1638 for (int terrain_mode_index = 0; terrain_mode_index < 3; terrain_mode_index++) {
1639 TerrainMode terrain_mode = TerrainMode(terrain_mode_index);
1640
1641 // Center terrain
1642 Vector<Vector2> polygon;
1643 if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
1644 polygon = _get_square_terrain_polygon(tile_size);
1645 } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1646 polygon = _get_isometric_terrain_polygon(tile_size);
1647 } else {
1648 float overlap = 0.0;
1649 switch (tile_shape) {
1650 case TileSet::TILE_SHAPE_HEXAGON:
1651 overlap = 0.25;
1652 break;
1653 case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
1654 overlap = 0.0;
1655 break;
1656 default:
1657 break;
1658 }
1659 polygon = _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
1660 }
1661 {
1662 Ref<ArrayMesh> mesh;
1663 mesh.instantiate();
1664 Vector<Vector2> uvs;
1665 uvs.resize(polygon.size());
1666 Vector<Color> colors;
1667 colors.resize(polygon.size());
1668 colors.fill(Color(1.0, 1.0, 1.0, 1.0));
1669 Array a;
1670 a.resize(Mesh::ARRAY_MAX);
1671 a[Mesh::ARRAY_VERTEX] = polygon;
1672 a[Mesh::ARRAY_TEX_UV] = uvs;
1673 a[Mesh::ARRAY_COLOR] = colors;
1674 a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
1675 mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
1676 terrain_meshes[terrain_mode] = mesh;
1677 }
1678 // Peering bits
1679 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
1680 CellNeighbor bit = CellNeighbor(i);
1681
1682 if (is_valid_terrain_peering_bit_for_mode(terrain_mode, bit)) {
1683 if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
1684 if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
1685 polygon = _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
1686 } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
1687 polygon = _get_square_corner_terrain_peering_bit_polygon(tile_size, bit);
1688 } else { // TileData::TERRAIN_MODE_MATCH_SIDES
1689 polygon = _get_square_side_terrain_peering_bit_polygon(tile_size, bit);
1690 }
1691 } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1692 if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
1693 polygon = _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
1694 } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
1695 polygon = _get_isometric_corner_terrain_peering_bit_polygon(tile_size, bit);
1696 } else { // TileData::TERRAIN_MODE_MATCH_SIDES
1697 polygon = _get_isometric_side_terrain_peering_bit_polygon(tile_size, bit);
1698 }
1699 } else {
1700 float overlap = 0.0;
1701 switch (tile_shape) {
1702 case TileSet::TILE_SHAPE_HEXAGON:
1703 overlap = 0.25;
1704 break;
1705 case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
1706 overlap = 0.0;
1707 break;
1708 default:
1709 break;
1710 }
1711 if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
1712 polygon = _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
1713 } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
1714 polygon = _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
1715 } else { // TileData::TERRAIN_MODE_MATCH_SIDES
1716 polygon = _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
1717 }
1718 }
1719 {
1720 Ref<ArrayMesh> mesh;
1721 mesh.instantiate();
1722 Vector<Vector2> uvs;
1723 uvs.resize(polygon.size());
1724 Vector<Color> colors;
1725 colors.resize(polygon.size());
1726 colors.fill(Color(1.0, 1.0, 1.0, 1.0));
1727 Array a;
1728 a.resize(Mesh::ARRAY_MAX);
1729 a[Mesh::ARRAY_VERTEX] = polygon;
1730 a[Mesh::ARRAY_TEX_UV] = uvs;
1731 a[Mesh::ARRAY_COLOR] = colors;
1732 a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
1733 mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
1734 terrain_peering_bits_meshes[terrain_mode][bit] = mesh;
1735 }
1736 }
1737 }
1738 }
1739 terrain_bits_meshes_dirty = false;
1740 }
1741
1742 int terrain_set = p_tile_data->get_terrain_set();
1743 if (terrain_set < 0) {
1744 return;
1745 }
1746 TileSet::TerrainMode terrain_mode = get_terrain_set_mode(terrain_set);
1747
1748 RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
1749 int terrain_id = p_tile_data->get_terrain();
1750 if (terrain_id >= 0) {
1751 Color color = get_terrain_color(terrain_set, terrain_id);
1752 color.a = TERRAIN_ALPHA;
1753 p_canvas_item->draw_mesh(terrain_meshes[terrain_mode], Ref<Texture2D>(), Transform2D(), color);
1754 }
1755
1756 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
1757 CellNeighbor bit = CellNeighbor(i);
1758 if (is_valid_terrain_peering_bit(terrain_set, bit)) {
1759 terrain_id = p_tile_data->get_terrain_peering_bit(bit);
1760 if (terrain_id >= 0) {
1761 Color color = get_terrain_color(terrain_set, terrain_id);
1762 color.a = TERRAIN_ALPHA;
1763 p_canvas_item->draw_mesh(terrain_peering_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
1764 }
1765 }
1766 }
1767 RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
1768}
1769
1770Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
1771 // Counts the number of matching terrain tiles and find the best matching icon.
1772 struct Count {
1773 int count = 0;
1774 float probability = 0.0;
1775 Ref<Texture2D> texture;
1776 Rect2i region;
1777 };
1778 Vector<Vector<Ref<Texture2D>>> output;
1779 LocalVector<LocalVector<Count>> counts;
1780 output.resize(get_terrain_sets_count());
1781 counts.resize(get_terrain_sets_count());
1782 for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) {
1783 output.write[terrain_set].resize(get_terrains_count(terrain_set));
1784 counts[terrain_set].resize(get_terrains_count(terrain_set));
1785 }
1786
1787 for (int source_index = 0; source_index < get_source_count(); source_index++) {
1788 int source_id = get_source_id(source_index);
1789 Ref<TileSetSource> source = get_source(source_id);
1790
1791 Ref<TileSetAtlasSource> atlas_source = source;
1792 if (atlas_source.is_valid()) {
1793 for (int tile_index = 0; tile_index < source->get_tiles_count(); tile_index++) {
1794 Vector2i tile_id = source->get_tile_id(tile_index);
1795 for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) {
1796 int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index);
1797
1798 TileData *tile_data = atlas_source->get_tile_data(tile_id, alternative_id);
1799 int terrain_set = tile_data->get_terrain_set();
1800 if (terrain_set >= 0) {
1801 ERR_FAIL_INDEX_V(terrain_set, get_terrain_sets_count(), Vector<Vector<Ref<Texture2D>>>());
1802
1803 LocalVector<int> bit_counts;
1804 bit_counts.resize(get_terrains_count(terrain_set));
1805 for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
1806 bit_counts[terrain] = 0;
1807 }
1808 if (tile_data->get_terrain() >= 0) {
1809 bit_counts[tile_data->get_terrain()] += 10;
1810 }
1811 for (int terrain_bit = 0; terrain_bit < TileSet::CELL_NEIGHBOR_MAX; terrain_bit++) {
1812 TileSet::CellNeighbor cell_neighbor = TileSet::CellNeighbor(terrain_bit);
1813 if (is_valid_terrain_peering_bit(terrain_set, cell_neighbor)) {
1814 int terrain = tile_data->get_terrain_peering_bit(cell_neighbor);
1815 if (terrain >= 0) {
1816 if (terrain >= (int)bit_counts.size()) {
1817 WARN_PRINT(vformat("Invalid terrain peering bit: %d", terrain));
1818 } else {
1819 bit_counts[terrain] += 1;
1820 }
1821 }
1822 }
1823 }
1824
1825 for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
1826 if ((bit_counts[terrain] > counts[terrain_set][terrain].count) || (bit_counts[terrain] == counts[terrain_set][terrain].count && tile_data->get_probability() > counts[terrain_set][terrain].probability)) {
1827 counts[terrain_set][terrain].count = bit_counts[terrain];
1828 counts[terrain_set][terrain].probability = tile_data->get_probability();
1829 counts[terrain_set][terrain].texture = atlas_source->get_texture();
1830 counts[terrain_set][terrain].region = atlas_source->get_tile_texture_region(tile_id);
1831 }
1832 }
1833 }
1834 }
1835 }
1836 }
1837 }
1838
1839 // Generate the icons.
1840 for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) {
1841 for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
1842 Ref<Image> image;
1843 image.instantiate();
1844 if (counts[terrain_set][terrain].count > 0) {
1845 // Get the best tile.
1846 Ref<Texture2D> texture = counts[terrain_set][terrain].texture;
1847 Rect2i region = counts[terrain_set][terrain].region;
1848 image->initialize_data(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
1849 image->blit_rect(texture->get_image(), region, Point2i());
1850 image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST);
1851 } else {
1852 image->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
1853 image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
1854 }
1855 Ref<ImageTexture> icon = ImageTexture::create_from_image(image);
1856 icon->set_size_override(p_size);
1857 output.write[terrain_set].write[terrain] = icon;
1858 }
1859 }
1860 return output;
1861}
1862
1863void TileSet::_source_changed() {
1864 terrains_cache_dirty = true;
1865 emit_changed();
1866}
1867
1868Vector<Point2> TileSet::_get_square_terrain_polygon(Vector2i p_size) {
1869 Rect2 rect(-Vector2(p_size) / 6.0, Vector2(p_size) / 3.0);
1870 return {
1871 rect.position,
1872 Vector2(rect.get_end().x, rect.position.y),
1873 rect.get_end(),
1874 Vector2(rect.position.x, rect.get_end().y)
1875 };
1876}
1877
1878Vector<Point2> TileSet::_get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
1879 Rect2 bit_rect;
1880 bit_rect.size = Vector2(p_size) / 3;
1881 switch (p_bit) {
1882 case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
1883 bit_rect.position = Vector2(1, -1);
1884 break;
1885 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
1886 bit_rect.position = Vector2(1, 1);
1887 break;
1888 case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
1889 bit_rect.position = Vector2(-1, 1);
1890 break;
1891 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
1892 bit_rect.position = Vector2(-3, 1);
1893 break;
1894 case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
1895 bit_rect.position = Vector2(-3, -1);
1896 break;
1897 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
1898 bit_rect.position = Vector2(-3, -3);
1899 break;
1900 case TileSet::CELL_NEIGHBOR_TOP_SIDE:
1901 bit_rect.position = Vector2(-1, -3);
1902 break;
1903 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
1904 bit_rect.position = Vector2(1, -3);
1905 break;
1906 default:
1907 break;
1908 }
1909 bit_rect.position *= Vector2(p_size) / 6.0;
1910
1911 Vector<Vector2> polygon = {
1912 bit_rect.position,
1913 Vector2(bit_rect.get_end().x, bit_rect.position.y),
1914 bit_rect.get_end(),
1915 Vector2(bit_rect.position.x, bit_rect.get_end().y)
1916 };
1917
1918 return polygon;
1919}
1920
1921Vector<Point2> TileSet::_get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
1922 Vector2 unit = Vector2(p_size) / 6.0;
1923 Vector<Vector2> polygon;
1924 switch (p_bit) {
1925 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
1926 polygon.push_back(Vector2(0, 3) * unit);
1927 polygon.push_back(Vector2(3, 3) * unit);
1928 polygon.push_back(Vector2(3, 0) * unit);
1929 polygon.push_back(Vector2(1, 0) * unit);
1930 polygon.push_back(Vector2(1, 1) * unit);
1931 polygon.push_back(Vector2(0, 1) * unit);
1932 break;
1933 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
1934 polygon.push_back(Vector2(0, 3) * unit);
1935 polygon.push_back(Vector2(-3, 3) * unit);
1936 polygon.push_back(Vector2(-3, 0) * unit);
1937 polygon.push_back(Vector2(-1, 0) * unit);
1938 polygon.push_back(Vector2(-1, 1) * unit);
1939 polygon.push_back(Vector2(0, 1) * unit);
1940 break;
1941 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
1942 polygon.push_back(Vector2(0, -3) * unit);
1943 polygon.push_back(Vector2(-3, -3) * unit);
1944 polygon.push_back(Vector2(-3, 0) * unit);
1945 polygon.push_back(Vector2(-1, 0) * unit);
1946 polygon.push_back(Vector2(-1, -1) * unit);
1947 polygon.push_back(Vector2(0, -1) * unit);
1948 break;
1949 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
1950 polygon.push_back(Vector2(0, -3) * unit);
1951 polygon.push_back(Vector2(3, -3) * unit);
1952 polygon.push_back(Vector2(3, 0) * unit);
1953 polygon.push_back(Vector2(1, 0) * unit);
1954 polygon.push_back(Vector2(1, -1) * unit);
1955 polygon.push_back(Vector2(0, -1) * unit);
1956 break;
1957 default:
1958 break;
1959 }
1960 return polygon;
1961}
1962
1963Vector<Point2> TileSet::_get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
1964 Vector2 unit = Vector2(p_size) / 6.0;
1965 Vector<Vector2> polygon;
1966 switch (p_bit) {
1967 case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
1968 polygon.push_back(Vector2(1, -1) * unit);
1969 polygon.push_back(Vector2(3, -3) * unit);
1970 polygon.push_back(Vector2(3, 3) * unit);
1971 polygon.push_back(Vector2(1, 1) * unit);
1972 break;
1973 case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
1974 polygon.push_back(Vector2(-1, 1) * unit);
1975 polygon.push_back(Vector2(-3, 3) * unit);
1976 polygon.push_back(Vector2(3, 3) * unit);
1977 polygon.push_back(Vector2(1, 1) * unit);
1978 break;
1979 case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
1980 polygon.push_back(Vector2(-1, -1) * unit);
1981 polygon.push_back(Vector2(-3, -3) * unit);
1982 polygon.push_back(Vector2(-3, 3) * unit);
1983 polygon.push_back(Vector2(-1, 1) * unit);
1984 break;
1985 case TileSet::CELL_NEIGHBOR_TOP_SIDE:
1986 polygon.push_back(Vector2(-1, -1) * unit);
1987 polygon.push_back(Vector2(-3, -3) * unit);
1988 polygon.push_back(Vector2(3, -3) * unit);
1989 polygon.push_back(Vector2(1, -1) * unit);
1990 break;
1991 default:
1992 break;
1993 }
1994 return polygon;
1995}
1996
1997Vector<Point2> TileSet::_get_isometric_terrain_polygon(Vector2i p_size) {
1998 Vector2 unit = Vector2(p_size) / 6.0;
1999 return {
2000 Vector2(1, 0) * unit,
2001 Vector2(0, 1) * unit,
2002 Vector2(-1, 0) * unit,
2003 Vector2(0, -1) * unit,
2004 };
2005}
2006
2007Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2008 Vector2 unit = Vector2(p_size) / 6.0;
2009 Vector<Vector2> polygon;
2010 switch (p_bit) {
2011 case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2012 polygon.push_back(Vector2(1, 0) * unit);
2013 polygon.push_back(Vector2(2, -1) * unit);
2014 polygon.push_back(Vector2(3, 0) * unit);
2015 polygon.push_back(Vector2(2, 1) * unit);
2016 break;
2017 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2018 polygon.push_back(Vector2(0, 1) * unit);
2019 polygon.push_back(Vector2(1, 2) * unit);
2020 polygon.push_back(Vector2(2, 1) * unit);
2021 polygon.push_back(Vector2(1, 0) * unit);
2022 break;
2023 case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2024 polygon.push_back(Vector2(0, 1) * unit);
2025 polygon.push_back(Vector2(-1, 2) * unit);
2026 polygon.push_back(Vector2(0, 3) * unit);
2027 polygon.push_back(Vector2(1, 2) * unit);
2028 break;
2029 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2030 polygon.push_back(Vector2(0, 1) * unit);
2031 polygon.push_back(Vector2(-1, 2) * unit);
2032 polygon.push_back(Vector2(-2, 1) * unit);
2033 polygon.push_back(Vector2(-1, 0) * unit);
2034 break;
2035 case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2036 polygon.push_back(Vector2(-1, 0) * unit);
2037 polygon.push_back(Vector2(-2, -1) * unit);
2038 polygon.push_back(Vector2(-3, 0) * unit);
2039 polygon.push_back(Vector2(-2, 1) * unit);
2040 break;
2041 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2042 polygon.push_back(Vector2(0, -1) * unit);
2043 polygon.push_back(Vector2(-1, -2) * unit);
2044 polygon.push_back(Vector2(-2, -1) * unit);
2045 polygon.push_back(Vector2(-1, 0) * unit);
2046 break;
2047 case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2048 polygon.push_back(Vector2(0, -1) * unit);
2049 polygon.push_back(Vector2(-1, -2) * unit);
2050 polygon.push_back(Vector2(0, -3) * unit);
2051 polygon.push_back(Vector2(1, -2) * unit);
2052 break;
2053 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2054 polygon.push_back(Vector2(0, -1) * unit);
2055 polygon.push_back(Vector2(1, -2) * unit);
2056 polygon.push_back(Vector2(2, -1) * unit);
2057 polygon.push_back(Vector2(1, 0) * unit);
2058 break;
2059 default:
2060 break;
2061 }
2062 return polygon;
2063}
2064
2065Vector<Point2> TileSet::_get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2066 Vector2 unit = Vector2(p_size) / 6.0;
2067 Vector<Vector2> polygon;
2068 switch (p_bit) {
2069 case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2070 polygon.push_back(Vector2(0.5, -0.5) * unit);
2071 polygon.push_back(Vector2(1.5, -1.5) * unit);
2072 polygon.push_back(Vector2(3, 0) * unit);
2073 polygon.push_back(Vector2(1.5, 1.5) * unit);
2074 polygon.push_back(Vector2(0.5, 0.5) * unit);
2075 polygon.push_back(Vector2(1, 0) * unit);
2076 break;
2077 case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2078 polygon.push_back(Vector2(-0.5, 0.5) * unit);
2079 polygon.push_back(Vector2(-1.5, 1.5) * unit);
2080 polygon.push_back(Vector2(0, 3) * unit);
2081 polygon.push_back(Vector2(1.5, 1.5) * unit);
2082 polygon.push_back(Vector2(0.5, 0.5) * unit);
2083 polygon.push_back(Vector2(0, 1) * unit);
2084 break;
2085 case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2086 polygon.push_back(Vector2(-0.5, -0.5) * unit);
2087 polygon.push_back(Vector2(-1.5, -1.5) * unit);
2088 polygon.push_back(Vector2(-3, 0) * unit);
2089 polygon.push_back(Vector2(-1.5, 1.5) * unit);
2090 polygon.push_back(Vector2(-0.5, 0.5) * unit);
2091 polygon.push_back(Vector2(-1, 0) * unit);
2092 break;
2093 case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2094 polygon.push_back(Vector2(-0.5, -0.5) * unit);
2095 polygon.push_back(Vector2(-1.5, -1.5) * unit);
2096 polygon.push_back(Vector2(0, -3) * unit);
2097 polygon.push_back(Vector2(1.5, -1.5) * unit);
2098 polygon.push_back(Vector2(0.5, -0.5) * unit);
2099 polygon.push_back(Vector2(0, -1) * unit);
2100 break;
2101 default:
2102 break;
2103 }
2104 return polygon;
2105}
2106
2107Vector<Point2> TileSet::_get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2108 Vector2 unit = Vector2(p_size) / 6.0;
2109 Vector<Vector2> polygon;
2110 switch (p_bit) {
2111 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2112 polygon.push_back(Vector2(1, 0) * unit);
2113 polygon.push_back(Vector2(3, 0) * unit);
2114 polygon.push_back(Vector2(0, 3) * unit);
2115 polygon.push_back(Vector2(0, 1) * unit);
2116 break;
2117 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2118 polygon.push_back(Vector2(-1, 0) * unit);
2119 polygon.push_back(Vector2(-3, 0) * unit);
2120 polygon.push_back(Vector2(0, 3) * unit);
2121 polygon.push_back(Vector2(0, 1) * unit);
2122 break;
2123 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2124 polygon.push_back(Vector2(-1, 0) * unit);
2125 polygon.push_back(Vector2(-3, 0) * unit);
2126 polygon.push_back(Vector2(0, -3) * unit);
2127 polygon.push_back(Vector2(0, -1) * unit);
2128 break;
2129 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2130 polygon.push_back(Vector2(1, 0) * unit);
2131 polygon.push_back(Vector2(3, 0) * unit);
2132 polygon.push_back(Vector2(0, -3) * unit);
2133 polygon.push_back(Vector2(0, -1) * unit);
2134 break;
2135 default:
2136 break;
2137 }
2138 return polygon;
2139}
2140
2141Vector<Point2> TileSet::_get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
2142 Vector2 unit = Vector2(p_size) / 6.0;
2143 if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2144 return {
2145 Vector2(1, 1.0 - p_overlap * 2.0) * unit,
2146 Vector2(0, 1) * unit,
2147 Vector2(-1, 1.0 - p_overlap * 2.0) * unit,
2148 Vector2(-1, -1.0 + p_overlap * 2.0) * unit,
2149 Vector2(0, -1) * unit,
2150 Vector2(1, -1.0 + p_overlap * 2.0) * unit,
2151 };
2152 } else {
2153 return {
2154 Vector2(1, 0) * unit,
2155 Vector2(1.0 - p_overlap * 2.0, -1) * unit,
2156 Vector2(-1.0 + p_overlap * 2.0, -1) * unit,
2157 Vector2(-1, 0) * unit,
2158 Vector2(-1.0 + p_overlap * 2.0, 1) * unit,
2159 Vector2(1.0 - p_overlap * 2.0, 1) * unit,
2160 };
2161 }
2162}
2163
2164Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
2165 Vector<Vector2> point_list = {
2166 Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
2167 Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
2168 Vector2(2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)),
2169 Vector2(1, 3.0 - p_overlap * 2.0),
2170 Vector2(0, 3),
2171 Vector2(-1, 3.0 - p_overlap * 2.0),
2172 Vector2(-2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)),
2173 Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)),
2174 Vector2(-3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
2175 Vector2(-3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
2176 Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)),
2177 Vector2(-2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)),
2178 Vector2(-1, -(3.0 - p_overlap * 2.0)),
2179 Vector2(0, -3),
2180 Vector2(1, -(3.0 - p_overlap * 2.0)),
2181 Vector2(2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)),
2182 Vector2(3, -3.0 * (1.0 - p_overlap * 2.0)),
2183 Vector2(3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)
2184 };
2185
2186 Vector2 unit = Vector2(p_size) / 6.0;
2187 Vector<Vector2> polygon;
2188 if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2189 for (int i = 0; i < point_list.size(); i++) {
2190 point_list.write[i] = point_list[i] * unit;
2191 }
2192 switch (p_bit) {
2193 case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
2194 polygon.push_back(point_list[17]);
2195 polygon.push_back(point_list[0]);
2196 break;
2197 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2198 polygon.push_back(point_list[0]);
2199 polygon.push_back(point_list[1]);
2200 polygon.push_back(point_list[2]);
2201 break;
2202 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2203 polygon.push_back(point_list[2]);
2204 polygon.push_back(point_list[3]);
2205 break;
2206 case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2207 polygon.push_back(point_list[3]);
2208 polygon.push_back(point_list[4]);
2209 polygon.push_back(point_list[5]);
2210 break;
2211 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2212 polygon.push_back(point_list[5]);
2213 polygon.push_back(point_list[6]);
2214 break;
2215 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2216 polygon.push_back(point_list[6]);
2217 polygon.push_back(point_list[7]);
2218 polygon.push_back(point_list[8]);
2219 break;
2220 case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
2221 polygon.push_back(point_list[8]);
2222 polygon.push_back(point_list[9]);
2223 break;
2224 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2225 polygon.push_back(point_list[9]);
2226 polygon.push_back(point_list[10]);
2227 polygon.push_back(point_list[11]);
2228 break;
2229 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2230 polygon.push_back(point_list[11]);
2231 polygon.push_back(point_list[12]);
2232 break;
2233 case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2234 polygon.push_back(point_list[12]);
2235 polygon.push_back(point_list[13]);
2236 polygon.push_back(point_list[14]);
2237 break;
2238 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2239 polygon.push_back(point_list[14]);
2240 polygon.push_back(point_list[15]);
2241 break;
2242 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2243 polygon.push_back(point_list[15]);
2244 polygon.push_back(point_list[16]);
2245 polygon.push_back(point_list[17]);
2246 break;
2247 default:
2248 break;
2249 }
2250 } else {
2251 for (int i = 0; i < point_list.size(); i++) {
2252 point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
2253 }
2254 switch (p_bit) {
2255 case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2256 polygon.push_back(point_list[3]);
2257 polygon.push_back(point_list[4]);
2258 polygon.push_back(point_list[5]);
2259 break;
2260 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2261 polygon.push_back(point_list[2]);
2262 polygon.push_back(point_list[3]);
2263 break;
2264 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2265 polygon.push_back(point_list[0]);
2266 polygon.push_back(point_list[1]);
2267 polygon.push_back(point_list[2]);
2268 break;
2269 case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
2270 polygon.push_back(point_list[17]);
2271 polygon.push_back(point_list[0]);
2272 break;
2273 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2274 polygon.push_back(point_list[15]);
2275 polygon.push_back(point_list[16]);
2276 polygon.push_back(point_list[17]);
2277 break;
2278 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2279 polygon.push_back(point_list[14]);
2280 polygon.push_back(point_list[15]);
2281 break;
2282 case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2283 polygon.push_back(point_list[12]);
2284 polygon.push_back(point_list[13]);
2285 polygon.push_back(point_list[14]);
2286 break;
2287 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2288 polygon.push_back(point_list[11]);
2289 polygon.push_back(point_list[12]);
2290 break;
2291 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2292 polygon.push_back(point_list[9]);
2293 polygon.push_back(point_list[10]);
2294 polygon.push_back(point_list[11]);
2295 break;
2296 case TileSet::CELL_NEIGHBOR_TOP_SIDE:
2297 polygon.push_back(point_list[8]);
2298 polygon.push_back(point_list[9]);
2299 break;
2300 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2301 polygon.push_back(point_list[6]);
2302 polygon.push_back(point_list[7]);
2303 polygon.push_back(point_list[8]);
2304 break;
2305 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2306 polygon.push_back(point_list[5]);
2307 polygon.push_back(point_list[6]);
2308 break;
2309 default:
2310 break;
2311 }
2312 }
2313
2314 int half_polygon_size = polygon.size();
2315 for (int i = 0; i < half_polygon_size; i++) {
2316 polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
2317 }
2318
2319 return polygon;
2320}
2321
2322Vector<Point2> TileSet::_get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
2323 Vector<Vector2> point_list = {
2324 Vector2(3, 0),
2325 Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
2326 Vector2(1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0),
2327 Vector2(0, 3),
2328 Vector2(-1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0),
2329 Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)),
2330 Vector2(-3, 0),
2331 Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)),
2332 Vector2(-1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0),
2333 Vector2(0, -3),
2334 Vector2(1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0),
2335 Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))
2336 };
2337
2338 Vector2 unit = Vector2(p_size) / 6.0;
2339 Vector<Vector2> polygon;
2340 if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2341 for (int i = 0; i < point_list.size(); i++) {
2342 point_list.write[i] = point_list[i] * unit;
2343 }
2344 switch (p_bit) {
2345 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2346 polygon.push_back(point_list[0]);
2347 polygon.push_back(point_list[1]);
2348 polygon.push_back(point_list[2]);
2349 break;
2350 case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2351 polygon.push_back(point_list[2]);
2352 polygon.push_back(point_list[3]);
2353 polygon.push_back(point_list[4]);
2354 break;
2355 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2356 polygon.push_back(point_list[4]);
2357 polygon.push_back(point_list[5]);
2358 polygon.push_back(point_list[6]);
2359 break;
2360 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2361 polygon.push_back(point_list[6]);
2362 polygon.push_back(point_list[7]);
2363 polygon.push_back(point_list[8]);
2364 break;
2365 case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2366 polygon.push_back(point_list[8]);
2367 polygon.push_back(point_list[9]);
2368 polygon.push_back(point_list[10]);
2369 break;
2370 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2371 polygon.push_back(point_list[10]);
2372 polygon.push_back(point_list[11]);
2373 polygon.push_back(point_list[0]);
2374 break;
2375 default:
2376 break;
2377 }
2378 } else {
2379 for (int i = 0; i < point_list.size(); i++) {
2380 point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
2381 }
2382 switch (p_bit) {
2383 case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2384 polygon.push_back(point_list[2]);
2385 polygon.push_back(point_list[3]);
2386 polygon.push_back(point_list[4]);
2387 break;
2388 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2389 polygon.push_back(point_list[0]);
2390 polygon.push_back(point_list[1]);
2391 polygon.push_back(point_list[2]);
2392 break;
2393 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2394 polygon.push_back(point_list[10]);
2395 polygon.push_back(point_list[11]);
2396 polygon.push_back(point_list[0]);
2397 break;
2398 case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2399 polygon.push_back(point_list[8]);
2400 polygon.push_back(point_list[9]);
2401 polygon.push_back(point_list[10]);
2402 break;
2403 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2404 polygon.push_back(point_list[6]);
2405 polygon.push_back(point_list[7]);
2406 polygon.push_back(point_list[8]);
2407 break;
2408 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2409 polygon.push_back(point_list[4]);
2410 polygon.push_back(point_list[5]);
2411 polygon.push_back(point_list[6]);
2412 break;
2413 default:
2414 break;
2415 }
2416 }
2417
2418 int half_polygon_size = polygon.size();
2419 for (int i = 0; i < half_polygon_size; i++) {
2420 polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
2421 }
2422
2423 return polygon;
2424}
2425
2426Vector<Point2> TileSet::_get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
2427 Vector<Vector2> point_list = {
2428 Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
2429 Vector2(0, 3),
2430 Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)),
2431 Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)),
2432 Vector2(0, -3),
2433 Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))
2434 };
2435
2436 Vector2 unit = Vector2(p_size) / 6.0;
2437 Vector<Vector2> polygon;
2438 if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2439 for (int i = 0; i < point_list.size(); i++) {
2440 point_list.write[i] = point_list[i] * unit;
2441 }
2442 switch (p_bit) {
2443 case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
2444 polygon.push_back(point_list[5]);
2445 polygon.push_back(point_list[0]);
2446 break;
2447 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2448 polygon.push_back(point_list[0]);
2449 polygon.push_back(point_list[1]);
2450 break;
2451 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2452 polygon.push_back(point_list[1]);
2453 polygon.push_back(point_list[2]);
2454 break;
2455 case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
2456 polygon.push_back(point_list[2]);
2457 polygon.push_back(point_list[3]);
2458 break;
2459 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2460 polygon.push_back(point_list[3]);
2461 polygon.push_back(point_list[4]);
2462 break;
2463 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2464 polygon.push_back(point_list[4]);
2465 polygon.push_back(point_list[5]);
2466 break;
2467 default:
2468 break;
2469 }
2470 } else {
2471 for (int i = 0; i < point_list.size(); i++) {
2472 point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
2473 }
2474 switch (p_bit) {
2475 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2476 polygon.push_back(point_list[0]);
2477 polygon.push_back(point_list[1]);
2478 break;
2479 case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
2480 polygon.push_back(point_list[5]);
2481 polygon.push_back(point_list[0]);
2482 break;
2483 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2484 polygon.push_back(point_list[4]);
2485 polygon.push_back(point_list[5]);
2486 break;
2487 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2488 polygon.push_back(point_list[3]);
2489 polygon.push_back(point_list[4]);
2490 break;
2491 case TileSet::CELL_NEIGHBOR_TOP_SIDE:
2492 polygon.push_back(point_list[2]);
2493 polygon.push_back(point_list[3]);
2494 break;
2495 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2496 polygon.push_back(point_list[1]);
2497 polygon.push_back(point_list[2]);
2498 break;
2499 default:
2500 break;
2501 }
2502 }
2503
2504 int half_polygon_size = polygon.size();
2505 for (int i = 0; i < half_polygon_size; i++) {
2506 polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
2507 }
2508
2509 return polygon;
2510}
2511
2512void TileSet::reset_state() {
2513 // Rendering
2514 occlusion_layers.clear();
2515 tile_lines_mesh.instantiate();
2516 tile_filled_mesh.instantiate();
2517 tile_meshes_dirty = true;
2518
2519 // Physics
2520 physics_layers.clear();
2521
2522 // Terrains
2523 terrain_sets.clear();
2524 terrain_meshes.clear();
2525 terrain_peering_bits_meshes.clear();
2526 per_terrain_pattern_tiles.clear();
2527 terrains_cache_dirty = true;
2528
2529 // Navigation
2530 navigation_layers.clear();
2531
2532 custom_data_layers.clear();
2533 custom_data_layers_by_name.clear();
2534
2535 // Proxies
2536 source_level_proxies.clear();
2537 coords_level_proxies.clear();
2538 alternative_level_proxies.clear();
2539
2540#ifndef DISABLE_DEPRECATED
2541 for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
2542 memdelete(E.value);
2543 }
2544 compatibility_data.clear();
2545#endif // DISABLE_DEPRECATED
2546 while (!source_ids.is_empty()) {
2547 remove_source(source_ids[0]);
2548 }
2549
2550 tile_shape = TILE_SHAPE_SQUARE;
2551 tile_layout = TILE_LAYOUT_STACKED;
2552 tile_offset_axis = TILE_OFFSET_AXIS_HORIZONTAL;
2553 tile_size = Size2i(16, 16);
2554}
2555
2556const Vector2i TileSetSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1);
2557const int TileSetSource::INVALID_TILE_ALTERNATIVE = -1;
2558
2559#ifndef DISABLE_DEPRECATED
2560void TileSet::_compatibility_conversion() {
2561 for (KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
2562 CompatibilityTileData *ctd = E.value;
2563
2564 // Add the texture
2565 TileSetAtlasSource *atlas_source = memnew(TileSetAtlasSource);
2566 int source_id = add_source(Ref<TileSetSource>(atlas_source));
2567
2568 atlas_source->set_texture(ctd->texture);
2569
2570 // Handle each tile as a new source. Not optimal but at least it should stay compatible.
2571 switch (ctd->tile_mode) {
2572 case COMPATIBILITY_TILE_MODE_SINGLE_TILE: {
2573 atlas_source->set_margins(ctd->region.get_position());
2574 atlas_source->set_texture_region_size(ctd->region.get_size());
2575
2576 Vector2i coords;
2577 for (int flags = 0; flags < 8; flags++) {
2578 bool flip_h = flags & 1;
2579 bool flip_v = flags & 2;
2580 bool transpose = flags & 4;
2581
2582 Transform2D xform;
2583 xform = flip_h ? xform.scaled(Size2(-1, 1)) : xform;
2584 xform = flip_v ? xform.scaled(Size2(1, -1)) : xform;
2585 xform = transpose ? Transform2D(xform[1], xform[0], Vector2()) : xform;
2586
2587 int alternative_tile = 0;
2588 if (!atlas_source->has_tile(coords)) {
2589 atlas_source->create_tile(coords);
2590 } else {
2591 alternative_tile = atlas_source->create_alternative_tile(coords);
2592 }
2593
2594 // Add to the mapping.
2595 Array key_array;
2596 key_array.push_back(flip_h);
2597 key_array.push_back(flip_v);
2598 key_array.push_back(transpose);
2599
2600 Array value_array;
2601 value_array.push_back(source_id);
2602 value_array.push_back(coords);
2603 value_array.push_back(alternative_tile);
2604
2605 if (!compatibility_tilemap_mapping.has(E.key)) {
2606 compatibility_tilemap_mapping[E.key] = RBMap<Array, Array>();
2607 }
2608 compatibility_tilemap_mapping[E.key][key_array] = value_array;
2609 compatibility_tilemap_mapping_tile_modes[E.key] = COMPATIBILITY_TILE_MODE_SINGLE_TILE;
2610
2611 TileData *tile_data = atlas_source->get_tile_data(coords, alternative_tile);
2612 ERR_CONTINUE(!tile_data);
2613
2614 tile_data->set_flip_h(flip_h);
2615 tile_data->set_flip_v(flip_v);
2616 tile_data->set_transpose(transpose);
2617 tile_data->set_material(ctd->material);
2618 tile_data->set_modulate(ctd->modulate);
2619 tile_data->set_z_index(ctd->z_index);
2620
2621 if (ctd->occluder.is_valid()) {
2622 if (get_occlusion_layers_count() < 1) {
2623 add_occlusion_layer();
2624 };
2625 Ref<OccluderPolygon2D> occluder = ctd->occluder->duplicate();
2626 Vector<Vector2> polygon = ctd->occluder->get_polygon();
2627 for (int index = 0; index < polygon.size(); index++) {
2628 polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0);
2629 }
2630 occluder->set_polygon(polygon);
2631 tile_data->set_occluder(0, occluder);
2632 }
2633 if (ctd->navigation.is_valid()) {
2634 if (get_navigation_layers_count() < 1) {
2635 add_navigation_layer();
2636 }
2637 Ref<NavigationPolygon> navigation = ctd->navigation->duplicate();
2638 Vector<Vector2> vertices = navigation->get_vertices();
2639 for (int index = 0; index < vertices.size(); index++) {
2640 vertices.write[index] = xform.xform(vertices[index] - ctd->region.get_size() / 2.0);
2641 }
2642 navigation->set_vertices(vertices);
2643 tile_data->set_navigation_polygon(0, navigation);
2644 }
2645
2646 tile_data->set_z_index(ctd->z_index);
2647
2648 // Add the shapes.
2649 if (ctd->shapes.size() > 0) {
2650 if (get_physics_layers_count() < 1) {
2651 add_physics_layer();
2652 }
2653 }
2654 for (int k = 0; k < ctd->shapes.size(); k++) {
2655 CompatibilityShapeData csd = ctd->shapes[k];
2656 if (csd.autotile_coords == coords) {
2657 Ref<ConvexPolygonShape2D> convex_shape = csd.shape; // Only ConvexPolygonShape2D are supported, which is the default type used by the 3.x editor
2658 if (convex_shape.is_valid()) {
2659 Vector<Vector2> polygon = convex_shape->get_points();
2660 for (int point_index = 0; point_index < polygon.size(); point_index++) {
2661 polygon.write[point_index] = xform.xform(csd.transform.xform(polygon[point_index]) - ctd->region.get_size() / 2.0);
2662 }
2663 tile_data->set_collision_polygons_count(0, tile_data->get_collision_polygons_count(0) + 1);
2664 int index = tile_data->get_collision_polygons_count(0) - 1;
2665 tile_data->set_collision_polygon_one_way(0, index, csd.one_way);
2666 tile_data->set_collision_polygon_one_way_margin(0, index, csd.one_way_margin);
2667 tile_data->set_collision_polygon_points(0, index, polygon);
2668 }
2669 }
2670 }
2671 }
2672 // Update the size count.
2673 if (!compatibility_size_count.has(ctd->region.get_size())) {
2674 compatibility_size_count[ctd->region.get_size()] = 0;
2675 }
2676 compatibility_size_count[ctd->region.get_size()]++;
2677 } break;
2678 case COMPATIBILITY_TILE_MODE_AUTO_TILE: {
2679 // Not supported. It would need manual conversion.
2680 WARN_PRINT_ONCE("Could not convert 3.x autotiles to 4.x. This operation cannot be done automatically, autotiles must be re-created using the terrain system.");
2681 } break;
2682 case COMPATIBILITY_TILE_MODE_ATLAS_TILE: {
2683 atlas_source->set_margins(ctd->region.get_position());
2684 atlas_source->set_separation(Vector2i(ctd->autotile_spacing, ctd->autotile_spacing));
2685 atlas_source->set_texture_region_size(ctd->autotile_tile_size);
2686
2687 Size2i atlas_size = ctd->region.get_size() / (ctd->autotile_tile_size + atlas_source->get_separation());
2688 for (int i = 0; i < atlas_size.x; i++) {
2689 for (int j = 0; j < atlas_size.y; j++) {
2690 Vector2i coords = Vector2i(i, j);
2691
2692 for (int flags = 0; flags < 8; flags++) {
2693 bool flip_h = flags & 1;
2694 bool flip_v = flags & 2;
2695 bool transpose = flags & 4;
2696
2697 Transform2D xform;
2698 xform = flip_h ? xform.scaled(Size2(-1, 1)) : xform;
2699 xform = flip_v ? xform.scaled(Size2(1, -1)) : xform;
2700 xform = transpose ? Transform2D(xform[1], xform[0], Vector2()) : xform;
2701
2702 int alternative_tile = 0;
2703 if (!atlas_source->has_tile(coords)) {
2704 atlas_source->create_tile(coords);
2705 } else {
2706 alternative_tile = atlas_source->create_alternative_tile(coords);
2707 }
2708
2709 // Add to the mapping.
2710 Array key_array;
2711 key_array.push_back(coords);
2712 key_array.push_back(flip_h);
2713 key_array.push_back(flip_v);
2714 key_array.push_back(transpose);
2715
2716 Array value_array;
2717 value_array.push_back(source_id);
2718 value_array.push_back(coords);
2719 value_array.push_back(alternative_tile);
2720
2721 if (!compatibility_tilemap_mapping.has(E.key)) {
2722 compatibility_tilemap_mapping[E.key] = RBMap<Array, Array>();
2723 }
2724 compatibility_tilemap_mapping[E.key][key_array] = value_array;
2725 compatibility_tilemap_mapping_tile_modes[E.key] = COMPATIBILITY_TILE_MODE_ATLAS_TILE;
2726
2727 TileData *tile_data = atlas_source->get_tile_data(coords, alternative_tile);
2728
2729 tile_data->set_flip_h(flip_h);
2730 tile_data->set_flip_v(flip_v);
2731 tile_data->set_transpose(transpose);
2732 tile_data->set_material(ctd->material);
2733 tile_data->set_modulate(ctd->modulate);
2734 tile_data->set_z_index(ctd->z_index);
2735 if (ctd->autotile_occluder_map.has(coords)) {
2736 if (get_occlusion_layers_count() < 1) {
2737 add_occlusion_layer();
2738 }
2739 Ref<OccluderPolygon2D> occluder = ctd->autotile_occluder_map[coords]->duplicate();
2740 Vector<Vector2> polygon = ctd->occluder->get_polygon();
2741 for (int index = 0; index < polygon.size(); index++) {
2742 polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0);
2743 }
2744 occluder->set_polygon(polygon);
2745 tile_data->set_occluder(0, occluder);
2746 }
2747 if (ctd->autotile_navpoly_map.has(coords)) {
2748 if (get_navigation_layers_count() < 1) {
2749 add_navigation_layer();
2750 }
2751 Ref<NavigationPolygon> navigation = ctd->autotile_navpoly_map[coords]->duplicate();
2752 Vector<Vector2> vertices = navigation->get_vertices();
2753 for (int index = 0; index < vertices.size(); index++) {
2754 vertices.write[index] = xform.xform(vertices[index] - ctd->region.get_size() / 2.0);
2755 }
2756 navigation->set_vertices(vertices);
2757 tile_data->set_navigation_polygon(0, navigation);
2758 }
2759 if (ctd->autotile_priority_map.has(coords)) {
2760 tile_data->set_probability(ctd->autotile_priority_map[coords]);
2761 }
2762 if (ctd->autotile_z_index_map.has(coords)) {
2763 tile_data->set_z_index(ctd->autotile_z_index_map[coords]);
2764 }
2765
2766 // Add the shapes.
2767 if (ctd->shapes.size() > 0) {
2768 if (get_physics_layers_count() < 1) {
2769 add_physics_layer();
2770 }
2771 }
2772 for (int k = 0; k < ctd->shapes.size(); k++) {
2773 CompatibilityShapeData csd = ctd->shapes[k];
2774 if (csd.autotile_coords == coords) {
2775 Ref<ConvexPolygonShape2D> convex_shape = csd.shape; // Only ConvexPolygonShape2D are supported, which is the default type used by the 3.x editor
2776 if (convex_shape.is_valid()) {
2777 Vector<Vector2> polygon = convex_shape->get_points();
2778 for (int point_index = 0; point_index < polygon.size(); point_index++) {
2779 polygon.write[point_index] = xform.xform(csd.transform.xform(polygon[point_index]) - ctd->autotile_tile_size / 2.0);
2780 }
2781 tile_data->set_collision_polygons_count(0, tile_data->get_collision_polygons_count(0) + 1);
2782 int index = tile_data->get_collision_polygons_count(0) - 1;
2783 tile_data->set_collision_polygon_one_way(0, index, csd.one_way);
2784 tile_data->set_collision_polygon_one_way_margin(0, index, csd.one_way_margin);
2785 tile_data->set_collision_polygon_points(0, index, polygon);
2786 }
2787 }
2788 }
2789
2790 // -- TODO: handle --
2791 // Those are offset for the whole atlas, they are likely useless for the atlases, but might make sense for single tiles.
2792 // texture offset
2793 // occluder_offset
2794 // navigation_offset
2795
2796 // For terrains, ignored for now?
2797 // bitmask_mode
2798 // bitmask_flags
2799 }
2800 }
2801 }
2802
2803 // Update the size count.
2804 if (!compatibility_size_count.has(ctd->region.get_size())) {
2805 compatibility_size_count[ctd->autotile_tile_size] = 0;
2806 }
2807 compatibility_size_count[ctd->autotile_tile_size] += atlas_size.x * atlas_size.y;
2808 } break;
2809 }
2810
2811 // Offset all shapes
2812 for (int k = 0; k < ctd->shapes.size(); k++) {
2813 Ref<ConvexPolygonShape2D> convex = ctd->shapes[k].shape;
2814 if (convex.is_valid()) {
2815 Vector<Vector2> points = convex->get_points();
2816 for (int i_point = 0; i_point < points.size(); i_point++) {
2817 points.write[i_point] = points[i_point] - get_tile_size() / 2;
2818 }
2819 convex->set_points(points);
2820 }
2821 }
2822 }
2823
2824 // Update the TileSet tile_size according to the most common size found.
2825 Vector2i max_size = get_tile_size();
2826 int max_count = 0;
2827 for (KeyValue<Vector2i, int> kv : compatibility_size_count) {
2828 if (kv.value > max_count) {
2829 max_size = kv.key;
2830 max_count = kv.value;
2831 }
2832 }
2833 set_tile_size(max_size);
2834
2835 // Reset compatibility data (besides the histogram counts)
2836 for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
2837 memdelete(E.value);
2838 }
2839 compatibility_data = HashMap<int, CompatibilityTileData *>();
2840}
2841
2842Array TileSet::compatibility_tilemap_map(int p_tile_id, Vector2i p_coords, bool p_flip_h, bool p_flip_v, bool p_transpose) {
2843 Array cannot_convert_array;
2844 cannot_convert_array.push_back(TileSet::INVALID_SOURCE);
2845 cannot_convert_array.push_back(TileSetAtlasSource::INVALID_ATLAS_COORDS);
2846 cannot_convert_array.push_back(TileSetAtlasSource::INVALID_TILE_ALTERNATIVE);
2847
2848 if (!compatibility_tilemap_mapping.has(p_tile_id)) {
2849 return cannot_convert_array;
2850 }
2851
2852 int tile_mode = compatibility_tilemap_mapping_tile_modes[p_tile_id];
2853 switch (tile_mode) {
2854 case COMPATIBILITY_TILE_MODE_SINGLE_TILE: {
2855 Array a;
2856 a.push_back(p_flip_h);
2857 a.push_back(p_flip_v);
2858 a.push_back(p_transpose);
2859 return compatibility_tilemap_mapping[p_tile_id][a];
2860 }
2861 case COMPATIBILITY_TILE_MODE_AUTO_TILE:
2862 return cannot_convert_array;
2863 break;
2864 case COMPATIBILITY_TILE_MODE_ATLAS_TILE: {
2865 Array a;
2866 a.push_back(p_coords);
2867 a.push_back(p_flip_h);
2868 a.push_back(p_flip_v);
2869 a.push_back(p_transpose);
2870 return compatibility_tilemap_mapping[p_tile_id][a];
2871 }
2872 default:
2873 return cannot_convert_array;
2874 break;
2875 }
2876};
2877
2878#endif // DISABLE_DEPRECATED
2879
2880bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
2881 Vector<String> components = String(p_name).split("/", true, 2);
2882
2883#ifndef DISABLE_DEPRECATED
2884 // TODO: This should be moved to a dedicated conversion system (see #50691)
2885 if (components.size() >= 1 && components[0].is_valid_int()) {
2886 int id = components[0].to_int();
2887
2888 // Get or create the compatibility object
2889 CompatibilityTileData *ctd;
2890 HashMap<int, CompatibilityTileData *>::Iterator E = compatibility_data.find(id);
2891 if (!E) {
2892 ctd = memnew(CompatibilityTileData);
2893 compatibility_data.insert(id, ctd);
2894 } else {
2895 ctd = E->value;
2896 }
2897
2898 if (components.size() < 2) {
2899 return false;
2900 }
2901
2902 String what = components[1];
2903
2904 if (what == "name") {
2905 ctd->name = p_value;
2906 } else if (what == "texture") {
2907 ctd->texture = p_value;
2908 } else if (what == "tex_offset") {
2909 ctd->tex_offset = p_value;
2910 } else if (what == "material") {
2911 ctd->material = p_value;
2912 } else if (what == "modulate") {
2913 ctd->modulate = p_value;
2914 } else if (what == "region") {
2915 ctd->region = p_value;
2916 } else if (what == "tile_mode") {
2917 ctd->tile_mode = p_value;
2918 } else if (what.left(9) == "autotile") {
2919 what = what.substr(9);
2920 if (what == "bitmask_mode") {
2921 ctd->autotile_bitmask_mode = p_value;
2922 } else if (what == "icon_coordinate") {
2923 ctd->autotile_icon_coordinate = p_value;
2924 } else if (what == "tile_size") {
2925 ctd->autotile_tile_size = p_value;
2926 } else if (what == "spacing") {
2927 ctd->autotile_spacing = p_value;
2928 } else if (what == "bitmask_flags") {
2929 if (p_value.is_array()) {
2930 Array p = p_value;
2931 Vector2i last_coord;
2932 while (p.size() > 0) {
2933 if (p[0].get_type() == Variant::VECTOR2) {
2934 last_coord = p[0];
2935 } else if (p[0].get_type() == Variant::INT) {
2936 ctd->autotile_bitmask_flags.insert(last_coord, p[0]);
2937 }
2938 p.pop_front();
2939 }
2940 }
2941 } else if (what == "occluder_map") {
2942 Array p = p_value;
2943 Vector2 last_coord;
2944 while (p.size() > 0) {
2945 if (p[0].get_type() == Variant::VECTOR2) {
2946 last_coord = p[0];
2947 } else if (p[0].get_type() == Variant::OBJECT) {
2948 ctd->autotile_occluder_map.insert(last_coord, p[0]);
2949 }
2950 p.pop_front();
2951 }
2952 } else if (what == "navpoly_map") {
2953 Array p = p_value;
2954 Vector2 last_coord;
2955 while (p.size() > 0) {
2956 if (p[0].get_type() == Variant::VECTOR2) {
2957 last_coord = p[0];
2958 } else if (p[0].get_type() == Variant::OBJECT) {
2959 ctd->autotile_navpoly_map.insert(last_coord, p[0]);
2960 }
2961 p.pop_front();
2962 }
2963 } else if (what == "priority_map") {
2964 Array p = p_value;
2965 Vector3 val;
2966 Vector2 v;
2967 int priority;
2968 while (p.size() > 0) {
2969 val = p[0];
2970 if (val.z > 1) {
2971 v.x = val.x;
2972 v.y = val.y;
2973 priority = (int)val.z;
2974 ctd->autotile_priority_map.insert(v, priority);
2975 }
2976 p.pop_front();
2977 }
2978 } else if (what == "z_index_map") {
2979 Array p = p_value;
2980 Vector3 val;
2981 Vector2 v;
2982 int z_index;
2983 while (p.size() > 0) {
2984 val = p[0];
2985 if (val.z != 0) {
2986 v.x = val.x;
2987 v.y = val.y;
2988 z_index = (int)val.z;
2989 ctd->autotile_z_index_map.insert(v, z_index);
2990 }
2991 p.pop_front();
2992 }
2993 }
2994
2995 } else if (what == "shapes") {
2996 Array p = p_value;
2997 for (int i = 0; i < p.size(); i++) {
2998 CompatibilityShapeData csd;
2999 Dictionary d = p[i];
3000 for (int j = 0; j < d.size(); j++) {
3001 String key = d.get_key_at_index(j);
3002 if (key == "autotile_coord") {
3003 csd.autotile_coords = d[key];
3004 } else if (key == "one_way") {
3005 csd.one_way = d[key];
3006 } else if (key == "one_way_margin") {
3007 csd.one_way_margin = d[key];
3008 } else if (key == "shape") {
3009 csd.shape = d[key];
3010 } else if (key == "shape_transform") {
3011 csd.transform = d[key];
3012 }
3013 }
3014 ctd->shapes.push_back(csd);
3015 }
3016 } else if (what == "occluder") {
3017 ctd->occluder = p_value;
3018 } else if (what == "navigation") {
3019 ctd->navigation = p_value;
3020
3021 /*
3022 // IGNORED FOR NOW, they seem duplicated data compared to the shapes array
3023 } else if (what == "shape") {
3024 } else if (what == "shape_offset") {
3025 } else if (what == "shape_transform") {
3026 } else if (what == "shape_one_way") {
3027 } else if (what == "shape_one_way_margin") {
3028 }
3029 // IGNORED FOR NOW, maybe useless ?
3030 else if (what == "occluder_offset") {
3031 // Not
3032 } else if (what == "navigation_offset") {
3033 }
3034 */
3035
3036 } else if (what == "z_index") {
3037 ctd->z_index = p_value;
3038
3039 // TODO: remove the conversion from here, it's not where it should be done (see #50691)
3040 _compatibility_conversion();
3041 } else {
3042 return false;
3043 }
3044 } else {
3045#endif // DISABLE_DEPRECATED
3046
3047 // This is now a new property.
3048 if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
3049 // Occlusion layers.
3050 int index = components[0].trim_prefix("occlusion_layer_").to_int();
3051 ERR_FAIL_COND_V(index < 0, false);
3052 if (components[1] == "light_mask") {
3053 ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3054 while (index >= occlusion_layers.size()) {
3055 add_occlusion_layer();
3056 }
3057 set_occlusion_layer_light_mask(index, p_value);
3058 return true;
3059 } else if (components[1] == "sdf_collision") {
3060 ERR_FAIL_COND_V(p_value.get_type() != Variant::BOOL, false);
3061 while (index >= occlusion_layers.size()) {
3062 add_occlusion_layer();
3063 }
3064 set_occlusion_layer_sdf_collision(index, p_value);
3065 return true;
3066 }
3067 } else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
3068 // Physics layers.
3069 int index = components[0].trim_prefix("physics_layer_").to_int();
3070 ERR_FAIL_COND_V(index < 0, false);
3071 if (components[1] == "collision_layer") {
3072 ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3073 while (index >= physics_layers.size()) {
3074 add_physics_layer();
3075 }
3076 set_physics_layer_collision_layer(index, p_value);
3077 return true;
3078 } else if (components[1] == "collision_mask") {
3079 ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3080 while (index >= physics_layers.size()) {
3081 add_physics_layer();
3082 }
3083 set_physics_layer_collision_mask(index, p_value);
3084 return true;
3085 } else if (components[1] == "physics_material") {
3086 Ref<PhysicsMaterial> physics_material = p_value;
3087 while (index >= physics_layers.size()) {
3088 add_physics_layer();
3089 }
3090 set_physics_layer_physics_material(index, physics_material);
3091 return true;
3092 }
3093 } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int()) {
3094 // Terrains.
3095 int terrain_set_index = components[0].trim_prefix("terrain_set_").to_int();
3096 ERR_FAIL_COND_V(terrain_set_index < 0, false);
3097 if (components[1] == "mode") {
3098 ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3099 while (terrain_set_index >= terrain_sets.size()) {
3100 add_terrain_set();
3101 }
3102 set_terrain_set_mode(terrain_set_index, TerrainMode(int(p_value)));
3103 } else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_int()) {
3104 int terrain_index = components[1].trim_prefix("terrain_").to_int();
3105 ERR_FAIL_COND_V(terrain_index < 0, false);
3106 if (components[2] == "name") {
3107 ERR_FAIL_COND_V(p_value.get_type() != Variant::STRING, false);
3108 while (terrain_set_index >= terrain_sets.size()) {
3109 add_terrain_set();
3110 }
3111 while (terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
3112 add_terrain(terrain_set_index);
3113 }
3114 set_terrain_name(terrain_set_index, terrain_index, p_value);
3115 return true;
3116 } else if (components[2] == "color") {
3117 ERR_FAIL_COND_V(p_value.get_type() != Variant::COLOR, false);
3118 while (terrain_set_index >= terrain_sets.size()) {
3119 add_terrain_set();
3120 }
3121 while (terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
3122 add_terrain(terrain_set_index);
3123 }
3124 set_terrain_color(terrain_set_index, terrain_index, p_value);
3125 return true;
3126 }
3127 }
3128 } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
3129 // Navigation layers.
3130 int index = components[0].trim_prefix("navigation_layer_").to_int();
3131 ERR_FAIL_COND_V(index < 0, false);
3132 if (components[1] == "layers") {
3133 ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3134 while (index >= navigation_layers.size()) {
3135 add_navigation_layer();
3136 }
3137 set_navigation_layer_layers(index, p_value);
3138 return true;
3139 }
3140 } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int()) {
3141 // Custom data layers.
3142 int index = components[0].trim_prefix("custom_data_layer_").to_int();
3143 ERR_FAIL_COND_V(index < 0, false);
3144 if (components[1] == "name") {
3145 ERR_FAIL_COND_V(p_value.get_type() != Variant::STRING, false);
3146 while (index >= custom_data_layers.size()) {
3147 add_custom_data_layer();
3148 }
3149 set_custom_data_layer_name(index, p_value);
3150 return true;
3151 } else if (components[1] == "type") {
3152 ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3153 while (index >= custom_data_layers.size()) {
3154 add_custom_data_layer();
3155 }
3156 set_custom_data_layer_type(index, Variant::Type(int(p_value)));
3157 return true;
3158 }
3159 } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) {
3160 // Create source only if it does not exists.
3161 int source_id = components[1].to_int();
3162
3163 if (has_source(source_id)) {
3164 remove_source(source_id);
3165 }
3166 add_source(p_value, source_id);
3167 return true;
3168 } else if (components.size() == 2 && components[0] == "tile_proxies") {
3169 ERR_FAIL_COND_V(p_value.get_type() != Variant::ARRAY, false);
3170 Array a = p_value;
3171 ERR_FAIL_COND_V(a.size() % 2 != 0, false);
3172 if (components[1] == "source_level") {
3173 for (int i = 0; i < a.size(); i += 2) {
3174 set_source_level_tile_proxy(a[i], a[i + 1]);
3175 }
3176 return true;
3177 } else if (components[1] == "coords_level") {
3178 for (int i = 0; i < a.size(); i += 2) {
3179 Array key = a[i];
3180 Array value = a[i + 1];
3181 set_coords_level_tile_proxy(key[0], key[1], value[0], value[1]);
3182 }
3183 return true;
3184 } else if (components[1] == "alternative_level") {
3185 for (int i = 0; i < a.size(); i += 2) {
3186 Array key = a[i];
3187 Array value = a[i + 1];
3188 set_alternative_level_tile_proxy(key[0], key[1], key[2], value[0], value[1], value[2]);
3189 }
3190 return true;
3191 }
3192 return false;
3193 } else if (components.size() == 1 && components[0].begins_with("pattern_") && components[0].trim_prefix("pattern_").is_valid_int()) {
3194 int pattern_index = components[0].trim_prefix("pattern_").to_int();
3195 for (int i = patterns.size(); i <= pattern_index; i++) {
3196 add_pattern(p_value);
3197 }
3198 return true;
3199 }
3200
3201#ifndef DISABLE_DEPRECATED
3202 }
3203#endif // DISABLE_DEPRECATED
3204
3205 return false;
3206}
3207
3208bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
3209 Vector<String> components = String(p_name).split("/", true, 2);
3210
3211 if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
3212 // Occlusion layers.
3213 int index = components[0].trim_prefix("occlusion_layer_").to_int();
3214 if (index < 0 || index >= occlusion_layers.size()) {
3215 return false;
3216 }
3217 if (components[1] == "light_mask") {
3218 r_ret = get_occlusion_layer_light_mask(index);
3219 return true;
3220 } else if (components[1] == "sdf_collision") {
3221 r_ret = get_occlusion_layer_sdf_collision(index);
3222 return true;
3223 }
3224 } else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
3225 // Physics layers.
3226 int index = components[0].trim_prefix("physics_layer_").to_int();
3227 if (index < 0 || index >= physics_layers.size()) {
3228 return false;
3229 }
3230 if (components[1] == "collision_layer") {
3231 r_ret = get_physics_layer_collision_layer(index);
3232 return true;
3233 } else if (components[1] == "collision_mask") {
3234 r_ret = get_physics_layer_collision_mask(index);
3235 return true;
3236 } else if (components[1] == "physics_material") {
3237 r_ret = get_physics_layer_physics_material(index);
3238 return true;
3239 }
3240 } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int()) {
3241 // Terrains.
3242 int terrain_set_index = components[0].trim_prefix("terrain_set_").to_int();
3243 if (terrain_set_index < 0 || terrain_set_index >= terrain_sets.size()) {
3244 return false;
3245 }
3246 if (components[1] == "mode") {
3247 r_ret = get_terrain_set_mode(terrain_set_index);
3248 return true;
3249 } else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_int()) {
3250 int terrain_index = components[1].trim_prefix("terrain_").to_int();
3251 if (terrain_index < 0 || terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
3252 return false;
3253 }
3254 if (components[2] == "name") {
3255 r_ret = get_terrain_name(terrain_set_index, terrain_index);
3256 return true;
3257 } else if (components[2] == "color") {
3258 r_ret = get_terrain_color(terrain_set_index, terrain_index);
3259 return true;
3260 }
3261 }
3262 } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
3263 // navigation layers.
3264 int index = components[0].trim_prefix("navigation_layer_").to_int();
3265 if (index < 0 || index >= navigation_layers.size()) {
3266 return false;
3267 }
3268 if (components[1] == "layers") {
3269 r_ret = get_navigation_layer_layers(index);
3270 return true;
3271 }
3272 } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int()) {
3273 // Custom data layers.
3274 int index = components[0].trim_prefix("custom_data_layer_").to_int();
3275 if (index < 0 || index >= custom_data_layers.size()) {
3276 return false;
3277 }
3278 if (components[1] == "name") {
3279 r_ret = get_custom_data_layer_name(index);
3280 return true;
3281 } else if (components[1] == "type") {
3282 r_ret = get_custom_data_layer_type(index);
3283 return true;
3284 }
3285 } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) {
3286 // Atlases data.
3287 int source_id = components[1].to_int();
3288
3289 if (has_source(source_id)) {
3290 r_ret = get_source(source_id);
3291 return true;
3292 } else {
3293 return false;
3294 }
3295 } else if (components.size() == 2 && components[0] == "tile_proxies") {
3296 if (components[1] == "source_level") {
3297 Array a;
3298 for (const KeyValue<int, int> &E : source_level_proxies) {
3299 a.push_back(E.key);
3300 a.push_back(E.value);
3301 }
3302 r_ret = a;
3303 return true;
3304 } else if (components[1] == "coords_level") {
3305 Array a;
3306 for (const KeyValue<Array, Array> &E : coords_level_proxies) {
3307 a.push_back(E.key);
3308 a.push_back(E.value);
3309 }
3310 r_ret = a;
3311 return true;
3312 } else if (components[1] == "alternative_level") {
3313 Array a;
3314 for (const KeyValue<Array, Array> &E : alternative_level_proxies) {
3315 a.push_back(E.key);
3316 a.push_back(E.value);
3317 }
3318 r_ret = a;
3319 return true;
3320 }
3321 return false;
3322 } else if (components.size() == 1 && components[0].begins_with("pattern_") && components[0].trim_prefix("pattern_").is_valid_int()) {
3323 int pattern_index = components[0].trim_prefix("pattern_").to_int();
3324 if (pattern_index < 0 || pattern_index >= (int)patterns.size()) {
3325 return false;
3326 }
3327 r_ret = patterns[pattern_index];
3328 return true;
3329 }
3330
3331 return false;
3332}
3333
3334void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
3335 PropertyInfo property_info;
3336 // Rendering.
3337 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Rendering", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
3338 for (int i = 0; i < occlusion_layers.size(); i++) {
3339 p_list->push_back(PropertyInfo(Variant::INT, vformat("occlusion_layer_%d/light_mask", i), PROPERTY_HINT_LAYERS_2D_RENDER));
3340
3341 // occlusion_layer_%d/sdf_collision
3342 property_info = PropertyInfo(Variant::BOOL, vformat("occlusion_layer_%d/sdf_collision", i));
3343 if (occlusion_layers[i].sdf_collision == false) {
3344 property_info.usage ^= PROPERTY_USAGE_STORAGE;
3345 }
3346 p_list->push_back(property_info);
3347 }
3348
3349 // Physics.
3350 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Physics", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
3351 for (int i = 0; i < physics_layers.size(); i++) {
3352 p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/collision_layer", i), PROPERTY_HINT_LAYERS_2D_PHYSICS));
3353
3354 // physics_layer_%d/collision_mask
3355 property_info = PropertyInfo(Variant::INT, vformat("physics_layer_%d/collision_mask", i), PROPERTY_HINT_LAYERS_2D_PHYSICS);
3356 if (physics_layers[i].collision_mask == 1) {
3357 property_info.usage ^= PROPERTY_USAGE_STORAGE;
3358 }
3359 p_list->push_back(property_info);
3360
3361 // physics_layer_%d/physics_material
3362 property_info = PropertyInfo(Variant::OBJECT, vformat("physics_layer_%d/physics_material", i), PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial");
3363 if (!physics_layers[i].physics_material.is_valid()) {
3364 property_info.usage ^= PROPERTY_USAGE_STORAGE;
3365 }
3366 p_list->push_back(property_info);
3367 }
3368
3369 // Terrains.
3370 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Terrains", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
3371 for (int terrain_set_index = 0; terrain_set_index < terrain_sets.size(); terrain_set_index++) {
3372 p_list->push_back(PropertyInfo(Variant::INT, vformat("terrain_set_%d/mode", terrain_set_index), PROPERTY_HINT_ENUM, "Match Corners and Sides,Match Corners,Match Sides"));
3373 p_list->push_back(PropertyInfo(Variant::NIL, vformat("terrain_set_%d/terrains", terrain_set_index), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, vformat("terrain_set_%d/terrain_", terrain_set_index)));
3374 for (int terrain_index = 0; terrain_index < terrain_sets[terrain_set_index].terrains.size(); terrain_index++) {
3375 p_list->push_back(PropertyInfo(Variant::STRING, vformat("terrain_set_%d/terrain_%d/name", terrain_set_index, terrain_index)));
3376 p_list->push_back(PropertyInfo(Variant::COLOR, vformat("terrain_set_%d/terrain_%d/color", terrain_set_index, terrain_index)));
3377 }
3378 }
3379
3380 // Navigation.
3381 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Navigation", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
3382 for (int i = 0; i < navigation_layers.size(); i++) {
3383 p_list->push_back(PropertyInfo(Variant::INT, vformat("navigation_layer_%d/layers", i), PROPERTY_HINT_LAYERS_2D_NAVIGATION));
3384 }
3385
3386 // Custom data.
3387 String argt = "Any";
3388 for (int i = 1; i < Variant::VARIANT_MAX; i++) {
3389 argt += "," + Variant::get_type_name(Variant::Type(i));
3390 }
3391 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Custom Data", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
3392 for (int i = 0; i < custom_data_layers.size(); i++) {
3393 p_list->push_back(PropertyInfo(Variant::STRING, vformat("custom_data_layer_%d/name", i)));
3394 p_list->push_back(PropertyInfo(Variant::INT, vformat("custom_data_layer_%d/type", i), PROPERTY_HINT_ENUM, argt));
3395 }
3396
3397 // Sources.
3398 // Note: sources have to be listed in at the end as some TileData rely on the TileSet properties being initialized first.
3399 for (const KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
3400 p_list->push_back(PropertyInfo(Variant::INT, vformat("sources/%d", E_source.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
3401 }
3402
3403 // Tile Proxies.
3404 // Note: proxies need to be set after sources are set.
3405 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Tile Proxies", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
3406 p_list->push_back(PropertyInfo(Variant::ARRAY, PNAME("tile_proxies/source_level"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
3407 p_list->push_back(PropertyInfo(Variant::ARRAY, PNAME("tile_proxies/coords_level"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
3408 p_list->push_back(PropertyInfo(Variant::ARRAY, PNAME("tile_proxies/alternative_level"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
3409
3410 // Patterns.
3411 for (unsigned int pattern_index = 0; pattern_index < patterns.size(); pattern_index++) {
3412 p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("pattern_%d", pattern_index), PROPERTY_HINT_RESOURCE_TYPE, "TileMapPattern", PROPERTY_USAGE_NO_EDITOR));
3413 }
3414}
3415
3416void TileSet::_validate_property(PropertyInfo &p_property) const {
3417 if (p_property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) {
3418 p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
3419 } else if (p_property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) {
3420 p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
3421 }
3422}
3423
3424void TileSet::_bind_methods() {
3425 // Sources management.
3426 ClassDB::bind_method(D_METHOD("get_next_source_id"), &TileSet::get_next_source_id);
3427 ClassDB::bind_method(D_METHOD("add_source", "source", "atlas_source_id_override"), &TileSet::add_source, DEFVAL(TileSet::INVALID_SOURCE));
3428 ClassDB::bind_method(D_METHOD("remove_source", "source_id"), &TileSet::remove_source);
3429 ClassDB::bind_method(D_METHOD("set_source_id", "source_id", "new_source_id"), &TileSet::set_source_id);
3430 ClassDB::bind_method(D_METHOD("get_source_count"), &TileSet::get_source_count);
3431 ClassDB::bind_method(D_METHOD("get_source_id", "index"), &TileSet::get_source_id);
3432 ClassDB::bind_method(D_METHOD("has_source", "source_id"), &TileSet::has_source);
3433 ClassDB::bind_method(D_METHOD("get_source", "source_id"), &TileSet::get_source);
3434
3435 // Shape and layout.
3436 ClassDB::bind_method(D_METHOD("set_tile_shape", "shape"), &TileSet::set_tile_shape);
3437 ClassDB::bind_method(D_METHOD("get_tile_shape"), &TileSet::get_tile_shape);
3438 ClassDB::bind_method(D_METHOD("set_tile_layout", "layout"), &TileSet::set_tile_layout);
3439 ClassDB::bind_method(D_METHOD("get_tile_layout"), &TileSet::get_tile_layout);
3440 ClassDB::bind_method(D_METHOD("set_tile_offset_axis", "alignment"), &TileSet::set_tile_offset_axis);
3441 ClassDB::bind_method(D_METHOD("get_tile_offset_axis"), &TileSet::get_tile_offset_axis);
3442 ClassDB::bind_method(D_METHOD("set_tile_size", "size"), &TileSet::set_tile_size);
3443 ClassDB::bind_method(D_METHOD("get_tile_size"), &TileSet::get_tile_size);
3444
3445 ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_shape", PROPERTY_HINT_ENUM, "Square,Isometric,Half-Offset Square,Hexagon"), "set_tile_shape", "get_tile_shape");
3446 ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_layout", PROPERTY_HINT_ENUM, "Stacked,Stacked Offset,Stairs Right,Stairs Down,Diamond Right,Diamond Down"), "set_tile_layout", "get_tile_layout");
3447 ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_offset_axis", PROPERTY_HINT_ENUM, "Horizontal Offset,Vertical Offset"), "set_tile_offset_axis", "get_tile_offset_axis");
3448 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size", PROPERTY_HINT_NONE, "suffix:px"), "set_tile_size", "get_tile_size");
3449
3450 // Rendering.
3451 ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping);
3452 ClassDB::bind_method(D_METHOD("is_uv_clipping"), &TileSet::is_uv_clipping);
3453
3454 ClassDB::bind_method(D_METHOD("get_occlusion_layers_count"), &TileSet::get_occlusion_layers_count);
3455 ClassDB::bind_method(D_METHOD("add_occlusion_layer", "to_position"), &TileSet::add_occlusion_layer, DEFVAL(-1));
3456 ClassDB::bind_method(D_METHOD("move_occlusion_layer", "layer_index", "to_position"), &TileSet::move_occlusion_layer);
3457 ClassDB::bind_method(D_METHOD("remove_occlusion_layer", "layer_index"), &TileSet::remove_occlusion_layer);
3458 ClassDB::bind_method(D_METHOD("set_occlusion_layer_light_mask", "layer_index", "light_mask"), &TileSet::set_occlusion_layer_light_mask);
3459 ClassDB::bind_method(D_METHOD("get_occlusion_layer_light_mask", "layer_index"), &TileSet::get_occlusion_layer_light_mask);
3460 ClassDB::bind_method(D_METHOD("set_occlusion_layer_sdf_collision", "layer_index", "sdf_collision"), &TileSet::set_occlusion_layer_sdf_collision);
3461 ClassDB::bind_method(D_METHOD("get_occlusion_layer_sdf_collision", "layer_index"), &TileSet::get_occlusion_layer_sdf_collision);
3462
3463 // Physics
3464 ClassDB::bind_method(D_METHOD("get_physics_layers_count"), &TileSet::get_physics_layers_count);
3465 ClassDB::bind_method(D_METHOD("add_physics_layer", "to_position"), &TileSet::add_physics_layer, DEFVAL(-1));
3466 ClassDB::bind_method(D_METHOD("move_physics_layer", "layer_index", "to_position"), &TileSet::move_physics_layer);
3467 ClassDB::bind_method(D_METHOD("remove_physics_layer", "layer_index"), &TileSet::remove_physics_layer);
3468 ClassDB::bind_method(D_METHOD("set_physics_layer_collision_layer", "layer_index", "layer"), &TileSet::set_physics_layer_collision_layer);
3469 ClassDB::bind_method(D_METHOD("get_physics_layer_collision_layer", "layer_index"), &TileSet::get_physics_layer_collision_layer);
3470 ClassDB::bind_method(D_METHOD("set_physics_layer_collision_mask", "layer_index", "mask"), &TileSet::set_physics_layer_collision_mask);
3471 ClassDB::bind_method(D_METHOD("get_physics_layer_collision_mask", "layer_index"), &TileSet::get_physics_layer_collision_mask);
3472 ClassDB::bind_method(D_METHOD("set_physics_layer_physics_material", "layer_index", "physics_material"), &TileSet::set_physics_layer_physics_material);
3473 ClassDB::bind_method(D_METHOD("get_physics_layer_physics_material", "layer_index"), &TileSet::get_physics_layer_physics_material);
3474
3475 // Terrains
3476 ClassDB::bind_method(D_METHOD("get_terrain_sets_count"), &TileSet::get_terrain_sets_count);
3477 ClassDB::bind_method(D_METHOD("add_terrain_set", "to_position"), &TileSet::add_terrain_set, DEFVAL(-1));
3478 ClassDB::bind_method(D_METHOD("move_terrain_set", "terrain_set", "to_position"), &TileSet::move_terrain_set);
3479 ClassDB::bind_method(D_METHOD("remove_terrain_set", "terrain_set"), &TileSet::remove_terrain_set);
3480 ClassDB::bind_method(D_METHOD("set_terrain_set_mode", "terrain_set", "mode"), &TileSet::set_terrain_set_mode);
3481 ClassDB::bind_method(D_METHOD("get_terrain_set_mode", "terrain_set"), &TileSet::get_terrain_set_mode);
3482
3483 ClassDB::bind_method(D_METHOD("get_terrains_count", "terrain_set"), &TileSet::get_terrains_count);
3484 ClassDB::bind_method(D_METHOD("add_terrain", "terrain_set", "to_position"), &TileSet::add_terrain, DEFVAL(-1));
3485 ClassDB::bind_method(D_METHOD("move_terrain", "terrain_set", "terrain_index", "to_position"), &TileSet::move_terrain);
3486 ClassDB::bind_method(D_METHOD("remove_terrain", "terrain_set", "terrain_index"), &TileSet::remove_terrain);
3487 ClassDB::bind_method(D_METHOD("set_terrain_name", "terrain_set", "terrain_index", "name"), &TileSet::set_terrain_name);
3488 ClassDB::bind_method(D_METHOD("get_terrain_name", "terrain_set", "terrain_index"), &TileSet::get_terrain_name);
3489 ClassDB::bind_method(D_METHOD("set_terrain_color", "terrain_set", "terrain_index", "color"), &TileSet::set_terrain_color);
3490 ClassDB::bind_method(D_METHOD("get_terrain_color", "terrain_set", "terrain_index"), &TileSet::get_terrain_color);
3491
3492 // Navigation
3493 ClassDB::bind_method(D_METHOD("get_navigation_layers_count"), &TileSet::get_navigation_layers_count);
3494 ClassDB::bind_method(D_METHOD("add_navigation_layer", "to_position"), &TileSet::add_navigation_layer, DEFVAL(-1));
3495 ClassDB::bind_method(D_METHOD("move_navigation_layer", "layer_index", "to_position"), &TileSet::move_navigation_layer);
3496 ClassDB::bind_method(D_METHOD("remove_navigation_layer", "layer_index"), &TileSet::remove_navigation_layer);
3497 ClassDB::bind_method(D_METHOD("set_navigation_layer_layers", "layer_index", "layers"), &TileSet::set_navigation_layer_layers);
3498 ClassDB::bind_method(D_METHOD("get_navigation_layer_layers", "layer_index"), &TileSet::get_navigation_layer_layers);
3499 ClassDB::bind_method(D_METHOD("set_navigation_layer_layer_value", "layer_index", "layer_number", "value"), &TileSet::set_navigation_layer_layer_value);
3500 ClassDB::bind_method(D_METHOD("get_navigation_layer_layer_value", "layer_index", "layer_number"), &TileSet::get_navigation_layer_layer_value);
3501
3502 // Custom data
3503 ClassDB::bind_method(D_METHOD("get_custom_data_layers_count"), &TileSet::get_custom_data_layers_count);
3504 ClassDB::bind_method(D_METHOD("add_custom_data_layer", "to_position"), &TileSet::add_custom_data_layer, DEFVAL(-1));
3505 ClassDB::bind_method(D_METHOD("move_custom_data_layer", "layer_index", "to_position"), &TileSet::move_custom_data_layer);
3506 ClassDB::bind_method(D_METHOD("remove_custom_data_layer", "layer_index"), &TileSet::remove_custom_data_layer);
3507 ClassDB::bind_method(D_METHOD("get_custom_data_layer_by_name", "layer_name"), &TileSet::get_custom_data_layer_by_name);
3508 ClassDB::bind_method(D_METHOD("set_custom_data_layer_name", "layer_index", "layer_name"), &TileSet::set_custom_data_layer_name);
3509 ClassDB::bind_method(D_METHOD("get_custom_data_layer_name", "layer_index"), &TileSet::get_custom_data_layer_name);
3510 ClassDB::bind_method(D_METHOD("set_custom_data_layer_type", "layer_index", "layer_type"), &TileSet::set_custom_data_layer_type);
3511 ClassDB::bind_method(D_METHOD("get_custom_data_layer_type", "layer_index"), &TileSet::get_custom_data_layer_type);
3512
3513 // Tile proxies
3514 ClassDB::bind_method(D_METHOD("set_source_level_tile_proxy", "source_from", "source_to"), &TileSet::set_source_level_tile_proxy);
3515 ClassDB::bind_method(D_METHOD("get_source_level_tile_proxy", "source_from"), &TileSet::get_source_level_tile_proxy);
3516 ClassDB::bind_method(D_METHOD("has_source_level_tile_proxy", "source_from"), &TileSet::has_source_level_tile_proxy);
3517 ClassDB::bind_method(D_METHOD("remove_source_level_tile_proxy", "source_from"), &TileSet::remove_source_level_tile_proxy);
3518
3519 ClassDB::bind_method(D_METHOD("set_coords_level_tile_proxy", "p_source_from", "coords_from", "source_to", "coords_to"), &TileSet::set_coords_level_tile_proxy);
3520 ClassDB::bind_method(D_METHOD("get_coords_level_tile_proxy", "source_from", "coords_from"), &TileSet::get_coords_level_tile_proxy);
3521 ClassDB::bind_method(D_METHOD("has_coords_level_tile_proxy", "source_from", "coords_from"), &TileSet::has_coords_level_tile_proxy);
3522 ClassDB::bind_method(D_METHOD("remove_coords_level_tile_proxy", "source_from", "coords_from"), &TileSet::remove_coords_level_tile_proxy);
3523
3524 ClassDB::bind_method(D_METHOD("set_alternative_level_tile_proxy", "source_from", "coords_from", "alternative_from", "source_to", "coords_to", "alternative_to"), &TileSet::set_alternative_level_tile_proxy);
3525 ClassDB::bind_method(D_METHOD("get_alternative_level_tile_proxy", "source_from", "coords_from", "alternative_from"), &TileSet::get_alternative_level_tile_proxy);
3526 ClassDB::bind_method(D_METHOD("has_alternative_level_tile_proxy", "source_from", "coords_from", "alternative_from"), &TileSet::has_alternative_level_tile_proxy);
3527 ClassDB::bind_method(D_METHOD("remove_alternative_level_tile_proxy", "source_from", "coords_from", "alternative_from"), &TileSet::remove_alternative_level_tile_proxy);
3528
3529 ClassDB::bind_method(D_METHOD("map_tile_proxy", "source_from", "coords_from", "alternative_from"), &TileSet::map_tile_proxy);
3530
3531 ClassDB::bind_method(D_METHOD("cleanup_invalid_tile_proxies"), &TileSet::cleanup_invalid_tile_proxies);
3532 ClassDB::bind_method(D_METHOD("clear_tile_proxies"), &TileSet::clear_tile_proxies);
3533
3534 // Patterns
3535 ClassDB::bind_method(D_METHOD("add_pattern", "pattern", "index"), &TileSet::add_pattern, DEFVAL(-1));
3536 ClassDB::bind_method(D_METHOD("get_pattern", "index"), &TileSet::get_pattern, DEFVAL(-1));
3537 ClassDB::bind_method(D_METHOD("remove_pattern", "index"), &TileSet::remove_pattern);
3538 ClassDB::bind_method(D_METHOD("get_patterns_count"), &TileSet::get_patterns_count);
3539
3540 ADD_GROUP("Rendering", "");
3541 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
3542 ADD_ARRAY("occlusion_layers", "occlusion_layer_");
3543
3544 ADD_GROUP("", "");
3545 ADD_ARRAY("physics_layers", "physics_layer_");
3546 ADD_ARRAY("terrain_sets", "terrain_set_");
3547 ADD_ARRAY("navigation_layers", "navigation_layer_");
3548 ADD_ARRAY("custom_data_layers", "custom_data_layer_");
3549
3550 // -- Enum binding --
3551 BIND_ENUM_CONSTANT(TILE_SHAPE_SQUARE);
3552 BIND_ENUM_CONSTANT(TILE_SHAPE_ISOMETRIC);
3553 BIND_ENUM_CONSTANT(TILE_SHAPE_HALF_OFFSET_SQUARE);
3554 BIND_ENUM_CONSTANT(TILE_SHAPE_HEXAGON);
3555
3556 BIND_ENUM_CONSTANT(TILE_LAYOUT_STACKED);
3557 BIND_ENUM_CONSTANT(TILE_LAYOUT_STACKED_OFFSET);
3558 BIND_ENUM_CONSTANT(TILE_LAYOUT_STAIRS_RIGHT);
3559 BIND_ENUM_CONSTANT(TILE_LAYOUT_STAIRS_DOWN);
3560 BIND_ENUM_CONSTANT(TILE_LAYOUT_DIAMOND_RIGHT);
3561 BIND_ENUM_CONSTANT(TILE_LAYOUT_DIAMOND_DOWN);
3562
3563 BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_HORIZONTAL);
3564 BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_VERTICAL);
3565
3566 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_RIGHT_SIDE);
3567 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_RIGHT_CORNER);
3568 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE);
3569 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER);
3570 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_SIDE);
3571 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_CORNER);
3572 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
3573 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_LEFT_CORNER);
3574 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_LEFT_SIDE);
3575 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_LEFT_CORNER);
3576 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_LEFT_SIDE);
3577 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_LEFT_CORNER);
3578 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_SIDE);
3579 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_CORNER);
3580 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_RIGHT_SIDE);
3581 BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_RIGHT_CORNER);
3582
3583 BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS_AND_SIDES);
3584 BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS);
3585 BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_SIDES);
3586}
3587
3588TileSet::TileSet() {
3589 // Instantiate the tile meshes.
3590 tile_lines_mesh.instantiate();
3591 tile_filled_mesh.instantiate();
3592}
3593
3594TileSet::~TileSet() {
3595#ifndef DISABLE_DEPRECATED
3596 for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
3597 memdelete(E.value);
3598 }
3599#endif // DISABLE_DEPRECATED
3600 while (!source_ids.is_empty()) {
3601 remove_source(source_ids[0]);
3602 }
3603}
3604
3605/////////////////////////////// TileSetSource //////////////////////////////////////
3606
3607void TileSetSource::set_tile_set(const TileSet *p_tile_set) {
3608 tile_set = p_tile_set;
3609}
3610
3611TileSet *TileSetSource::get_tile_set() const {
3612 return (TileSet *)tile_set;
3613}
3614
3615void TileSetSource::reset_state() {
3616 tile_set = nullptr;
3617};
3618
3619void TileSetSource::_bind_methods() {
3620 // Base tiles
3621 ClassDB::bind_method(D_METHOD("get_tiles_count"), &TileSetSource::get_tiles_count);
3622 ClassDB::bind_method(D_METHOD("get_tile_id", "index"), &TileSetSource::get_tile_id);
3623 ClassDB::bind_method(D_METHOD("has_tile", "atlas_coords"), &TileSetSource::has_tile);
3624
3625 // Alternative tiles
3626 ClassDB::bind_method(D_METHOD("get_alternative_tiles_count", "atlas_coords"), &TileSetSource::get_alternative_tiles_count);
3627 ClassDB::bind_method(D_METHOD("get_alternative_tile_id", "atlas_coords", "index"), &TileSetSource::get_alternative_tile_id);
3628 ClassDB::bind_method(D_METHOD("has_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetSource::has_alternative_tile);
3629}
3630
3631/////////////////////////////// TileSetAtlasSource //////////////////////////////////////
3632
3633void TileSetAtlasSource::set_tile_set(const TileSet *p_tile_set) {
3634 tile_set = p_tile_set;
3635
3636 // Set the TileSet on all TileData.
3637 for (KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
3638 for (KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) {
3639 E_alternative.value->set_tile_set(tile_set);
3640 }
3641 }
3642}
3643
3644const TileSet *TileSetAtlasSource::get_tile_set() const {
3645 return tile_set;
3646}
3647
3648void TileSetAtlasSource::notify_tile_data_properties_should_change() {
3649 // Set the TileSet on all TileData.
3650 for (KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
3651 for (KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) {
3652 E_alternative.value->notify_tile_data_properties_should_change();
3653 }
3654 }
3655}
3656
3657void TileSetAtlasSource::add_occlusion_layer(int p_to_pos) {
3658 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3659 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3660 E_alternative.value->add_occlusion_layer(p_to_pos);
3661 }
3662 }
3663}
3664
3665void TileSetAtlasSource::move_occlusion_layer(int p_from_index, int p_to_pos) {
3666 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3667 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3668 E_alternative.value->move_occlusion_layer(p_from_index, p_to_pos);
3669 }
3670 }
3671}
3672
3673void TileSetAtlasSource::remove_occlusion_layer(int p_index) {
3674 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3675 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3676 E_alternative.value->remove_occlusion_layer(p_index);
3677 }
3678 }
3679}
3680
3681void TileSetAtlasSource::add_physics_layer(int p_to_pos) {
3682 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3683 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3684 E_alternative.value->add_physics_layer(p_to_pos);
3685 }
3686 }
3687}
3688
3689void TileSetAtlasSource::move_physics_layer(int p_from_index, int p_to_pos) {
3690 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3691 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3692 E_alternative.value->move_physics_layer(p_from_index, p_to_pos);
3693 }
3694 }
3695}
3696
3697void TileSetAtlasSource::remove_physics_layer(int p_index) {
3698 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3699 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3700 E_alternative.value->remove_physics_layer(p_index);
3701 }
3702 }
3703}
3704
3705void TileSetAtlasSource::add_terrain_set(int p_to_pos) {
3706 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3707 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3708 E_alternative.value->add_terrain_set(p_to_pos);
3709 }
3710 }
3711}
3712
3713void TileSetAtlasSource::move_terrain_set(int p_from_index, int p_to_pos) {
3714 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3715 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3716 E_alternative.value->move_terrain_set(p_from_index, p_to_pos);
3717 }
3718 }
3719}
3720
3721void TileSetAtlasSource::remove_terrain_set(int p_index) {
3722 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3723 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3724 E_alternative.value->remove_terrain_set(p_index);
3725 }
3726 }
3727}
3728
3729void TileSetAtlasSource::add_terrain(int p_terrain_set, int p_to_pos) {
3730 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3731 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3732 E_alternative.value->add_terrain(p_terrain_set, p_to_pos);
3733 }
3734 }
3735}
3736
3737void TileSetAtlasSource::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
3738 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3739 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3740 E_alternative.value->move_terrain(p_terrain_set, p_from_index, p_to_pos);
3741 }
3742 }
3743}
3744
3745void TileSetAtlasSource::remove_terrain(int p_terrain_set, int p_index) {
3746 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3747 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3748 E_alternative.value->remove_terrain(p_terrain_set, p_index);
3749 }
3750 }
3751}
3752
3753void TileSetAtlasSource::add_navigation_layer(int p_to_pos) {
3754 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3755 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3756 E_alternative.value->add_navigation_layer(p_to_pos);
3757 }
3758 }
3759}
3760
3761void TileSetAtlasSource::move_navigation_layer(int p_from_index, int p_to_pos) {
3762 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3763 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3764 E_alternative.value->move_navigation_layer(p_from_index, p_to_pos);
3765 }
3766 }
3767}
3768
3769void TileSetAtlasSource::remove_navigation_layer(int p_index) {
3770 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3771 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3772 E_alternative.value->remove_navigation_layer(p_index);
3773 }
3774 }
3775}
3776
3777void TileSetAtlasSource::add_custom_data_layer(int p_to_pos) {
3778 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3779 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3780 E_alternative.value->add_custom_data_layer(p_to_pos);
3781 }
3782 }
3783}
3784
3785void TileSetAtlasSource::move_custom_data_layer(int p_from_index, int p_to_pos) {
3786 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3787 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3788 E_alternative.value->move_custom_data_layer(p_from_index, p_to_pos);
3789 }
3790 }
3791}
3792
3793void TileSetAtlasSource::remove_custom_data_layer(int p_index) {
3794 for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
3795 for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
3796 E_alternative.value->remove_custom_data_layer(p_index);
3797 }
3798 }
3799}
3800
3801void TileSetAtlasSource::reset_state() {
3802 tile_set = nullptr;
3803
3804 for (KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
3805 for (const KeyValue<int, TileData *> &E_tile_data : E_tile.value.alternatives) {
3806 memdelete(E_tile_data.value);
3807 }
3808 }
3809 _coords_mapping_cache.clear();
3810 tiles.clear();
3811 tiles_ids.clear();
3812 _queue_update_padded_texture();
3813}
3814
3815void TileSetAtlasSource::set_texture(Ref<Texture2D> p_texture) {
3816 if (texture.is_valid()) {
3817 texture->disconnect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
3818 }
3819
3820 texture = p_texture;
3821
3822 if (texture.is_valid()) {
3823 texture->connect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
3824 }
3825
3826 _queue_update_padded_texture();
3827 emit_changed();
3828}
3829
3830Ref<Texture2D> TileSetAtlasSource::get_texture() const {
3831 return texture;
3832}
3833
3834void TileSetAtlasSource::set_margins(Vector2i p_margins) {
3835 if (p_margins.x < 0 || p_margins.y < 0) {
3836 WARN_PRINT("Atlas source margins should be positive.");
3837 margins = Vector2i(MAX(0, p_margins.x), MAX(0, p_margins.y));
3838 } else {
3839 margins = p_margins;
3840 }
3841
3842 _queue_update_padded_texture();
3843 emit_changed();
3844}
3845
3846Vector2i TileSetAtlasSource::get_margins() const {
3847 return margins;
3848}
3849
3850void TileSetAtlasSource::set_separation(Vector2i p_separation) {
3851 if (p_separation.x < 0 || p_separation.y < 0) {
3852 WARN_PRINT("Atlas source separation should be positive.");
3853 separation = Vector2i(MAX(0, p_separation.x), MAX(0, p_separation.y));
3854 } else {
3855 separation = p_separation;
3856 }
3857
3858 _queue_update_padded_texture();
3859 emit_changed();
3860}
3861
3862Vector2i TileSetAtlasSource::get_separation() const {
3863 return separation;
3864}
3865
3866void TileSetAtlasSource::set_texture_region_size(Vector2i p_tile_size) {
3867 if (p_tile_size.x <= 0 || p_tile_size.y <= 0) {
3868 WARN_PRINT("Atlas source tile_size should be strictly positive.");
3869 texture_region_size = Vector2i(MAX(1, p_tile_size.x), MAX(1, p_tile_size.y));
3870 } else {
3871 texture_region_size = p_tile_size;
3872 }
3873
3874 _queue_update_padded_texture();
3875 emit_changed();
3876}
3877
3878Vector2i TileSetAtlasSource::get_texture_region_size() const {
3879 return texture_region_size;
3880}
3881
3882void TileSetAtlasSource::set_use_texture_padding(bool p_use_padding) {
3883 if (use_texture_padding == p_use_padding) {
3884 return;
3885 }
3886 use_texture_padding = p_use_padding;
3887 _queue_update_padded_texture();
3888 emit_changed();
3889}
3890
3891bool TileSetAtlasSource::get_use_texture_padding() const {
3892 return use_texture_padding;
3893}
3894
3895Vector2i TileSetAtlasSource::get_atlas_grid_size() const {
3896 Ref<Texture2D> txt = get_texture();
3897 if (!txt.is_valid()) {
3898 return Vector2i();
3899 }
3900
3901 ERR_FAIL_COND_V(texture_region_size.x <= 0 || texture_region_size.y <= 0, Vector2i());
3902
3903 Size2i valid_area = txt->get_size() - margins;
3904
3905 // Compute the number of valid tiles in the tiles atlas
3906 Size2i grid_size;
3907 if (valid_area.x >= texture_region_size.x && valid_area.y >= texture_region_size.y) {
3908 valid_area -= texture_region_size;
3909 grid_size = Size2i(1, 1) + valid_area / (texture_region_size + separation);
3910 }
3911 return grid_size;
3912}
3913
3914bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) {
3915 Vector<String> components = String(p_name).split("/", true, 2);
3916
3917 // Compute the vector2i if we have coordinates.
3918 Vector<String> coords_split = components[0].split(":");
3919 Vector2i coords = TileSetSource::INVALID_ATLAS_COORDS;
3920 if (coords_split.size() == 2 && coords_split[0].is_valid_int() && coords_split[1].is_valid_int()) {
3921 coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int());
3922 }
3923
3924 // Properties.
3925 if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
3926 // Create the tile if needed.
3927 if (!has_tile(coords)) {
3928 create_tile(coords);
3929 }
3930 if (components.size() >= 2) {
3931 // Properties.
3932 if (components[1] == "size_in_atlas") {
3933 move_tile_in_atlas(coords, coords, p_value);
3934 return true;
3935 } else if (components[1] == "next_alternative_id") {
3936 tiles[coords].next_alternative_id = p_value;
3937 return true;
3938 } else if (components[1] == "animation_columns") {
3939 set_tile_animation_columns(coords, p_value);
3940 return true;
3941 } else if (components[1] == "animation_separation") {
3942 set_tile_animation_separation(coords, p_value);
3943 return true;
3944 } else if (components[1] == "animation_speed") {
3945 set_tile_animation_speed(coords, p_value);
3946 return true;
3947 } else if (components[1] == "animation_mode") {
3948 set_tile_animation_mode(coords, VariantCaster<TileSetAtlasSource::TileAnimationMode>::cast(p_value));
3949 return true;
3950 } else if (components[1] == "animation_frames_count") {
3951 set_tile_animation_frames_count(coords, p_value);
3952 return true;
3953 } else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) {
3954 int frame = components[1].trim_prefix("animation_frame_").to_int();
3955 if (components[2] == "duration") {
3956 if (frame >= get_tile_animation_frames_count(coords)) {
3957 set_tile_animation_frames_count(coords, frame + 1);
3958 }
3959 set_tile_animation_frame_duration(coords, frame, p_value);
3960 return true;
3961 }
3962 return false;
3963 } else if (components[1].is_valid_int()) {
3964 int alternative_id = components[1].to_int();
3965 if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
3966 // Create the alternative if needed ?
3967 if (!has_alternative_tile(coords, alternative_id)) {
3968 create_alternative_tile(coords, alternative_id);
3969 }
3970 if (!tiles[coords].alternatives.has(alternative_id)) {
3971 tiles[coords].alternatives[alternative_id] = memnew(TileData);
3972 tiles[coords].alternatives[alternative_id]->set_tile_set(tile_set);
3973 tiles[coords].alternatives[alternative_id]->set_allow_transform(alternative_id > 0);
3974 tiles[coords].alternatives_ids.push_back(alternative_id);
3975 }
3976 if (components.size() >= 3) {
3977 bool valid;
3978 tiles[coords].alternatives[alternative_id]->set(components[2], p_value, &valid);
3979 return valid;
3980 } else {
3981 // Only create the alternative if it did not exist yet.
3982 return true;
3983 }
3984 }
3985 }
3986 }
3987 }
3988
3989 return false;
3990}
3991
3992bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const {
3993 Vector<String> components = String(p_name).split("/", true, 2);
3994
3995 // Properties.
3996 Vector<String> coords_split = components[0].split(":");
3997 if (coords_split.size() == 2 && coords_split[0].is_valid_int() && coords_split[1].is_valid_int()) {
3998 Vector2i coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int());
3999 if (tiles.has(coords)) {
4000 if (components.size() >= 2) {
4001 // Properties.
4002 if (components[1] == "size_in_atlas") {
4003 r_ret = tiles[coords].size_in_atlas;
4004 return true;
4005 } else if (components[1] == "next_alternative_id") {
4006 r_ret = tiles[coords].next_alternative_id;
4007 return true;
4008 } else if (components[1] == "animation_columns") {
4009 r_ret = get_tile_animation_columns(coords);
4010 return true;
4011 } else if (components[1] == "animation_separation") {
4012 r_ret = get_tile_animation_separation(coords);
4013 return true;
4014 } else if (components[1] == "animation_speed") {
4015 r_ret = get_tile_animation_speed(coords);
4016 return true;
4017 } else if (components[1] == "animation_mode") {
4018 r_ret = get_tile_animation_mode(coords);
4019 return true;
4020 } else if (components[1] == "animation_frames_count") {
4021 r_ret = get_tile_animation_frames_count(coords);
4022 return true;
4023 } else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) {
4024 int frame = components[1].trim_prefix("animation_frame_").to_int();
4025 if (frame < 0 || frame >= get_tile_animation_frames_count(coords)) {
4026 return false;
4027 }
4028 if (components[2] == "duration") {
4029 r_ret = get_tile_animation_frame_duration(coords, frame);
4030 return true;
4031 }
4032 return false;
4033 } else if (components[1].is_valid_int()) {
4034 int alternative_id = components[1].to_int();
4035 if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) {
4036 if (components.size() >= 3) {
4037 bool valid;
4038 r_ret = tiles[coords].alternatives[alternative_id]->get(components[2], &valid);
4039 return valid;
4040 } else {
4041 // Only to notify the tile alternative exists.
4042 r_ret = alternative_id;
4043 return true;
4044 }
4045 }
4046 }
4047 }
4048 }
4049 }
4050
4051 return false;
4052}
4053
4054void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
4055 // Atlases data.
4056 PropertyInfo property_info;
4057 for (const KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
4058 List<PropertyInfo> tile_property_list;
4059
4060 // size_in_atlas
4061 property_info = PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4062 if (E_tile.value.size_in_atlas == Vector2i(1, 1)) {
4063 property_info.usage ^= PROPERTY_USAGE_STORAGE;
4064 }
4065 tile_property_list.push_back(property_info);
4066
4067 // next_alternative_id
4068 property_info = PropertyInfo(Variant::INT, "next_alternative_id", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4069 if (E_tile.value.next_alternative_id == 1) {
4070 property_info.usage ^= PROPERTY_USAGE_STORAGE;
4071 }
4072 tile_property_list.push_back(property_info);
4073
4074 // animation_columns.
4075 property_info = PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4076 if (E_tile.value.animation_columns == 0) {
4077 property_info.usage ^= PROPERTY_USAGE_STORAGE;
4078 }
4079 tile_property_list.push_back(property_info);
4080
4081 // animation_separation.
4082 property_info = PropertyInfo(Variant::INT, "animation_separation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4083 if (E_tile.value.animation_separation == Vector2i()) {
4084 property_info.usage ^= PROPERTY_USAGE_STORAGE;
4085 }
4086 tile_property_list.push_back(property_info);
4087
4088 // animation_speed.
4089 property_info = PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4090 if (E_tile.value.animation_speed == 1.0) {
4091 property_info.usage ^= PROPERTY_USAGE_STORAGE;
4092 }
4093 tile_property_list.push_back(property_info);
4094
4095 // animation_mode.
4096 property_info = PropertyInfo(Variant::INT, "animation_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4097 if (E_tile.value.animation_mode == TILE_ANIMATION_MODE_DEFAULT) {
4098 property_info.usage ^= PROPERTY_USAGE_STORAGE;
4099 }
4100 tile_property_list.push_back(property_info);
4101
4102 // animation_frames_count.
4103 tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
4104
4105 // animation_frame_*.
4106 bool store_durations = tiles[E_tile.key].animation_frames_durations.size() >= 2;
4107 for (int i = 0; i < (int)tiles[E_tile.key].animation_frames_durations.size(); i++) {
4108 property_info = PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4109 if (!store_durations) {
4110 property_info.usage ^= PROPERTY_USAGE_STORAGE;
4111 }
4112 tile_property_list.push_back(property_info);
4113 }
4114
4115 for (const KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) {
4116 // Add a dummy property to show the alternative exists.
4117 tile_property_list.push_back(PropertyInfo(Variant::INT, vformat("%d", E_alternative.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
4118
4119 // Get the alternative tile's properties and append them to the list of properties.
4120 List<PropertyInfo> alternative_property_list;
4121 E_alternative.value->get_property_list(&alternative_property_list);
4122 for (PropertyInfo &alternative_property_info : alternative_property_list) {
4123 Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name);
4124 Variant value = E_alternative.value->get(alternative_property_info.name);
4125 if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
4126 alternative_property_info.usage ^= PROPERTY_USAGE_STORAGE;
4127 }
4128 alternative_property_info.name = vformat("%s/%s", vformat("%d", E_alternative.key), alternative_property_info.name);
4129 tile_property_list.push_back(alternative_property_info);
4130 }
4131 }
4132
4133 // Add all alternative.
4134 for (PropertyInfo &tile_property_info : tile_property_list) {
4135 tile_property_info.name = vformat("%s/%s", vformat("%d:%d", E_tile.key.x, E_tile.key.y), tile_property_info.name);
4136 p_list->push_back(tile_property_info);
4137 }
4138 }
4139}
4140
4141void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector2i p_size) {
4142 // Create a tile if it does not exists.
4143 ERR_FAIL_COND(p_atlas_coords.x < 0 || p_atlas_coords.y < 0);
4144 ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0);
4145
4146 bool room_for_tile = has_room_for_tile(p_atlas_coords, p_size, 1, Vector2i(), 1);
4147 ERR_FAIL_COND_MSG(!room_for_tile, "Cannot create tile. The tile is outside the texture or tiles are already present in the space the tile would cover.");
4148
4149 // Initialize the tile data.
4150 TileAlternativesData tad;
4151 tad.size_in_atlas = p_size;
4152 tad.animation_frames_durations.push_back(1.0);
4153 tad.alternatives[0] = memnew(TileData);
4154 tad.alternatives[0]->set_tile_set(tile_set);
4155 tad.alternatives[0]->set_allow_transform(false);
4156 tad.alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
4157 tad.alternatives[0]->notify_property_list_changed();
4158 tad.alternatives_ids.push_back(0);
4159
4160 // Create and resize the tile.
4161 tiles.insert(p_atlas_coords, tad);
4162 tiles_ids.push_back(p_atlas_coords);
4163 tiles_ids.sort();
4164
4165 _create_coords_mapping_cache(p_atlas_coords);
4166 _queue_update_padded_texture();
4167
4168 emit_signal(SNAME("changed"));
4169}
4170
4171void TileSetAtlasSource::remove_tile(Vector2i p_atlas_coords) {
4172 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4173
4174 // Remove all covered positions from the mapping cache
4175 _clear_coords_mapping_cache(p_atlas_coords);
4176
4177 // Free tile data.
4178 for (const KeyValue<int, TileData *> &E_tile_data : tiles[p_atlas_coords].alternatives) {
4179 memdelete(E_tile_data.value);
4180 }
4181
4182 // Delete the tile
4183 tiles.erase(p_atlas_coords);
4184 tiles_ids.erase(p_atlas_coords);
4185 tiles_ids.sort();
4186
4187 _queue_update_padded_texture();
4188
4189 emit_signal(SNAME("changed"));
4190}
4191
4192bool TileSetAtlasSource::has_tile(Vector2i p_atlas_coords) const {
4193 return tiles.has(p_atlas_coords);
4194}
4195
4196Vector2i TileSetAtlasSource::get_tile_at_coords(Vector2i p_atlas_coords) const {
4197 if (!_coords_mapping_cache.has(p_atlas_coords)) {
4198 return INVALID_ATLAS_COORDS;
4199 }
4200
4201 return _coords_mapping_cache[p_atlas_coords];
4202}
4203
4204void TileSetAtlasSource::set_tile_animation_columns(const Vector2i p_atlas_coords, int p_frame_columns) {
4205 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4206 ERR_FAIL_COND(p_frame_columns < 0);
4207
4208 TileAlternativesData &tad = tiles[p_atlas_coords];
4209 bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, p_frame_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords);
4210 ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
4211
4212 _clear_coords_mapping_cache(p_atlas_coords);
4213
4214 tiles[p_atlas_coords].animation_columns = p_frame_columns;
4215
4216 _create_coords_mapping_cache(p_atlas_coords);
4217 _queue_update_padded_texture();
4218
4219 emit_signal(SNAME("changed"));
4220}
4221
4222int TileSetAtlasSource::get_tile_animation_columns(const Vector2i p_atlas_coords) const {
4223 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4224 return tiles[p_atlas_coords].animation_columns;
4225}
4226
4227void TileSetAtlasSource::set_tile_animation_separation(const Vector2i p_atlas_coords, const Vector2i p_separation) {
4228 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4229 ERR_FAIL_COND(p_separation.x < 0 || p_separation.y < 0);
4230
4231 TileAlternativesData &tad = tiles[p_atlas_coords];
4232 bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, p_separation, tad.animation_frames_durations.size(), p_atlas_coords);
4233 ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
4234
4235 _clear_coords_mapping_cache(p_atlas_coords);
4236
4237 tiles[p_atlas_coords].animation_separation = p_separation;
4238
4239 _create_coords_mapping_cache(p_atlas_coords);
4240 _queue_update_padded_texture();
4241
4242 emit_signal(SNAME("changed"));
4243}
4244
4245Vector2i TileSetAtlasSource::get_tile_animation_separation(const Vector2i p_atlas_coords) const {
4246 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4247 return tiles[p_atlas_coords].animation_separation;
4248}
4249
4250void TileSetAtlasSource::set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed) {
4251 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4252 ERR_FAIL_COND(p_speed <= 0);
4253
4254 tiles[p_atlas_coords].animation_speed = p_speed;
4255
4256 emit_signal(SNAME("changed"));
4257}
4258
4259real_t TileSetAtlasSource::get_tile_animation_speed(const Vector2i p_atlas_coords) const {
4260 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1.0, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4261 return tiles[p_atlas_coords].animation_speed;
4262}
4263
4264void TileSetAtlasSource::set_tile_animation_mode(const Vector2i p_atlas_coords, TileSetAtlasSource::TileAnimationMode p_mode) {
4265 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4266
4267 tiles[p_atlas_coords].animation_mode = p_mode;
4268
4269 emit_signal(SNAME("changed"));
4270}
4271
4272TileSetAtlasSource::TileAnimationMode TileSetAtlasSource::get_tile_animation_mode(const Vector2i p_atlas_coords) const {
4273 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TILE_ANIMATION_MODE_DEFAULT, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4274
4275 return tiles[p_atlas_coords].animation_mode;
4276}
4277
4278void TileSetAtlasSource::set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count) {
4279 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4280 ERR_FAIL_COND(p_frames_count < 1);
4281
4282 int old_size = tiles[p_atlas_coords].animation_frames_durations.size();
4283 if (p_frames_count == old_size) {
4284 return;
4285 }
4286
4287 TileAlternativesData &tad = tiles[p_atlas_coords];
4288 bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, tad.animation_separation, p_frames_count, p_atlas_coords);
4289 ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
4290
4291 _clear_coords_mapping_cache(p_atlas_coords);
4292
4293 tiles[p_atlas_coords].animation_frames_durations.resize(p_frames_count);
4294 for (int i = old_size; i < p_frames_count; i++) {
4295 tiles[p_atlas_coords].animation_frames_durations[i] = 1.0;
4296 }
4297
4298 _create_coords_mapping_cache(p_atlas_coords);
4299 _queue_update_padded_texture();
4300
4301 notify_property_list_changed();
4302
4303 emit_signal(SNAME("changed"));
4304}
4305
4306int TileSetAtlasSource::get_tile_animation_frames_count(const Vector2i p_atlas_coords) const {
4307 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4308 return tiles[p_atlas_coords].animation_frames_durations.size();
4309}
4310
4311void TileSetAtlasSource::set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration) {
4312 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4313 ERR_FAIL_INDEX(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size());
4314 ERR_FAIL_COND(p_duration <= 0.0);
4315
4316 tiles[p_atlas_coords].animation_frames_durations[p_frame_index] = p_duration;
4317
4318 emit_signal(SNAME("changed"));
4319}
4320
4321real_t TileSetAtlasSource::get_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index) const {
4322 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4323 ERR_FAIL_INDEX_V(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size(), 0.0);
4324 return tiles[p_atlas_coords].animation_frames_durations[p_frame_index];
4325}
4326
4327real_t TileSetAtlasSource::get_tile_animation_total_duration(const Vector2i p_atlas_coords) const {
4328 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4329
4330 real_t sum = 0.0;
4331 for (const real_t &duration : tiles[p_atlas_coords].animation_frames_durations) {
4332 sum += duration;
4333 }
4334 return sum;
4335}
4336
4337Vector2i TileSetAtlasSource::get_tile_size_in_atlas(Vector2i p_atlas_coords) const {
4338 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(-1, -1), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4339
4340 return tiles[p_atlas_coords].size_in_atlas;
4341}
4342
4343int TileSetAtlasSource::get_tiles_count() const {
4344 return tiles_ids.size();
4345}
4346
4347Vector2i TileSetAtlasSource::get_tile_id(int p_index) const {
4348 ERR_FAIL_INDEX_V(p_index, tiles_ids.size(), TileSetSource::INVALID_ATLAS_COORDS);
4349 return tiles_ids[p_index];
4350}
4351
4352bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile) const {
4353 if (p_atlas_coords.x < 0 || p_atlas_coords.y < 0) {
4354 return false;
4355 }
4356 if (p_size.x <= 0 || p_size.y <= 0) {
4357 return false;
4358 }
4359 if (p_frames_count <= 0) {
4360 return false;
4361 }
4362 Size2i atlas_grid_size = get_atlas_grid_size();
4363 for (int frame = 0; frame < p_frames_count; frame++) {
4364 Vector2i frame_coords = p_atlas_coords + (p_size + p_animation_separation) * ((p_animation_columns > 0) ? Vector2i(frame % p_animation_columns, frame / p_animation_columns) : Vector2i(frame, 0));
4365 for (int x = 0; x < p_size.x; x++) {
4366 for (int y = 0; y < p_size.y; y++) {
4367 Vector2i coords = frame_coords + Vector2i(x, y);
4368 if (_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] != p_ignored_tile) {
4369 return false;
4370 }
4371 if (coords.x >= atlas_grid_size.x || coords.y >= atlas_grid_size.y) {
4372 return false;
4373 }
4374 }
4375 }
4376 }
4377 return true;
4378}
4379
4380bool TileSetAtlasSource::has_tiles_outside_texture() const {
4381 for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
4382 if (!has_room_for_tile(E.key, E.value.size_in_atlas, E.value.animation_columns, E.value.animation_separation, E.value.animation_frames_durations.size(), E.key)) {
4383 return true;
4384 }
4385 }
4386 return false;
4387}
4388
4389Vector<Vector2i> TileSetAtlasSource::get_tiles_outside_texture() const {
4390 Vector<Vector2i> to_return;
4391
4392 for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
4393 if (!has_room_for_tile(E.key, E.value.size_in_atlas, E.value.animation_columns, E.value.animation_separation, E.value.animation_frames_durations.size(), E.key)) {
4394 to_return.push_back(E.key);
4395 }
4396 }
4397 return to_return;
4398}
4399
4400void TileSetAtlasSource::clear_tiles_outside_texture() {
4401 LocalVector<Vector2i> to_remove;
4402
4403 for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
4404 if (!has_room_for_tile(E.key, E.value.size_in_atlas, E.value.animation_columns, E.value.animation_separation, E.value.animation_frames_durations.size(), E.key)) {
4405 to_remove.push_back(E.key);
4406 }
4407 }
4408
4409 for (const Vector2i &v : to_remove) {
4410 remove_tile(v);
4411 }
4412}
4413
4414PackedVector2Array TileSetAtlasSource::get_tiles_to_be_removed_on_change(Ref<Texture2D> p_texture, Vector2i p_margins, Vector2i p_separation, Vector2i p_texture_region_size) {
4415 ERR_FAIL_COND_V(p_margins.x < 0 || p_margins.y < 0, PackedVector2Array());
4416 ERR_FAIL_COND_V(p_separation.x < 0 || p_separation.y < 0, PackedVector2Array());
4417 ERR_FAIL_COND_V(p_texture_region_size.x <= 0 || p_texture_region_size.y <= 0, PackedVector2Array());
4418
4419 // Compute the new atlas grid size.
4420 Size2 new_grid_size;
4421 if (p_texture.is_valid()) {
4422 Size2i valid_area = p_texture->get_size() - p_margins;
4423
4424 // Compute the number of valid tiles in the tiles atlas
4425 if (valid_area.x >= p_texture_region_size.x && valid_area.y >= p_texture_region_size.y) {
4426 valid_area -= p_texture_region_size;
4427 new_grid_size = Size2i(1, 1) + valid_area / (p_texture_region_size + p_separation);
4428 }
4429 }
4430
4431 Vector<Vector2> output;
4432 for (KeyValue<Vector2i, TileAlternativesData> &E : tiles) {
4433 for (unsigned int frame = 0; frame < E.value.animation_frames_durations.size(); frame++) {
4434 Vector2i frame_coords = E.key + (E.value.size_in_atlas + E.value.animation_separation) * ((E.value.animation_columns > 0) ? Vector2i(frame % E.value.animation_columns, frame / E.value.animation_columns) : Vector2i(frame, 0));
4435 frame_coords += E.value.size_in_atlas;
4436 if (frame_coords.x > new_grid_size.x || frame_coords.y > new_grid_size.y) {
4437 output.push_back(E.key);
4438 break;
4439 }
4440 }
4441 }
4442 return output;
4443}
4444
4445Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords, int p_frame) const {
4446 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4447 ERR_FAIL_INDEX_V(p_frame, (int)tiles[p_atlas_coords].animation_frames_durations.size(), Rect2i());
4448
4449 const TileAlternativesData &tad = tiles[p_atlas_coords];
4450
4451 Vector2i size_in_atlas = tad.size_in_atlas;
4452 Vector2 region_size = texture_region_size * size_in_atlas + separation * (size_in_atlas - Vector2i(1, 1));
4453
4454 Vector2i frame_coords = p_atlas_coords + (size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(p_frame % tad.animation_columns, p_frame / tad.animation_columns) : Vector2i(p_frame, 0));
4455 Vector2 origin = margins + (frame_coords * (texture_region_size + separation));
4456
4457 return Rect2(origin, region_size);
4458}
4459
4460bool TileSetAtlasSource::is_position_in_tile_texture_region(const Vector2i p_atlas_coords, int p_alternative_tile, Vector2 p_position) const {
4461 Size2 size = get_tile_texture_region(p_atlas_coords).size;
4462 Rect2 rect = Rect2(-size / 2 - get_tile_data(p_atlas_coords, p_alternative_tile)->get_texture_origin(), size);
4463
4464 return rect.has_point(p_position);
4465}
4466
4467int TileSetAtlasSource::alternative_no_transform(int p_alternative_id) {
4468 return p_alternative_id & ~(TRANSFORM_FLIP_H | TRANSFORM_FLIP_V | TRANSFORM_TRANSPOSE);
4469}
4470
4471// Getters for texture and tile region (padded or not)
4472Ref<Texture2D> TileSetAtlasSource::get_runtime_texture() const {
4473 if (use_texture_padding) {
4474 return padded_texture;
4475 } else {
4476 return texture;
4477 }
4478}
4479
4480Rect2i TileSetAtlasSource::get_runtime_tile_texture_region(Vector2i p_atlas_coords, int p_frame) const {
4481 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4482 ERR_FAIL_INDEX_V(p_frame, (int)tiles[p_atlas_coords].animation_frames_durations.size(), Rect2i());
4483
4484 Rect2i src_rect = get_tile_texture_region(p_atlas_coords, p_frame);
4485 if (use_texture_padding) {
4486 const TileAlternativesData &tad = tiles[p_atlas_coords];
4487 Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(p_frame % tad.animation_columns, p_frame / tad.animation_columns) : Vector2i(p_frame, 0));
4488 Vector2i base_pos = frame_coords * (texture_region_size + Vector2i(2, 2)) + Vector2i(1, 1);
4489
4490 return Rect2i(base_pos, src_rect.size);
4491 } else {
4492 return src_rect;
4493 }
4494}
4495
4496void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) {
4497 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4498
4499 TileAlternativesData &tad = tiles[p_atlas_coords];
4500
4501 // Compute the actual new rect from arguments.
4502 Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords;
4503 Vector2i new_size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tad.size_in_atlas;
4504
4505 if (new_atlas_coords == p_atlas_coords && new_size == tad.size_in_atlas) {
4506 return;
4507 }
4508
4509 bool room_for_tile = has_room_for_tile(new_atlas_coords, new_size, tad.animation_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords);
4510 ERR_FAIL_COND_MSG(!room_for_tile, vformat("Cannot move tile at position %s with size %s. Tile already present.", new_atlas_coords, new_size));
4511
4512 _clear_coords_mapping_cache(p_atlas_coords);
4513
4514 // Move the tile and update its size.
4515 if (new_atlas_coords != p_atlas_coords) {
4516 tiles[new_atlas_coords] = tiles[p_atlas_coords];
4517 tiles.erase(p_atlas_coords);
4518
4519 tiles_ids.erase(p_atlas_coords);
4520 tiles_ids.push_back(new_atlas_coords);
4521 tiles_ids.sort();
4522 }
4523 tiles[new_atlas_coords].size_in_atlas = new_size;
4524
4525 _create_coords_mapping_cache(new_atlas_coords);
4526 _queue_update_padded_texture();
4527
4528 emit_signal(SNAME("changed"));
4529}
4530
4531int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override) {
4532 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4533 ERR_FAIL_COND_V_MSG(p_alternative_id_override >= 0 && tiles[p_atlas_coords].alternatives.has(p_alternative_id_override), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("Cannot create alternative tile. Another alternative exists with id %d.", p_alternative_id_override));
4534
4535 int new_alternative_id = p_alternative_id_override >= 0 ? p_alternative_id_override : tiles[p_atlas_coords].next_alternative_id;
4536
4537 tiles[p_atlas_coords].alternatives[new_alternative_id] = memnew(TileData);
4538 tiles[p_atlas_coords].alternatives[new_alternative_id]->set_tile_set(tile_set);
4539 tiles[p_atlas_coords].alternatives[new_alternative_id]->set_allow_transform(true);
4540 tiles[p_atlas_coords].alternatives[new_alternative_id]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
4541 tiles[p_atlas_coords].alternatives[new_alternative_id]->notify_property_list_changed();
4542 tiles[p_atlas_coords].alternatives_ids.push_back(new_alternative_id);
4543 tiles[p_atlas_coords].alternatives_ids.sort();
4544 _compute_next_alternative_id(p_atlas_coords);
4545
4546 emit_signal(SNAME("changed"));
4547
4548 return new_alternative_id;
4549}
4550
4551void TileSetAtlasSource::remove_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) {
4552 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4553 ERR_FAIL_COND_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
4554 p_alternative_tile = alternative_no_transform(p_alternative_tile);
4555 ERR_FAIL_COND_MSG(p_alternative_tile == 0, "Cannot remove the alternative with id 0, the base tile alternative cannot be removed.");
4556
4557 memdelete(tiles[p_atlas_coords].alternatives[p_alternative_tile]);
4558 tiles[p_atlas_coords].alternatives.erase(p_alternative_tile);
4559 tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile);
4560 tiles[p_atlas_coords].alternatives_ids.sort();
4561
4562 emit_signal(SNAME("changed"));
4563}
4564
4565void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords, int p_alternative_tile, int p_new_id) {
4566 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4567 ERR_FAIL_COND_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
4568 p_alternative_tile = alternative_no_transform(p_alternative_tile);
4569 ERR_FAIL_COND_MSG(p_alternative_tile == 0, "Cannot change the alternative with id 0, the base tile alternative cannot be modified.");
4570
4571 ERR_FAIL_COND_MSG(tiles[p_atlas_coords].alternatives.has(p_new_id), vformat("TileSetAtlasSource has already an alternative with id %d at %s.", p_new_id, String(p_atlas_coords)));
4572
4573 tiles[p_atlas_coords].alternatives[p_new_id] = tiles[p_atlas_coords].alternatives[p_alternative_tile];
4574 tiles[p_atlas_coords].alternatives_ids.push_back(p_new_id);
4575
4576 tiles[p_atlas_coords].alternatives.erase(p_alternative_tile);
4577 tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile);
4578 tiles[p_atlas_coords].alternatives_ids.sort();
4579
4580 emit_signal(SNAME("changed"));
4581}
4582
4583bool TileSetAtlasSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const {
4584 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), false, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
4585 return tiles[p_atlas_coords].alternatives.has(alternative_no_transform(p_alternative_tile));
4586}
4587
4588int TileSetAtlasSource::get_next_alternative_tile_id(const Vector2i p_atlas_coords) const {
4589 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
4590 return tiles[p_atlas_coords].next_alternative_id;
4591}
4592
4593int TileSetAtlasSource::get_alternative_tiles_count(const Vector2i p_atlas_coords) const {
4594 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), -1, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
4595 return tiles[p_atlas_coords].alternatives_ids.size();
4596}
4597
4598int TileSetAtlasSource::get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const {
4599 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
4600 p_index = alternative_no_transform(p_index);
4601 ERR_FAIL_INDEX_V(p_index, tiles[p_atlas_coords].alternatives_ids.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
4602
4603 return tiles[p_atlas_coords].alternatives_ids[p_index];
4604}
4605
4606TileData *TileSetAtlasSource::get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const {
4607 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
4608 p_alternative_tile = alternative_no_transform(p_alternative_tile);
4609 ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
4610
4611 return tiles[p_atlas_coords].alternatives[p_alternative_tile];
4612}
4613
4614void TileSetAtlasSource::_bind_methods() {
4615 ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TileSetAtlasSource::set_texture);
4616 ClassDB::bind_method(D_METHOD("get_texture"), &TileSetAtlasSource::get_texture);
4617 ClassDB::bind_method(D_METHOD("set_margins", "margins"), &TileSetAtlasSource::set_margins);
4618 ClassDB::bind_method(D_METHOD("get_margins"), &TileSetAtlasSource::get_margins);
4619 ClassDB::bind_method(D_METHOD("set_separation", "separation"), &TileSetAtlasSource::set_separation);
4620 ClassDB::bind_method(D_METHOD("get_separation"), &TileSetAtlasSource::get_separation);
4621 ClassDB::bind_method(D_METHOD("set_texture_region_size", "texture_region_size"), &TileSetAtlasSource::set_texture_region_size);
4622 ClassDB::bind_method(D_METHOD("get_texture_region_size"), &TileSetAtlasSource::get_texture_region_size);
4623 ClassDB::bind_method(D_METHOD("set_use_texture_padding", "use_texture_padding"), &TileSetAtlasSource::set_use_texture_padding);
4624 ClassDB::bind_method(D_METHOD("get_use_texture_padding"), &TileSetAtlasSource::get_use_texture_padding);
4625
4626 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NO_EDITOR), "set_texture", "get_texture");
4627 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_margins", "get_margins");
4628 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_separation", "get_separation");
4629 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_texture_region_size", "get_texture_region_size");
4630 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_texture_padding", "get_use_texture_padding");
4631
4632 // Base tiles
4633 ClassDB::bind_method(D_METHOD("create_tile", "atlas_coords", "size"), &TileSetAtlasSource::create_tile, DEFVAL(Vector2i(1, 1)));
4634 ClassDB::bind_method(D_METHOD("remove_tile", "atlas_coords"), &TileSetAtlasSource::remove_tile); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative
4635 ClassDB::bind_method(D_METHOD("move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1)));
4636 ClassDB::bind_method(D_METHOD("get_tile_size_in_atlas", "atlas_coords"), &TileSetAtlasSource::get_tile_size_in_atlas);
4637
4638 ClassDB::bind_method(D_METHOD("has_room_for_tile", "atlas_coords", "size", "animation_columns", "animation_separation", "frames_count", "ignored_tile"), &TileSetAtlasSource::has_room_for_tile, DEFVAL(INVALID_ATLAS_COORDS));
4639 ClassDB::bind_method(D_METHOD("get_tiles_to_be_removed_on_change", "texture", "margins", "separation", "texture_region_size"), &TileSetAtlasSource::get_tiles_to_be_removed_on_change);
4640 ClassDB::bind_method(D_METHOD("get_tile_at_coords", "atlas_coords"), &TileSetAtlasSource::get_tile_at_coords);
4641
4642 ClassDB::bind_method(D_METHOD("has_tiles_outside_texture"), &TileSetAtlasSource::has_tiles_outside_texture);
4643 ClassDB::bind_method(D_METHOD("clear_tiles_outside_texture"), &TileSetAtlasSource::clear_tiles_outside_texture);
4644
4645 ClassDB::bind_method(D_METHOD("set_tile_animation_columns", "atlas_coords", "frame_columns"), &TileSetAtlasSource::set_tile_animation_columns);
4646 ClassDB::bind_method(D_METHOD("get_tile_animation_columns", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_columns);
4647 ClassDB::bind_method(D_METHOD("set_tile_animation_separation", "atlas_coords", "separation"), &TileSetAtlasSource::set_tile_animation_separation);
4648 ClassDB::bind_method(D_METHOD("get_tile_animation_separation", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_separation);
4649 ClassDB::bind_method(D_METHOD("set_tile_animation_speed", "atlas_coords", "speed"), &TileSetAtlasSource::set_tile_animation_speed);
4650 ClassDB::bind_method(D_METHOD("get_tile_animation_speed", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_speed);
4651 ClassDB::bind_method(D_METHOD("set_tile_animation_mode", "atlas_coords", "mode"), &TileSetAtlasSource::set_tile_animation_mode);
4652 ClassDB::bind_method(D_METHOD("get_tile_animation_mode", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_mode);
4653 ClassDB::bind_method(D_METHOD("set_tile_animation_frames_count", "atlas_coords", "frames_count"), &TileSetAtlasSource::set_tile_animation_frames_count);
4654 ClassDB::bind_method(D_METHOD("get_tile_animation_frames_count", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_frames_count);
4655 ClassDB::bind_method(D_METHOD("set_tile_animation_frame_duration", "atlas_coords", "frame_index", "duration"), &TileSetAtlasSource::set_tile_animation_frame_duration);
4656 ClassDB::bind_method(D_METHOD("get_tile_animation_frame_duration", "atlas_coords", "frame_index"), &TileSetAtlasSource::get_tile_animation_frame_duration);
4657 ClassDB::bind_method(D_METHOD("get_tile_animation_total_duration", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_total_duration);
4658
4659 // Alternative tiles
4660 ClassDB::bind_method(D_METHOD("create_alternative_tile", "atlas_coords", "alternative_id_override"), &TileSetAtlasSource::create_alternative_tile, DEFVAL(INVALID_TILE_ALTERNATIVE));
4661 ClassDB::bind_method(D_METHOD("remove_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::remove_alternative_tile);
4662 ClassDB::bind_method(D_METHOD("set_alternative_tile_id", "atlas_coords", "alternative_tile", "new_id"), &TileSetAtlasSource::set_alternative_tile_id);
4663 ClassDB::bind_method(D_METHOD("get_next_alternative_tile_id", "atlas_coords"), &TileSetAtlasSource::get_next_alternative_tile_id);
4664
4665 ClassDB::bind_method(D_METHOD("get_tile_data", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::get_tile_data);
4666
4667 // Helpers.
4668 ClassDB::bind_method(D_METHOD("get_atlas_grid_size"), &TileSetAtlasSource::get_atlas_grid_size);
4669 ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0));
4670
4671 // Getters for texture and tile region (padded or not)
4672 ClassDB::bind_method(D_METHOD("_update_padded_texture"), &TileSetAtlasSource::_update_padded_texture);
4673 ClassDB::bind_method(D_METHOD("get_runtime_texture"), &TileSetAtlasSource::get_runtime_texture);
4674 ClassDB::bind_method(D_METHOD("get_runtime_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_runtime_tile_texture_region);
4675
4676 BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_DEFAULT)
4677 BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_RANDOM_START_TIMES)
4678 BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_MAX)
4679
4680 BIND_CONSTANT(TRANSFORM_FLIP_H)
4681 BIND_CONSTANT(TRANSFORM_FLIP_V)
4682 BIND_CONSTANT(TRANSFORM_TRANSPOSE)
4683}
4684
4685TileSetAtlasSource::~TileSetAtlasSource() {
4686 // Free everything needed.
4687 for (KeyValue<Vector2i, TileAlternativesData> &E_alternatives : tiles) {
4688 for (KeyValue<int, TileData *> &E_tile_data : E_alternatives.value.alternatives) {
4689 memdelete(E_tile_data.value);
4690 }
4691 }
4692}
4693
4694TileData *TileSetAtlasSource::_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) {
4695 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4696 p_alternative_tile = alternative_no_transform(p_alternative_tile);
4697 ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
4698
4699 return tiles[p_atlas_coords].alternatives[p_alternative_tile];
4700}
4701
4702const TileData *TileSetAtlasSource::_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) const {
4703 ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4704 ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
4705
4706 return tiles[p_atlas_coords].alternatives[p_alternative_tile];
4707}
4708
4709void TileSetAtlasSource::_compute_next_alternative_id(const Vector2i p_atlas_coords) {
4710 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
4711
4712 while (tiles[p_atlas_coords].alternatives.has(tiles[p_atlas_coords].next_alternative_id)) {
4713 tiles[p_atlas_coords].next_alternative_id = (tiles[p_atlas_coords].next_alternative_id % 1073741823) + 1; // 2 ** 30
4714 };
4715}
4716
4717void TileSetAtlasSource::_clear_coords_mapping_cache(Vector2i p_atlas_coords) {
4718 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4719 TileAlternativesData &tad = tiles[p_atlas_coords];
4720 for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) {
4721 Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0));
4722 for (int x = 0; x < tad.size_in_atlas.x; x++) {
4723 for (int y = 0; y < tad.size_in_atlas.y; y++) {
4724 Vector2i coords = frame_coords + Vector2i(x, y);
4725 if (!_coords_mapping_cache.has(coords)) {
4726 WARN_PRINT(vformat("TileSetAtlasSource has no cached tile at position %s, the position cache might be corrupted.", coords));
4727 } else {
4728 if (_coords_mapping_cache[coords] != p_atlas_coords) {
4729 WARN_PRINT(vformat("The position cache at position %s is pointing to a wrong tile, the position cache might be corrupted.", coords));
4730 }
4731 _coords_mapping_cache.erase(coords);
4732 }
4733 }
4734 }
4735 }
4736}
4737
4738void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) {
4739 ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
4740
4741 TileAlternativesData &tad = tiles[p_atlas_coords];
4742 for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) {
4743 Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0));
4744 for (int x = 0; x < tad.size_in_atlas.x; x++) {
4745 for (int y = 0; y < tad.size_in_atlas.y; y++) {
4746 Vector2i coords = frame_coords + Vector2i(x, y);
4747 if (_coords_mapping_cache.has(coords)) {
4748 WARN_PRINT(vformat("The cache already has a tile for position %s, the position cache might be corrupted.", coords));
4749 }
4750 _coords_mapping_cache[coords] = p_atlas_coords;
4751 }
4752 }
4753 }
4754}
4755
4756void TileSetAtlasSource::_queue_update_padded_texture() {
4757 padded_texture_needs_update = true;
4758 call_deferred(SNAME("_update_padded_texture"));
4759}
4760
4761void TileSetAtlasSource::_update_padded_texture() {
4762 if (!padded_texture_needs_update) {
4763 return;
4764 }
4765 padded_texture_needs_update = false;
4766 padded_texture = Ref<ImageTexture>();
4767
4768 if (!texture.is_valid()) {
4769 return;
4770 }
4771
4772 if (!use_texture_padding) {
4773 return;
4774 }
4775
4776 Size2 size = get_atlas_grid_size() * (texture_region_size + Vector2i(2, 2));
4777
4778 Ref<Image> src = texture->get_image();
4779
4780 if (!src.is_valid()) {
4781 return;
4782 }
4783
4784 Ref<Image> image = Image::create_empty(size.x, size.y, false, src->get_format());
4785
4786 for (KeyValue<Vector2i, TileAlternativesData> kv : tiles) {
4787 for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) {
4788 // Compute the source rects.
4789 Rect2i src_rect = get_tile_texture_region(kv.key, frame);
4790
4791 Rect2i top_src_rect = Rect2i(src_rect.position, Vector2i(src_rect.size.x, 1));
4792 Rect2i bottom_src_rect = Rect2i(src_rect.position + Vector2i(0, src_rect.size.y - 1), Vector2i(src_rect.size.x, 1));
4793 Rect2i left_src_rect = Rect2i(src_rect.position, Vector2i(1, src_rect.size.y));
4794 Rect2i right_src_rect = Rect2i(src_rect.position + Vector2i(src_rect.size.x - 1, 0), Vector2i(1, src_rect.size.y));
4795
4796 // Copy the tile and the paddings.
4797 Vector2i frame_coords = kv.key + (kv.value.size_in_atlas + kv.value.animation_separation) * ((kv.value.animation_columns > 0) ? Vector2i(frame % kv.value.animation_columns, frame / kv.value.animation_columns) : Vector2i(frame, 0));
4798 Vector2i base_pos = frame_coords * (texture_region_size + Vector2i(2, 2)) + Vector2i(1, 1);
4799
4800 image->blit_rect(*src, src_rect, base_pos);
4801
4802 image->blit_rect(*src, top_src_rect, base_pos + Vector2i(0, -1));
4803 image->blit_rect(*src, bottom_src_rect, base_pos + Vector2i(0, src_rect.size.y));
4804 image->blit_rect(*src, left_src_rect, base_pos + Vector2i(-1, 0));
4805 image->blit_rect(*src, right_src_rect, base_pos + Vector2i(src_rect.size.x, 0));
4806
4807 image->set_pixelv(base_pos + Vector2i(-1, -1), src->get_pixelv(src_rect.position));
4808 image->set_pixelv(base_pos + Vector2i(src_rect.size.x, -1), src->get_pixelv(src_rect.position + Vector2i(src_rect.size.x - 1, 0)));
4809 image->set_pixelv(base_pos + Vector2i(-1, src_rect.size.y), src->get_pixelv(src_rect.position + Vector2i(0, src_rect.size.y - 1)));
4810 image->set_pixelv(base_pos + Vector2i(src_rect.size.x, src_rect.size.y), src->get_pixelv(src_rect.position + Vector2i(src_rect.size.x - 1, src_rect.size.y - 1)));
4811 }
4812 }
4813
4814 if (!padded_texture.is_valid()) {
4815 padded_texture.instantiate();
4816 }
4817 padded_texture->set_image(image);
4818 emit_changed();
4819}
4820
4821/////////////////////////////// TileSetScenesCollectionSource //////////////////////////////////////
4822
4823void TileSetScenesCollectionSource::_compute_next_alternative_id() {
4824 while (scenes.has(next_scene_id)) {
4825 next_scene_id = (next_scene_id % 1073741823) + 1; // 2 ** 30
4826 };
4827}
4828
4829int TileSetScenesCollectionSource::get_tiles_count() const {
4830 return 1;
4831}
4832
4833Vector2i TileSetScenesCollectionSource::get_tile_id(int p_tile_index) const {
4834 ERR_FAIL_COND_V(p_tile_index != 0, TileSetSource::INVALID_ATLAS_COORDS);
4835 return Vector2i();
4836}
4837
4838bool TileSetScenesCollectionSource::has_tile(Vector2i p_atlas_coords) const {
4839 return p_atlas_coords == Vector2i();
4840}
4841
4842int TileSetScenesCollectionSource::get_alternative_tiles_count(const Vector2i p_atlas_coords) const {
4843 return scenes_ids.size();
4844}
4845
4846int TileSetScenesCollectionSource::get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const {
4847 ERR_FAIL_COND_V(p_atlas_coords != Vector2i(), TileSetSource::INVALID_TILE_ALTERNATIVE);
4848 ERR_FAIL_INDEX_V(p_index, scenes_ids.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
4849
4850 return scenes_ids[p_index];
4851}
4852
4853bool TileSetScenesCollectionSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const {
4854 ERR_FAIL_COND_V(p_atlas_coords != Vector2i(), false);
4855 return scenes.has(p_alternative_tile);
4856}
4857
4858int TileSetScenesCollectionSource::create_scene_tile(Ref<PackedScene> p_packed_scene, int p_id_override) {
4859 ERR_FAIL_COND_V_MSG(p_id_override >= 0 && scenes.has(p_id_override), INVALID_TILE_ALTERNATIVE, vformat("Cannot create scene tile. Another scene tile exists with id %d.", p_id_override));
4860
4861 int new_scene_id = p_id_override >= 0 ? p_id_override : next_scene_id;
4862
4863 scenes[new_scene_id] = SceneData();
4864 scenes_ids.push_back(new_scene_id);
4865 scenes_ids.sort();
4866 set_scene_tile_scene(new_scene_id, p_packed_scene);
4867 _compute_next_alternative_id();
4868
4869 emit_signal(SNAME("changed"));
4870
4871 return new_scene_id;
4872}
4873
4874void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) {
4875 ERR_FAIL_COND(p_new_id < 0);
4876 ERR_FAIL_COND(!has_scene_tile_id(p_id));
4877 ERR_FAIL_COND(has_scene_tile_id(p_new_id));
4878
4879 scenes[p_new_id] = SceneData();
4880 scenes[p_new_id] = scenes[p_id];
4881 scenes_ids.push_back(p_new_id);
4882 scenes_ids.sort();
4883
4884 _compute_next_alternative_id();
4885
4886 scenes.erase(p_id);
4887 scenes_ids.erase(p_id);
4888
4889 emit_signal(SNAME("changed"));
4890}
4891
4892void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene) {
4893 ERR_FAIL_COND(!scenes.has(p_id));
4894 if (p_packed_scene.is_valid()) {
4895 // Check if it extends CanvasItem.
4896 Ref<SceneState> scene_state = p_packed_scene->get_state();
4897 String type;
4898 while (scene_state.is_valid() && type.is_empty()) {
4899 // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work.
4900 ERR_FAIL_COND(scene_state->get_node_count() < 1);
4901
4902 type = scene_state->get_node_type(0);
4903 scene_state = scene_state->get_base_scene_state();
4904 }
4905 ERR_FAIL_COND_EDMSG(type.is_empty(), vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Could not get the type of the root node.", p_packed_scene->get_path()));
4906 bool extends_correct_class = ClassDB::is_parent_class(type, "CanvasItem");
4907 ERR_FAIL_COND_EDMSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend CanvasItem. Found %s instead.", p_packed_scene->get_path(), type));
4908
4909 scenes[p_id].scene = p_packed_scene;
4910 } else {
4911 scenes[p_id].scene = Ref<PackedScene>();
4912 }
4913 emit_signal(SNAME("changed"));
4914}
4915
4916Ref<PackedScene> TileSetScenesCollectionSource::get_scene_tile_scene(int p_id) const {
4917 ERR_FAIL_COND_V(!scenes.has(p_id), Ref<PackedScene>());
4918 return scenes[p_id].scene;
4919}
4920
4921void TileSetScenesCollectionSource::set_scene_tile_display_placeholder(int p_id, bool p_display_placeholder) {
4922 ERR_FAIL_COND(!scenes.has(p_id));
4923
4924 scenes[p_id].display_placeholder = p_display_placeholder;
4925
4926 emit_signal(SNAME("changed"));
4927}
4928
4929bool TileSetScenesCollectionSource::get_scene_tile_display_placeholder(int p_id) const {
4930 ERR_FAIL_COND_V(!scenes.has(p_id), false);
4931 return scenes[p_id].display_placeholder;
4932}
4933
4934void TileSetScenesCollectionSource::remove_scene_tile(int p_id) {
4935 ERR_FAIL_COND(!scenes.has(p_id));
4936
4937 scenes.erase(p_id);
4938 scenes_ids.erase(p_id);
4939 emit_signal(SNAME("changed"));
4940}
4941
4942int TileSetScenesCollectionSource::get_next_scene_tile_id() const {
4943 return next_scene_id;
4944}
4945
4946bool TileSetScenesCollectionSource::_set(const StringName &p_name, const Variant &p_value) {
4947 Vector<String> components = String(p_name).split("/", true, 2);
4948
4949 if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_int()) {
4950 int scene_id = components[1].to_int();
4951 if (components.size() >= 3 && components[2] == "scene") {
4952 if (has_scene_tile_id(scene_id)) {
4953 set_scene_tile_scene(scene_id, p_value);
4954 } else {
4955 create_scene_tile(p_value, scene_id);
4956 }
4957 return true;
4958 } else if (components.size() >= 3 && components[2] == "display_placeholder") {
4959 if (!has_scene_tile_id(scene_id)) {
4960 create_scene_tile(p_value, scene_id);
4961 }
4962
4963 return true;
4964 }
4965 }
4966
4967 return false;
4968}
4969
4970bool TileSetScenesCollectionSource::_get(const StringName &p_name, Variant &r_ret) const {
4971 Vector<String> components = String(p_name).split("/", true, 2);
4972
4973 if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_int() && scenes.has(components[1].to_int())) {
4974 if (components.size() >= 3 && components[2] == "scene") {
4975 r_ret = scenes[components[1].to_int()].scene;
4976 return true;
4977 } else if (components.size() >= 3 && components[2] == "display_placeholder") {
4978 r_ret = scenes[components[1].to_int()].scene;
4979 return true;
4980 }
4981 }
4982
4983 return false;
4984}
4985
4986void TileSetScenesCollectionSource::_get_property_list(List<PropertyInfo> *p_list) const {
4987 for (int i = 0; i < scenes_ids.size(); i++) {
4988 p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("%s/%d/%s", PNAME("scenes"), scenes_ids[i], PNAME("scene")), PROPERTY_HINT_RESOURCE_TYPE, "TileSetScenesCollectionSource"));
4989
4990 PropertyInfo property_info = PropertyInfo(Variant::BOOL, vformat("%s/%d/%s", PNAME("scenes"), scenes_ids[i], PNAME("display_placeholder")));
4991 if (scenes[scenes_ids[i]].display_placeholder == false) {
4992 property_info.usage ^= PROPERTY_USAGE_STORAGE;
4993 }
4994 p_list->push_back(property_info);
4995 }
4996}
4997
4998void TileSetScenesCollectionSource::_bind_methods() {
4999 ClassDB::bind_method(D_METHOD("get_scene_tiles_count"), &TileSetScenesCollectionSource::get_scene_tiles_count);
5000 ClassDB::bind_method(D_METHOD("get_scene_tile_id", "index"), &TileSetScenesCollectionSource::get_scene_tile_id);
5001 ClassDB::bind_method(D_METHOD("has_scene_tile_id", "id"), &TileSetScenesCollectionSource::has_scene_tile_id);
5002 ClassDB::bind_method(D_METHOD("create_scene_tile", "packed_scene", "id_override"), &TileSetScenesCollectionSource::create_scene_tile, DEFVAL(INVALID_TILE_ALTERNATIVE));
5003 ClassDB::bind_method(D_METHOD("set_scene_tile_id", "id", "new_id"), &TileSetScenesCollectionSource::set_scene_tile_id);
5004 ClassDB::bind_method(D_METHOD("set_scene_tile_scene", "id", "packed_scene"), &TileSetScenesCollectionSource::set_scene_tile_scene);
5005 ClassDB::bind_method(D_METHOD("get_scene_tile_scene", "id"), &TileSetScenesCollectionSource::get_scene_tile_scene);
5006 ClassDB::bind_method(D_METHOD("set_scene_tile_display_placeholder", "id", "display_placeholder"), &TileSetScenesCollectionSource::set_scene_tile_display_placeholder);
5007 ClassDB::bind_method(D_METHOD("get_scene_tile_display_placeholder", "id"), &TileSetScenesCollectionSource::get_scene_tile_display_placeholder);
5008 ClassDB::bind_method(D_METHOD("remove_scene_tile", "id"), &TileSetScenesCollectionSource::remove_scene_tile);
5009 ClassDB::bind_method(D_METHOD("get_next_scene_tile_id"), &TileSetScenesCollectionSource::get_next_scene_tile_id);
5010}
5011
5012/////////////////////////////// TileData //////////////////////////////////////
5013
5014void TileData::set_tile_set(const TileSet *p_tile_set) {
5015 tile_set = p_tile_set;
5016 notify_tile_data_properties_should_change();
5017}
5018
5019void TileData::notify_tile_data_properties_should_change() {
5020 if (!tile_set) {
5021 return;
5022 }
5023
5024 occluders.resize(tile_set->get_occlusion_layers_count());
5025 physics.resize(tile_set->get_physics_layers_count());
5026 for (int bit_index = 0; bit_index < 16; bit_index++) {
5027 if (terrain_set < 0 || terrain_peering_bits[bit_index] >= tile_set->get_terrains_count(terrain_set)) {
5028 terrain_peering_bits[bit_index] = -1;
5029 }
5030 }
5031 navigation.resize(tile_set->get_navigation_layers_count());
5032
5033 // Convert custom data to the new type.
5034 custom_data.resize(tile_set->get_custom_data_layers_count());
5035 for (int i = 0; i < custom_data.size(); i++) {
5036 if (custom_data[i].get_type() != tile_set->get_custom_data_layer_type(i)) {
5037 Variant new_val;
5038 Callable::CallError error;
5039 if (Variant::can_convert(custom_data[i].get_type(), tile_set->get_custom_data_layer_type(i))) {
5040 const Variant *args[] = { &custom_data[i] };
5041 Variant::construct(tile_set->get_custom_data_layer_type(i), new_val, args, 1, error);
5042 } else {
5043 Variant::construct(tile_set->get_custom_data_layer_type(i), new_val, nullptr, 0, error);
5044 }
5045 custom_data.write[i] = new_val;
5046 }
5047 }
5048
5049 notify_property_list_changed();
5050 emit_signal(SNAME("changed"));
5051}
5052
5053void TileData::add_occlusion_layer(int p_to_pos) {
5054 if (p_to_pos < 0) {
5055 p_to_pos = occluders.size();
5056 }
5057 ERR_FAIL_INDEX(p_to_pos, occluders.size() + 1);
5058 occluders.insert(p_to_pos, Ref<OccluderPolygon2D>());
5059}
5060
5061void TileData::move_occlusion_layer(int p_from_index, int p_to_pos) {
5062 ERR_FAIL_INDEX(p_from_index, occluders.size());
5063 ERR_FAIL_INDEX(p_to_pos, occluders.size() + 1);
5064 occluders.insert(p_to_pos, occluders[p_from_index]);
5065 occluders.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
5066}
5067
5068void TileData::remove_occlusion_layer(int p_index) {
5069 ERR_FAIL_INDEX(p_index, occluders.size());
5070 occluders.remove_at(p_index);
5071}
5072
5073void TileData::add_physics_layer(int p_to_pos) {
5074 if (p_to_pos < 0) {
5075 p_to_pos = physics.size();
5076 }
5077 ERR_FAIL_INDEX(p_to_pos, physics.size() + 1);
5078 physics.insert(p_to_pos, PhysicsLayerTileData());
5079}
5080
5081void TileData::move_physics_layer(int p_from_index, int p_to_pos) {
5082 ERR_FAIL_INDEX(p_from_index, physics.size());
5083 ERR_FAIL_INDEX(p_to_pos, physics.size() + 1);
5084 physics.insert(p_to_pos, physics[p_from_index]);
5085 physics.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
5086}
5087
5088void TileData::remove_physics_layer(int p_index) {
5089 ERR_FAIL_INDEX(p_index, physics.size());
5090 physics.remove_at(p_index);
5091}
5092
5093void TileData::add_terrain_set(int p_to_pos) {
5094 if (p_to_pos >= 0 && p_to_pos <= terrain_set) {
5095 terrain_set += 1;
5096 }
5097}
5098
5099void TileData::move_terrain_set(int p_from_index, int p_to_pos) {
5100 if (p_from_index == terrain_set) {
5101 terrain_set = (p_from_index < p_to_pos) ? p_to_pos - 1 : p_to_pos;
5102 } else {
5103 if (p_from_index < terrain_set) {
5104 terrain_set -= 1;
5105 }
5106 if (p_to_pos <= terrain_set) {
5107 terrain_set += 1;
5108 }
5109 }
5110}
5111
5112void TileData::remove_terrain_set(int p_index) {
5113 if (p_index == terrain_set) {
5114 terrain_set = -1;
5115 for (int i = 0; i < 16; i++) {
5116 terrain_peering_bits[i] = -1;
5117 }
5118 } else if (terrain_set > p_index) {
5119 terrain_set -= 1;
5120 }
5121}
5122
5123void TileData::add_terrain(int p_terrain_set, int p_to_pos) {
5124 if (terrain_set == p_terrain_set) {
5125 for (int i = 0; i < 16; i++) {
5126 if (p_to_pos >= 0 && p_to_pos <= terrain_peering_bits[i]) {
5127 terrain_peering_bits[i] += 1;
5128 }
5129 }
5130 }
5131}
5132
5133void TileData::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
5134 if (terrain_set == p_terrain_set) {
5135 for (int i = 0; i < 16; i++) {
5136 if (p_from_index == terrain_peering_bits[i]) {
5137 terrain_peering_bits[i] = (p_from_index < p_to_pos) ? p_to_pos - 1 : p_to_pos;
5138 } else {
5139 if (p_from_index < terrain_peering_bits[i]) {
5140 terrain_peering_bits[i] -= 1;
5141 }
5142 if (p_to_pos <= terrain_peering_bits[i]) {
5143 terrain_peering_bits[i] += 1;
5144 }
5145 }
5146 }
5147 }
5148}
5149
5150void TileData::remove_terrain(int p_terrain_set, int p_index) {
5151 if (terrain_set == p_terrain_set) {
5152 if (terrain == p_index) {
5153 terrain = -1;
5154 } else if (terrain > p_index) {
5155 terrain -= 1;
5156 }
5157
5158 for (int i = 0; i < 16; i++) {
5159 if (terrain_peering_bits[i] == p_index) {
5160 terrain_peering_bits[i] = -1;
5161 } else if (terrain_peering_bits[i] > p_index) {
5162 terrain_peering_bits[i] -= 1;
5163 }
5164 }
5165 }
5166}
5167
5168void TileData::add_navigation_layer(int p_to_pos) {
5169 if (p_to_pos < 0) {
5170 p_to_pos = navigation.size();
5171 }
5172 ERR_FAIL_INDEX(p_to_pos, navigation.size() + 1);
5173 navigation.insert(p_to_pos, Ref<NavigationPolygon>());
5174}
5175
5176void TileData::move_navigation_layer(int p_from_index, int p_to_pos) {
5177 ERR_FAIL_INDEX(p_from_index, navigation.size());
5178 ERR_FAIL_INDEX(p_to_pos, navigation.size() + 1);
5179 navigation.insert(p_to_pos, navigation[p_from_index]);
5180 navigation.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
5181}
5182
5183void TileData::remove_navigation_layer(int p_index) {
5184 ERR_FAIL_INDEX(p_index, navigation.size());
5185 navigation.remove_at(p_index);
5186}
5187
5188void TileData::add_custom_data_layer(int p_to_pos) {
5189 if (p_to_pos < 0) {
5190 p_to_pos = custom_data.size();
5191 }
5192 ERR_FAIL_INDEX(p_to_pos, custom_data.size() + 1);
5193 custom_data.insert(p_to_pos, Variant());
5194}
5195
5196void TileData::move_custom_data_layer(int p_from_index, int p_to_pos) {
5197 ERR_FAIL_INDEX(p_from_index, custom_data.size());
5198 ERR_FAIL_INDEX(p_to_pos, custom_data.size() + 1);
5199 custom_data.insert(p_to_pos, custom_data[p_from_index]);
5200 custom_data.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
5201}
5202
5203void TileData::remove_custom_data_layer(int p_index) {
5204 ERR_FAIL_INDEX(p_index, custom_data.size());
5205 custom_data.remove_at(p_index);
5206}
5207
5208void TileData::set_allow_transform(bool p_allow_transform) {
5209 allow_transform = p_allow_transform;
5210}
5211
5212bool TileData::is_allowing_transform() const {
5213 return allow_transform;
5214}
5215
5216TileData *TileData::duplicate() {
5217 TileData *output = memnew(TileData);
5218 output->tile_set = tile_set;
5219
5220 output->allow_transform = allow_transform;
5221
5222 // Rendering
5223 output->flip_h = flip_h;
5224 output->flip_v = flip_v;
5225 output->transpose = transpose;
5226 output->texture_origin = texture_origin;
5227 output->material = material;
5228 output->modulate = modulate;
5229 output->z_index = z_index;
5230 output->y_sort_origin = y_sort_origin;
5231 output->occluders = occluders;
5232 // Physics
5233 output->physics = physics;
5234 // Terrain
5235 output->terrain_set = -1;
5236 memcpy(output->terrain_peering_bits, terrain_peering_bits, 16 * sizeof(int));
5237 // Navigation
5238 output->navigation = navigation;
5239 // Misc
5240 output->probability = probability;
5241 // Custom data
5242 output->custom_data = custom_data;
5243
5244 return output;
5245}
5246
5247// Rendering
5248void TileData::set_flip_h(bool p_flip_h) {
5249 ERR_FAIL_COND_MSG(!allow_transform && p_flip_h, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
5250 flip_h = p_flip_h;
5251 emit_signal(SNAME("changed"));
5252}
5253bool TileData::get_flip_h() const {
5254 return flip_h;
5255}
5256
5257void TileData::set_flip_v(bool p_flip_v) {
5258 ERR_FAIL_COND_MSG(!allow_transform && p_flip_v, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
5259 flip_v = p_flip_v;
5260 emit_signal(SNAME("changed"));
5261}
5262
5263bool TileData::get_flip_v() const {
5264 return flip_v;
5265}
5266
5267void TileData::set_transpose(bool p_transpose) {
5268 ERR_FAIL_COND_MSG(!allow_transform && p_transpose, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
5269 transpose = p_transpose;
5270 emit_signal(SNAME("changed"));
5271}
5272bool TileData::get_transpose() const {
5273 return transpose;
5274}
5275
5276void TileData::set_texture_origin(Vector2i p_texture_origin) {
5277 texture_origin = p_texture_origin;
5278 emit_signal(SNAME("changed"));
5279}
5280
5281Vector2i TileData::get_texture_origin() const {
5282 return texture_origin;
5283}
5284
5285void TileData::set_material(Ref<Material> p_material) {
5286 material = p_material;
5287 emit_signal(SNAME("changed"));
5288}
5289Ref<Material> TileData::get_material() const {
5290 return material;
5291}
5292
5293void TileData::set_modulate(Color p_modulate) {
5294 modulate = p_modulate;
5295 emit_signal(SNAME("changed"));
5296}
5297Color TileData::get_modulate() const {
5298 return modulate;
5299}
5300
5301void TileData::set_z_index(int p_z_index) {
5302 z_index = p_z_index;
5303 emit_signal(SNAME("changed"));
5304}
5305int TileData::get_z_index() const {
5306 return z_index;
5307}
5308
5309void TileData::set_y_sort_origin(int p_y_sort_origin) {
5310 y_sort_origin = p_y_sort_origin;
5311 emit_signal(SNAME("changed"));
5312}
5313int TileData::get_y_sort_origin() const {
5314 return y_sort_origin;
5315}
5316
5317void TileData::set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon) {
5318 ERR_FAIL_INDEX(p_layer_id, occluders.size());
5319 occluders.write[p_layer_id] = p_occluder_polygon;
5320 emit_signal(SNAME("changed"));
5321}
5322
5323Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id) const {
5324 ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref<OccluderPolygon2D>());
5325 return occluders[p_layer_id];
5326}
5327
5328// Physics
5329void TileData::set_constant_linear_velocity(int p_layer_id, const Vector2 &p_velocity) {
5330 ERR_FAIL_INDEX(p_layer_id, physics.size());
5331 physics.write[p_layer_id].linear_velocity = p_velocity;
5332 emit_signal(SNAME("changed"));
5333}
5334
5335Vector2 TileData::get_constant_linear_velocity(int p_layer_id) const {
5336 ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Vector2());
5337 return physics[p_layer_id].linear_velocity;
5338}
5339
5340void TileData::set_constant_angular_velocity(int p_layer_id, real_t p_velocity) {
5341 ERR_FAIL_INDEX(p_layer_id, physics.size());
5342 physics.write[p_layer_id].angular_velocity = p_velocity;
5343 emit_signal(SNAME("changed"));
5344}
5345
5346real_t TileData::get_constant_angular_velocity(int p_layer_id) const {
5347 ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0.0);
5348 return physics[p_layer_id].angular_velocity;
5349}
5350
5351void TileData::set_collision_polygons_count(int p_layer_id, int p_polygons_count) {
5352 ERR_FAIL_INDEX(p_layer_id, physics.size());
5353 ERR_FAIL_COND(p_polygons_count < 0);
5354 if (p_polygons_count == physics.write[p_layer_id].polygons.size()) {
5355 return;
5356 }
5357 physics.write[p_layer_id].polygons.resize(p_polygons_count);
5358 notify_property_list_changed();
5359 emit_signal(SNAME("changed"));
5360}
5361
5362int TileData::get_collision_polygons_count(int p_layer_id) const {
5363 ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0);
5364 return physics[p_layer_id].polygons.size();
5365}
5366
5367void TileData::add_collision_polygon(int p_layer_id) {
5368 ERR_FAIL_INDEX(p_layer_id, physics.size());
5369 physics.write[p_layer_id].polygons.push_back(PhysicsLayerTileData::PolygonShapeTileData());
5370 emit_signal(SNAME("changed"));
5371}
5372
5373void TileData::remove_collision_polygon(int p_layer_id, int p_polygon_index) {
5374 ERR_FAIL_INDEX(p_layer_id, physics.size());
5375 ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
5376 physics.write[p_layer_id].polygons.remove_at(p_polygon_index);
5377 emit_signal(SNAME("changed"));
5378}
5379
5380void TileData::set_collision_polygon_points(int p_layer_id, int p_polygon_index, Vector<Vector2> p_polygon) {
5381 ERR_FAIL_INDEX(p_layer_id, physics.size());
5382 ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
5383 ERR_FAIL_COND_MSG(p_polygon.size() != 0 && p_polygon.size() < 3, "Invalid polygon. Needs either 0 or more than 3 points.");
5384
5385 if (p_polygon.is_empty()) {
5386 physics.write[p_layer_id].polygons.write[p_polygon_index].shapes.clear();
5387 } else {
5388 // Decompose into convex shapes.
5389 Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(p_polygon);
5390 ERR_FAIL_COND_MSG(decomp.is_empty(), "Could not decompose the polygon into convex shapes.");
5391
5392 physics.write[p_layer_id].polygons.write[p_polygon_index].shapes.resize(decomp.size());
5393 for (int i = 0; i < decomp.size(); i++) {
5394 Ref<ConvexPolygonShape2D> shape;
5395 shape.instantiate();
5396 shape->set_points(decomp[i]);
5397 physics.write[p_layer_id].polygons.write[p_polygon_index].shapes[i] = shape;
5398 }
5399 }
5400 physics.write[p_layer_id].polygons.write[p_polygon_index].polygon = p_polygon;
5401 emit_signal(SNAME("changed"));
5402}
5403
5404Vector<Vector2> TileData::get_collision_polygon_points(int p_layer_id, int p_polygon_index) const {
5405 ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Vector<Vector2>());
5406 ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Vector<Vector2>());
5407 return physics[p_layer_id].polygons[p_polygon_index].polygon;
5408}
5409
5410void TileData::set_collision_polygon_one_way(int p_layer_id, int p_polygon_index, bool p_one_way) {
5411 ERR_FAIL_INDEX(p_layer_id, physics.size());
5412 ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
5413 physics.write[p_layer_id].polygons.write[p_polygon_index].one_way = p_one_way;
5414 emit_signal(SNAME("changed"));
5415}
5416
5417bool TileData::is_collision_polygon_one_way(int p_layer_id, int p_polygon_index) const {
5418 ERR_FAIL_INDEX_V(p_layer_id, physics.size(), false);
5419 ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), false);
5420 return physics[p_layer_id].polygons[p_polygon_index].one_way;
5421}
5422
5423void TileData::set_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index, float p_one_way_margin) {
5424 ERR_FAIL_INDEX(p_layer_id, physics.size());
5425 ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
5426 physics.write[p_layer_id].polygons.write[p_polygon_index].one_way_margin = p_one_way_margin;
5427 emit_signal(SNAME("changed"));
5428}
5429
5430float TileData::get_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index) const {
5431 ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0.0);
5432 ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), 0.0);
5433 return physics[p_layer_id].polygons[p_polygon_index].one_way_margin;
5434}
5435
5436int TileData::get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_index) const {
5437 ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0);
5438 ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), 0);
5439 return physics[p_layer_id].polygons[p_polygon_index].shapes.size();
5440}
5441
5442Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index) const {
5443 ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Ref<ConvexPolygonShape2D>());
5444 ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Ref<ConvexPolygonShape2D>());
5445 ERR_FAIL_INDEX_V(shape_index, (int)physics[p_layer_id].polygons[p_polygon_index].shapes.size(), Ref<ConvexPolygonShape2D>());
5446 return physics[p_layer_id].polygons[p_polygon_index].shapes[shape_index];
5447}
5448
5449// Terrain
5450void TileData::set_terrain_set(int p_terrain_set) {
5451 ERR_FAIL_COND(p_terrain_set < -1);
5452 if (p_terrain_set == terrain_set) {
5453 return;
5454 }
5455 if (tile_set) {
5456 ERR_FAIL_COND(p_terrain_set >= tile_set->get_terrain_sets_count());
5457 terrain = -1;
5458 for (int i = 0; i < 16; i++) {
5459 terrain_peering_bits[i] = -1;
5460 }
5461 }
5462 terrain_set = p_terrain_set;
5463 notify_property_list_changed();
5464 emit_signal(SNAME("changed"));
5465}
5466
5467int TileData::get_terrain_set() const {
5468 return terrain_set;
5469}
5470
5471void TileData::set_terrain(int p_terrain) {
5472 ERR_FAIL_COND(terrain_set < 0);
5473 ERR_FAIL_COND(p_terrain < -1);
5474 if (tile_set) {
5475 ERR_FAIL_COND(p_terrain >= tile_set->get_terrains_count(terrain_set));
5476 }
5477 terrain = p_terrain;
5478 emit_signal(SNAME("changed"));
5479}
5480
5481int TileData::get_terrain() const {
5482 return terrain;
5483}
5484
5485void TileData::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
5486 ERR_FAIL_INDEX(p_peering_bit, TileSet::CellNeighbor::CELL_NEIGHBOR_MAX);
5487 ERR_FAIL_COND(terrain_set < 0);
5488 ERR_FAIL_COND(p_terrain_index < -1);
5489 if (tile_set) {
5490 ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
5491 ERR_FAIL_COND(!is_valid_terrain_peering_bit(p_peering_bit));
5492 }
5493 terrain_peering_bits[p_peering_bit] = p_terrain_index;
5494 emit_signal(SNAME("changed"));
5495}
5496
5497int TileData::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
5498 ERR_FAIL_COND_V(!is_valid_terrain_peering_bit(p_peering_bit), -1);
5499 return terrain_peering_bits[p_peering_bit];
5500}
5501
5502bool TileData::is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
5503 ERR_FAIL_NULL_V(tile_set, false);
5504
5505 return tile_set->is_valid_terrain_peering_bit(terrain_set, p_peering_bit);
5506}
5507
5508TileSet::TerrainsPattern TileData::get_terrains_pattern() const {
5509 ERR_FAIL_NULL_V(tile_set, TileSet::TerrainsPattern());
5510
5511 TileSet::TerrainsPattern output(tile_set, terrain_set);
5512 output.set_terrain(terrain);
5513 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
5514 if (tile_set->is_valid_terrain_peering_bit(terrain_set, TileSet::CellNeighbor(i))) {
5515 output.set_terrain_peering_bit(TileSet::CellNeighbor(i), get_terrain_peering_bit(TileSet::CellNeighbor(i)));
5516 }
5517 }
5518 return output;
5519}
5520
5521// Navigation
5522void TileData::set_navigation_polygon(int p_layer_id, Ref<NavigationPolygon> p_navigation_polygon) {
5523 ERR_FAIL_INDEX(p_layer_id, navigation.size());
5524 navigation.write[p_layer_id] = p_navigation_polygon;
5525 emit_signal(SNAME("changed"));
5526}
5527
5528Ref<NavigationPolygon> TileData::get_navigation_polygon(int p_layer_id) const {
5529 ERR_FAIL_INDEX_V(p_layer_id, navigation.size(), Ref<NavigationPolygon>());
5530 return navigation[p_layer_id];
5531}
5532
5533// Misc
5534void TileData::set_probability(float p_probability) {
5535 ERR_FAIL_COND(p_probability < 0.0);
5536 probability = p_probability;
5537 emit_signal(SNAME("changed"));
5538}
5539float TileData::get_probability() const {
5540 return probability;
5541}
5542
5543// Custom data
5544void TileData::set_custom_data(String p_layer_name, Variant p_value) {
5545 ERR_FAIL_NULL(tile_set);
5546 int p_layer_id = tile_set->get_custom_data_layer_by_name(p_layer_name);
5547 ERR_FAIL_COND_MSG(p_layer_id < 0, vformat("TileSet has no layer with name: %s", p_layer_name));
5548 set_custom_data_by_layer_id(p_layer_id, p_value);
5549}
5550
5551Variant TileData::get_custom_data(String p_layer_name) const {
5552 ERR_FAIL_NULL_V(tile_set, Variant());
5553 int p_layer_id = tile_set->get_custom_data_layer_by_name(p_layer_name);
5554 ERR_FAIL_COND_V_MSG(p_layer_id < 0, Variant(), vformat("TileSet has no layer with name: %s", p_layer_name));
5555 return get_custom_data_by_layer_id(p_layer_id);
5556}
5557
5558void TileData::set_custom_data_by_layer_id(int p_layer_id, Variant p_value) {
5559 ERR_FAIL_INDEX(p_layer_id, custom_data.size());
5560 custom_data.write[p_layer_id] = p_value;
5561 emit_signal(SNAME("changed"));
5562}
5563
5564Variant TileData::get_custom_data_by_layer_id(int p_layer_id) const {
5565 ERR_FAIL_INDEX_V(p_layer_id, custom_data.size(), Variant());
5566 return custom_data[p_layer_id];
5567}
5568
5569bool TileData::_set(const StringName &p_name, const Variant &p_value) {
5570#ifndef DISABLE_DEPRECATED
5571 if (p_name == "texture_offset") {
5572 texture_origin = p_value;
5573 return true;
5574 }
5575#endif
5576
5577 Vector<String> components = String(p_name).split("/", true, 2);
5578
5579 if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
5580 // Occlusion layers.
5581 int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
5582 ERR_FAIL_COND_V(layer_index < 0, false);
5583 if (components[1] == "polygon") {
5584 Ref<OccluderPolygon2D> polygon = p_value;
5585
5586 if (layer_index >= occluders.size()) {
5587 if (tile_set) {
5588 return false;
5589 } else {
5590 occluders.resize(layer_index + 1);
5591 }
5592 }
5593 set_occluder(layer_index, polygon);
5594 return true;
5595 }
5596 } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
5597 // Physics layers.
5598 int layer_index = components[0].trim_prefix("physics_layer_").to_int();
5599 ERR_FAIL_COND_V(layer_index < 0, false);
5600 if (components.size() == 2) {
5601 if (layer_index >= physics.size()) {
5602 if (tile_set) {
5603 return false;
5604 } else {
5605 physics.resize(layer_index + 1);
5606 }
5607 }
5608 if (components[1] == "linear_velocity") {
5609 set_constant_linear_velocity(layer_index, p_value);
5610 return true;
5611 } else if (components[1] == "angular_velocity") {
5612 set_constant_angular_velocity(layer_index, p_value);
5613 return true;
5614 } else if (components[1] == "polygons_count") {
5615 if (p_value.get_type() != Variant::INT) {
5616 return false;
5617 }
5618 set_collision_polygons_count(layer_index, p_value);
5619 return true;
5620 }
5621 } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
5622 int polygon_index = components[1].trim_prefix("polygon_").to_int();
5623 ERR_FAIL_COND_V(polygon_index < 0, false);
5624
5625 if (components[2] == "points" || components[2] == "one_way" || components[2] == "one_way_margin") {
5626 if (layer_index >= physics.size()) {
5627 if (tile_set) {
5628 return false;
5629 } else {
5630 physics.resize(layer_index + 1);
5631 }
5632 }
5633
5634 if (polygon_index >= physics[layer_index].polygons.size()) {
5635 physics.write[layer_index].polygons.resize(polygon_index + 1);
5636 }
5637 }
5638 if (components[2] == "points") {
5639 Vector<Vector2> polygon = p_value;
5640 set_collision_polygon_points(layer_index, polygon_index, polygon);
5641 return true;
5642 } else if (components[2] == "one_way") {
5643 set_collision_polygon_one_way(layer_index, polygon_index, p_value);
5644 return true;
5645 } else if (components[2] == "one_way_margin") {
5646 set_collision_polygon_one_way_margin(layer_index, polygon_index, p_value);
5647 return true;
5648 }
5649 }
5650 } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
5651 // Navigation layers.
5652 int layer_index = components[0].trim_prefix("navigation_layer_").to_int();
5653 ERR_FAIL_COND_V(layer_index < 0, false);
5654 if (components[1] == "polygon") {
5655 Ref<NavigationPolygon> polygon = p_value;
5656
5657 if (layer_index >= navigation.size()) {
5658 if (tile_set) {
5659 return false;
5660 } else {
5661 navigation.resize(layer_index + 1);
5662 }
5663 }
5664 set_navigation_polygon(layer_index, polygon);
5665 return true;
5666 }
5667 } else if (components.size() == 2 && components[0] == "terrains_peering_bit") {
5668 // Terrains.
5669 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
5670 TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
5671 if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) {
5672 set_terrain_peering_bit(bit, p_value);
5673 return true;
5674 }
5675 }
5676 return false;
5677 } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_int()) {
5678 // Custom data layers.
5679 int layer_index = components[0].trim_prefix("custom_data_").to_int();
5680 ERR_FAIL_COND_V(layer_index < 0, false);
5681
5682 if (layer_index >= custom_data.size()) {
5683 if (tile_set) {
5684 return false;
5685 } else {
5686 custom_data.resize(layer_index + 1);
5687 }
5688 }
5689 set_custom_data_by_layer_id(layer_index, p_value);
5690
5691 return true;
5692 }
5693
5694 return false;
5695}
5696
5697bool TileData::_get(const StringName &p_name, Variant &r_ret) const {
5698#ifndef DISABLE_DEPRECATED
5699 if (p_name == "texture_offset") {
5700 r_ret = texture_origin;
5701 return true;
5702 }
5703#endif
5704
5705 Vector<String> components = String(p_name).split("/", true, 2);
5706
5707 if (tile_set) {
5708 if (components.size() == 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
5709 // Occlusion layers.
5710 int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
5711 ERR_FAIL_COND_V(layer_index < 0, false);
5712 if (layer_index >= occluders.size()) {
5713 return false;
5714 }
5715 if (components[1] == "polygon") {
5716 r_ret = get_occluder(layer_index);
5717 return true;
5718 }
5719 } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
5720 // Physics layers.
5721 int layer_index = components[0].trim_prefix("physics_layer_").to_int();
5722 ERR_FAIL_COND_V(layer_index < 0, false);
5723 if (layer_index >= physics.size()) {
5724 return false;
5725 }
5726
5727 if (components.size() == 2) {
5728 if (components[1] == "linear_velocity") {
5729 r_ret = get_constant_linear_velocity(layer_index);
5730 return true;
5731 } else if (components[1] == "angular_velocity") {
5732 r_ret = get_constant_angular_velocity(layer_index);
5733 return true;
5734 } else if (components[1] == "polygons_count") {
5735 r_ret = get_collision_polygons_count(layer_index);
5736 return true;
5737 }
5738 } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
5739 int polygon_index = components[1].trim_prefix("polygon_").to_int();
5740 ERR_FAIL_COND_V(polygon_index < 0, false);
5741 if (polygon_index >= physics[layer_index].polygons.size()) {
5742 return false;
5743 }
5744 if (components[2] == "points") {
5745 r_ret = get_collision_polygon_points(layer_index, polygon_index);
5746 return true;
5747 } else if (components[2] == "one_way") {
5748 r_ret = is_collision_polygon_one_way(layer_index, polygon_index);
5749 return true;
5750 } else if (components[2] == "one_way_margin") {
5751 r_ret = get_collision_polygon_one_way_margin(layer_index, polygon_index);
5752 return true;
5753 }
5754 }
5755 } else if (components.size() == 2 && components[0] == "terrains_peering_bit") {
5756 // Terrains.
5757 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
5758 if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) {
5759 r_ret = terrain_peering_bits[i];
5760 return true;
5761 }
5762 }
5763 return false;
5764 } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
5765 // Occlusion layers.
5766 int layer_index = components[0].trim_prefix("navigation_layer_").to_int();
5767 ERR_FAIL_COND_V(layer_index < 0, false);
5768 if (layer_index >= navigation.size()) {
5769 return false;
5770 }
5771 if (components[1] == "polygon") {
5772 r_ret = get_navigation_polygon(layer_index);
5773 return true;
5774 }
5775 } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_int()) {
5776 // Custom data layers.
5777 int layer_index = components[0].trim_prefix("custom_data_").to_int();
5778 ERR_FAIL_COND_V(layer_index < 0, false);
5779 if (layer_index >= custom_data.size()) {
5780 return false;
5781 }
5782 r_ret = get_custom_data_by_layer_id(layer_index);
5783 return true;
5784 }
5785 }
5786
5787 return false;
5788}
5789
5790void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
5791 PropertyInfo property_info;
5792 // Add the groups manually.
5793 if (tile_set) {
5794 // Occlusion layers.
5795 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Rendering", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
5796 for (int i = 0; i < occluders.size(); i++) {
5797 // occlusion_layer_%d/polygon
5798 property_info = PropertyInfo(Variant::OBJECT, vformat("occlusion_layer_%d/%s", i, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_DEFAULT);
5799 if (!occluders[i].is_valid()) {
5800 property_info.usage ^= PROPERTY_USAGE_STORAGE;
5801 }
5802 p_list->push_back(property_info);
5803 }
5804
5805 // Physics layers.
5806 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Physics", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
5807 for (int i = 0; i < physics.size(); i++) {
5808 p_list->push_back(PropertyInfo(Variant::VECTOR2, vformat("physics_layer_%d/%s", i, PNAME("linear_velocity")), PROPERTY_HINT_NONE));
5809 p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/%s", i, PNAME("angular_velocity")), PROPERTY_HINT_NONE));
5810 p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/%s", i, PNAME("polygons_count")), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
5811
5812 for (int j = 0; j < physics[i].polygons.size(); j++) {
5813 // physics_layer_%d/points
5814 property_info = PropertyInfo(Variant::ARRAY, vformat("physics_layer_%d/polygon_%d/%s", i, j, PNAME("points")), PROPERTY_HINT_ARRAY_TYPE, "Vector2", PROPERTY_USAGE_DEFAULT);
5815 if (physics[i].polygons[j].polygon.is_empty()) {
5816 property_info.usage ^= PROPERTY_USAGE_STORAGE;
5817 }
5818 p_list->push_back(property_info);
5819
5820 // physics_layer_%d/polygon_%d/one_way
5821 property_info = PropertyInfo(Variant::BOOL, vformat("physics_layer_%d/polygon_%d/%s", i, j, PNAME("one_way")));
5822 if (physics[i].polygons[j].one_way == false) {
5823 property_info.usage ^= PROPERTY_USAGE_STORAGE;
5824 }
5825 p_list->push_back(property_info);
5826
5827 // physics_layer_%d/polygon_%d/one_way_margin
5828 property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/polygon_%d/%s", i, j, PNAME("one_way_margin")));
5829 if (physics[i].polygons[j].one_way_margin == 1.0) {
5830 property_info.usage ^= PROPERTY_USAGE_STORAGE;
5831 }
5832 p_list->push_back(property_info);
5833 }
5834 }
5835
5836 // Terrain data
5837 if (terrain_set >= 0) {
5838 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Terrains", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
5839 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
5840 TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
5841 if (is_valid_terrain_peering_bit(bit)) {
5842 property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
5843 if (get_terrain_peering_bit(bit) == -1) {
5844 property_info.usage ^= PROPERTY_USAGE_STORAGE;
5845 }
5846 p_list->push_back(property_info);
5847 }
5848 }
5849 }
5850
5851 // Navigation layers.
5852 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Navigation", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
5853 for (int i = 0; i < navigation.size(); i++) {
5854 property_info = PropertyInfo(Variant::OBJECT, vformat("navigation_layer_%d/%s", i, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon", PROPERTY_USAGE_DEFAULT);
5855 if (!navigation[i].is_valid()) {
5856 property_info.usage ^= PROPERTY_USAGE_STORAGE;
5857 }
5858 p_list->push_back(property_info);
5859 }
5860
5861 // Custom data layers.
5862 p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Custom Data", "custom_data_"), PROPERTY_HINT_NONE, "custom_data_", PROPERTY_USAGE_GROUP));
5863 for (int i = 0; i < custom_data.size(); i++) {
5864 Variant default_val;
5865 Callable::CallError error;
5866 Variant::construct(custom_data[i].get_type(), default_val, nullptr, 0, error);
5867 property_info = PropertyInfo(tile_set->get_custom_data_layer_type(i), vformat("custom_data_%d", i), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
5868 if (custom_data[i] == default_val) {
5869 property_info.usage ^= PROPERTY_USAGE_STORAGE;
5870 }
5871 p_list->push_back(property_info);
5872 }
5873 }
5874}
5875
5876void TileData::_bind_methods() {
5877 // Rendering.
5878 ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &TileData::set_flip_h);
5879 ClassDB::bind_method(D_METHOD("get_flip_h"), &TileData::get_flip_h);
5880 ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &TileData::set_flip_v);
5881 ClassDB::bind_method(D_METHOD("get_flip_v"), &TileData::get_flip_v);
5882 ClassDB::bind_method(D_METHOD("set_transpose", "transpose"), &TileData::set_transpose);
5883 ClassDB::bind_method(D_METHOD("get_transpose"), &TileData::get_transpose);
5884 ClassDB::bind_method(D_METHOD("set_material", "material"), &TileData::set_material);
5885 ClassDB::bind_method(D_METHOD("get_material"), &TileData::get_material);
5886 ClassDB::bind_method(D_METHOD("set_texture_origin", "texture_origin"), &TileData::set_texture_origin);
5887 ClassDB::bind_method(D_METHOD("get_texture_origin"), &TileData::get_texture_origin);
5888 ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &TileData::set_modulate);
5889 ClassDB::bind_method(D_METHOD("get_modulate"), &TileData::get_modulate);
5890 ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &TileData::set_z_index);
5891 ClassDB::bind_method(D_METHOD("get_z_index"), &TileData::get_z_index);
5892 ClassDB::bind_method(D_METHOD("set_y_sort_origin", "y_sort_origin"), &TileData::set_y_sort_origin);
5893 ClassDB::bind_method(D_METHOD("get_y_sort_origin"), &TileData::get_y_sort_origin);
5894
5895 ClassDB::bind_method(D_METHOD("set_occluder", "layer_id", "occluder_polygon"), &TileData::set_occluder);
5896 ClassDB::bind_method(D_METHOD("get_occluder", "layer_id"), &TileData::get_occluder);
5897
5898 // Physics.
5899 ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "layer_id", "velocity"), &TileData::set_constant_linear_velocity);
5900 ClassDB::bind_method(D_METHOD("get_constant_linear_velocity", "layer_id"), &TileData::get_constant_linear_velocity);
5901 ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "layer_id", "velocity"), &TileData::set_constant_angular_velocity);
5902 ClassDB::bind_method(D_METHOD("get_constant_angular_velocity", "layer_id"), &TileData::get_constant_angular_velocity);
5903 ClassDB::bind_method(D_METHOD("set_collision_polygons_count", "layer_id", "polygons_count"), &TileData::set_collision_polygons_count);
5904 ClassDB::bind_method(D_METHOD("get_collision_polygons_count", "layer_id"), &TileData::get_collision_polygons_count);
5905 ClassDB::bind_method(D_METHOD("add_collision_polygon", "layer_id"), &TileData::add_collision_polygon);
5906 ClassDB::bind_method(D_METHOD("remove_collision_polygon", "layer_id", "polygon_index"), &TileData::remove_collision_polygon);
5907 ClassDB::bind_method(D_METHOD("set_collision_polygon_points", "layer_id", "polygon_index", "polygon"), &TileData::set_collision_polygon_points);
5908 ClassDB::bind_method(D_METHOD("get_collision_polygon_points", "layer_id", "polygon_index"), &TileData::get_collision_polygon_points);
5909 ClassDB::bind_method(D_METHOD("set_collision_polygon_one_way", "layer_id", "polygon_index", "one_way"), &TileData::set_collision_polygon_one_way);
5910 ClassDB::bind_method(D_METHOD("is_collision_polygon_one_way", "layer_id", "polygon_index"), &TileData::is_collision_polygon_one_way);
5911 ClassDB::bind_method(D_METHOD("set_collision_polygon_one_way_margin", "layer_id", "polygon_index", "one_way_margin"), &TileData::set_collision_polygon_one_way_margin);
5912 ClassDB::bind_method(D_METHOD("get_collision_polygon_one_way_margin", "layer_id", "polygon_index"), &TileData::get_collision_polygon_one_way_margin);
5913
5914 // Terrain
5915 ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set);
5916 ClassDB::bind_method(D_METHOD("get_terrain_set"), &TileData::get_terrain_set);
5917 ClassDB::bind_method(D_METHOD("set_terrain", "terrain"), &TileData::set_terrain);
5918 ClassDB::bind_method(D_METHOD("get_terrain"), &TileData::get_terrain);
5919 ClassDB::bind_method(D_METHOD("set_terrain_peering_bit", "peering_bit", "terrain"), &TileData::set_terrain_peering_bit);
5920 ClassDB::bind_method(D_METHOD("get_terrain_peering_bit", "peering_bit"), &TileData::get_terrain_peering_bit);
5921
5922 // Navigation
5923 ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon);
5924 ClassDB::bind_method(D_METHOD("get_navigation_polygon", "layer_id"), &TileData::get_navigation_polygon);
5925
5926 // Misc.
5927 ClassDB::bind_method(D_METHOD("set_probability", "probability"), &TileData::set_probability);
5928 ClassDB::bind_method(D_METHOD("get_probability"), &TileData::get_probability);
5929
5930 // Custom data.
5931 ClassDB::bind_method(D_METHOD("set_custom_data", "layer_name", "value"), &TileData::set_custom_data);
5932 ClassDB::bind_method(D_METHOD("get_custom_data", "layer_name"), &TileData::get_custom_data);
5933 ClassDB::bind_method(D_METHOD("set_custom_data_by_layer_id", "layer_id", "value"), &TileData::set_custom_data_by_layer_id);
5934 ClassDB::bind_method(D_METHOD("get_custom_data_by_layer_id", "layer_id"), &TileData::get_custom_data_by_layer_id);
5935
5936 ADD_GROUP("Rendering", "");
5937 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "get_flip_h");
5938 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "get_flip_v");
5939 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transpose"), "set_transpose", "get_transpose");
5940 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_origin", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_origin", "get_texture_origin");
5941 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
5942 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material");
5943 ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index"), "set_z_index", "get_z_index");
5944 ADD_PROPERTY(PropertyInfo(Variant::INT, "y_sort_origin"), "set_y_sort_origin", "get_y_sort_origin");
5945
5946 ADD_GROUP("Terrains", "");
5947 ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain_set"), "set_terrain_set", "get_terrain_set");
5948 ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain"), "set_terrain", "get_terrain");
5949
5950 ADD_GROUP("Miscellaneous", "");
5951 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "probability"), "set_probability", "get_probability");
5952
5953 ADD_SIGNAL(MethodInfo("changed"));
5954}
5955