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 | |
44 | void 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 | |
80 | Vector<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 | |
103 | void 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 | |
111 | bool TileMapPattern::has_cell(const Vector2i &p_coords) const { |
112 | return pattern.has(p_coords); |
113 | } |
114 | |
115 | void 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 | |
128 | int 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 | |
134 | Vector2i 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 | |
140 | int 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 | |
146 | TypedArray<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 | |
159 | Size2i TileMapPattern::get_size() const { |
160 | return size; |
161 | } |
162 | |
163 | void 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 | |
175 | bool TileMapPattern::is_empty() const { |
176 | return pattern.is_empty(); |
177 | }; |
178 | |
179 | void TileMapPattern::clear() { |
180 | size = Size2i(); |
181 | pattern.clear(); |
182 | emit_changed(); |
183 | }; |
184 | |
185 | bool 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 | |
196 | bool 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 | |
204 | void 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 | |
208 | void 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 | |
224 | bool TileSet::TerrainsPattern::is_valid() const { |
225 | return valid; |
226 | } |
227 | |
228 | bool TileSet::TerrainsPattern::is_erase_pattern() const { |
229 | return not_empty_terrains_count == 0; |
230 | } |
231 | |
232 | bool 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 | |
249 | bool 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 | |
264 | void TileSet::TerrainsPattern::set_terrain(int p_terrain) { |
265 | ERR_FAIL_COND(p_terrain < -1); |
266 | |
267 | terrain = p_terrain; |
268 | } |
269 | |
270 | int TileSet::TerrainsPattern::get_terrain() const { |
271 | return terrain; |
272 | } |
273 | |
274 | void 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 | |
289 | int 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 | |
295 | void 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 | |
307 | Array 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 | |
318 | TileSet::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 | |
327 | const int TileSet::INVALID_SOURCE = -1; |
328 | |
329 | const 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 -- |
349 | void 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 | } |
361 | TileSet::TileShape TileSet::get_tile_shape() const { |
362 | return tile_shape; |
363 | } |
364 | |
365 | void TileSet::set_tile_layout(TileSet::TileLayout p_layout) { |
366 | tile_layout = p_layout; |
367 | emit_changed(); |
368 | } |
369 | TileSet::TileLayout TileSet::get_tile_layout() const { |
370 | return tile_layout; |
371 | } |
372 | |
373 | void 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 | } |
384 | TileSet::TileOffsetAxis TileSet::get_tile_offset_axis() const { |
385 | return tile_offset_axis; |
386 | } |
387 | |
388 | void 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 | } |
395 | Size2i TileSet::get_tile_size() const { |
396 | return tile_size; |
397 | } |
398 | |
399 | int TileSet::get_next_source_id() const { |
400 | return next_source_id; |
401 | } |
402 | |
403 | void 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 | |
466 | void 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 |
473 | int 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 | |
498 | void 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 | |
512 | void 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 | |
522 | void 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 | |
544 | bool TileSet::has_source(int p_source_id) const { |
545 | return sources.has(p_source_id); |
546 | } |
547 | |
548 | Ref<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 | |
554 | int TileSet::get_source_count() const { |
555 | return source_ids.size(); |
556 | } |
557 | |
558 | int 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 |
564 | void 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 | |
572 | bool TileSet::is_uv_clipping() const { |
573 | return uv_clipping; |
574 | }; |
575 | |
576 | int TileSet::get_occlusion_layers_count() const { |
577 | return occlusion_layers.size(); |
578 | }; |
579 | |
580 | void 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 | |
595 | void 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 | |
607 | void 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 | |
617 | void 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 | |
623 | int 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 | |
628 | void 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 | |
634 | bool 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 | |
639 | int TileSet::get_physics_layers_count() const { |
640 | return physics_layers.size(); |
641 | } |
642 | |
643 | void 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 | |
658 | void 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 | |
670 | void 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 | |
680 | void 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 | |
686 | uint32_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 | |
691 | void 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 | |
697 | uint32_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 | |
702 | void 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 | |
707 | Ref<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 |
713 | int TileSet::get_terrain_sets_count() const { |
714 | return terrain_sets.size(); |
715 | } |
716 | |
717 | void 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 | |
733 | void 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 | |
746 | void 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 | |
757 | void 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 | |
769 | TileSet::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 | |
774 | int 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 | |
779 | void 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 | |
804 | void 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 | |
820 | void 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 | |
834 | void 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 | |
841 | String 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 | |
847 | void 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 | |
858 | Color 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 | |
864 | bool 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 | |
947 | bool 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 |
957 | int TileSet::get_navigation_layers_count() const { |
958 | return navigation_layers.size(); |
959 | } |
960 | |
961 | void 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 | |
976 | void 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 | |
988 | void 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 | |
998 | void 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 | |
1004 | uint32_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 | |
1009 | void 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 | |
1024 | bool 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. |
1032 | int TileSet::get_custom_data_layers_count() const { |
1033 | return custom_data_layers.size(); |
1034 | } |
1035 | |
1036 | void 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 | |
1051 | void 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 | |
1063 | void 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 | |
1084 | int 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 | |
1092 | void 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 | |
1114 | String 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 | |
1119 | void 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 | |
1130 | Variant::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 | |
1135 | void 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 | |
1143 | int 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 | |
1149 | bool TileSet::has_source_level_tile_proxy(int p_source_from) { |
1150 | return source_level_proxies.has(p_source_from); |
1151 | } |
1152 | |
1153 | void 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 | |
1161 | void 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 | |
1178 | Array 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 | |
1188 | bool 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 | |
1196 | void 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 | |
1208 | void 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 | |
1227 | Array 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 | |
1238 | bool 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 | |
1247 | void 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 | |
1260 | Array 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 | |
1271 | Array 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 | |
1282 | Array 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 | |
1293 | Array 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 | |
1336 | void 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 | |
1375 | void 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 | |
1383 | int 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 | |
1398 | Ref<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 | |
1403 | void 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 | |
1409 | int TileSet::get_patterns_count() { |
1410 | return patterns.size(); |
1411 | } |
1412 | |
1413 | RBSet<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 | |
1424 | RBSet<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 | |
1430 | TileMapCell 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 | |
1480 | Vector<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 | |
1521 | void 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 | |
1565 | Vector<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 | |
1586 | Vector<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 | |
1631 | void 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 | |
1770 | Vector<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 | |
1863 | void TileSet::_source_changed() { |
1864 | terrains_cache_dirty = true; |
1865 | emit_changed(); |
1866 | } |
1867 | |
1868 | Vector<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 | |
1878 | Vector<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 | |
1921 | Vector<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 | |
1963 | Vector<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 | |
1997 | Vector<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 | |
2007 | Vector<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 | |
2065 | Vector<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 | |
2107 | Vector<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 | |
2141 | Vector<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 | |
2164 | Vector<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 | |
2322 | Vector<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 | |
2426 | Vector<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 | |
2512 | void 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 | |
2556 | const Vector2i TileSetSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1); |
2557 | const int TileSetSource::INVALID_TILE_ALTERNATIVE = -1; |
2558 | |
2559 | #ifndef DISABLE_DEPRECATED |
2560 | void 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 | |
2842 | Array 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 | |
2880 | bool 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 | |
3208 | bool 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 | |
3334 | void 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 | |
3416 | void 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 | |
3424 | void 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 | |
3588 | TileSet::TileSet() { |
3589 | // Instantiate the tile meshes. |
3590 | tile_lines_mesh.instantiate(); |
3591 | tile_filled_mesh.instantiate(); |
3592 | } |
3593 | |
3594 | TileSet::~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 | |
3607 | void TileSetSource::set_tile_set(const TileSet *p_tile_set) { |
3608 | tile_set = p_tile_set; |
3609 | } |
3610 | |
3611 | TileSet *TileSetSource::get_tile_set() const { |
3612 | return (TileSet *)tile_set; |
3613 | } |
3614 | |
3615 | void TileSetSource::reset_state() { |
3616 | tile_set = nullptr; |
3617 | }; |
3618 | |
3619 | void 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 | |
3633 | void 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 | |
3644 | const TileSet *TileSetAtlasSource::get_tile_set() const { |
3645 | return tile_set; |
3646 | } |
3647 | |
3648 | void 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 | |
3657 | void 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 | |
3665 | void 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 | |
3673 | void 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 | |
3681 | void 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 | |
3689 | void 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 | |
3697 | void 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 | |
3705 | void 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 | |
3713 | void 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 | |
3721 | void 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 | |
3729 | void 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 | |
3737 | void 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 | |
3745 | void 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 | |
3753 | void 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 | |
3761 | void 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 | |
3769 | void 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 | |
3777 | void 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 | |
3785 | void 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 | |
3793 | void 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 | |
3801 | void 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 | |
3815 | void 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 | |
3830 | Ref<Texture2D> TileSetAtlasSource::get_texture() const { |
3831 | return texture; |
3832 | } |
3833 | |
3834 | void 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 | |
3846 | Vector2i TileSetAtlasSource::get_margins() const { |
3847 | return margins; |
3848 | } |
3849 | |
3850 | void 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 | |
3862 | Vector2i TileSetAtlasSource::get_separation() const { |
3863 | return separation; |
3864 | } |
3865 | |
3866 | void 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 | |
3878 | Vector2i TileSetAtlasSource::get_texture_region_size() const { |
3879 | return texture_region_size; |
3880 | } |
3881 | |
3882 | void 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 | |
3891 | bool TileSetAtlasSource::get_use_texture_padding() const { |
3892 | return use_texture_padding; |
3893 | } |
3894 | |
3895 | Vector2i 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 | |
3914 | bool 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 | |
3992 | bool 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 | |
4054 | void 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 | |
4141 | void 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 | |
4171 | void 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 | |
4192 | bool TileSetAtlasSource::has_tile(Vector2i p_atlas_coords) const { |
4193 | return tiles.has(p_atlas_coords); |
4194 | } |
4195 | |
4196 | Vector2i 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 | |
4204 | void 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 | |
4222 | int 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 | |
4227 | void 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 | |
4245 | Vector2i 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 | |
4250 | void 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 | |
4259 | real_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 | |
4264 | void 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 | |
4272 | TileSetAtlasSource::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 | |
4278 | void 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 | |
4306 | int 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 | |
4311 | void 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 | |
4321 | real_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 | |
4327 | real_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 | |
4337 | Vector2i 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 | |
4343 | int TileSetAtlasSource::get_tiles_count() const { |
4344 | return tiles_ids.size(); |
4345 | } |
4346 | |
4347 | Vector2i 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 | |
4352 | bool 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 | |
4380 | bool 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 | |
4389 | Vector<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 | |
4400 | void 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 | |
4414 | PackedVector2Array 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 | |
4445 | Rect2i 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 | |
4460 | bool 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 | |
4467 | int 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) |
4472 | Ref<Texture2D> TileSetAtlasSource::get_runtime_texture() const { |
4473 | if (use_texture_padding) { |
4474 | return padded_texture; |
4475 | } else { |
4476 | return texture; |
4477 | } |
4478 | } |
4479 | |
4480 | Rect2i 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 | |
4496 | void 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 | |
4531 | int 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 | |
4551 | void 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 | |
4565 | void 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 | |
4583 | bool 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 | |
4588 | int 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 | |
4593 | int 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 | |
4598 | int 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 | |
4606 | TileData *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 | |
4614 | void 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 | |
4685 | TileSetAtlasSource::~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 | |
4694 | TileData *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 | |
4702 | const 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 | |
4709 | void 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 | |
4717 | void 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 | |
4738 | void 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 | |
4756 | void TileSetAtlasSource::_queue_update_padded_texture() { |
4757 | padded_texture_needs_update = true; |
4758 | call_deferred(SNAME("_update_padded_texture" )); |
4759 | } |
4760 | |
4761 | void 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 | |
4823 | void 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 | |
4829 | int TileSetScenesCollectionSource::get_tiles_count() const { |
4830 | return 1; |
4831 | } |
4832 | |
4833 | Vector2i 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 | |
4838 | bool TileSetScenesCollectionSource::has_tile(Vector2i p_atlas_coords) const { |
4839 | return p_atlas_coords == Vector2i(); |
4840 | } |
4841 | |
4842 | int TileSetScenesCollectionSource::get_alternative_tiles_count(const Vector2i p_atlas_coords) const { |
4843 | return scenes_ids.size(); |
4844 | } |
4845 | |
4846 | int 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 | |
4853 | bool 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 | |
4858 | int 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 | |
4874 | void 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 | |
4892 | void 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 | |
4916 | Ref<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 | |
4921 | void 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 | |
4929 | bool 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 | |
4934 | void 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 | |
4942 | int TileSetScenesCollectionSource::get_next_scene_tile_id() const { |
4943 | return next_scene_id; |
4944 | } |
4945 | |
4946 | bool 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 | |
4970 | bool 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 | |
4986 | void 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 | |
4998 | void 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 | |
5014 | void TileData::set_tile_set(const TileSet *p_tile_set) { |
5015 | tile_set = p_tile_set; |
5016 | notify_tile_data_properties_should_change(); |
5017 | } |
5018 | |
5019 | void 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 | |
5053 | void 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 | |
5061 | void 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 | |
5068 | void TileData::remove_occlusion_layer(int p_index) { |
5069 | ERR_FAIL_INDEX(p_index, occluders.size()); |
5070 | occluders.remove_at(p_index); |
5071 | } |
5072 | |
5073 | void 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 | |
5081 | void 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 | |
5088 | void TileData::remove_physics_layer(int p_index) { |
5089 | ERR_FAIL_INDEX(p_index, physics.size()); |
5090 | physics.remove_at(p_index); |
5091 | } |
5092 | |
5093 | void 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 | |
5099 | void 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 | |
5112 | void 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 | |
5123 | void 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 | |
5133 | void 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 | |
5150 | void 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 | |
5168 | void 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 | |
5176 | void 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 | |
5183 | void TileData::remove_navigation_layer(int p_index) { |
5184 | ERR_FAIL_INDEX(p_index, navigation.size()); |
5185 | navigation.remove_at(p_index); |
5186 | } |
5187 | |
5188 | void 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 | |
5196 | void 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 | |
5203 | void 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 | |
5208 | void TileData::set_allow_transform(bool p_allow_transform) { |
5209 | allow_transform = p_allow_transform; |
5210 | } |
5211 | |
5212 | bool TileData::is_allowing_transform() const { |
5213 | return allow_transform; |
5214 | } |
5215 | |
5216 | TileData *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 |
5248 | void 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 | } |
5253 | bool TileData::get_flip_h() const { |
5254 | return flip_h; |
5255 | } |
5256 | |
5257 | void 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 | |
5263 | bool TileData::get_flip_v() const { |
5264 | return flip_v; |
5265 | } |
5266 | |
5267 | void 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 | } |
5272 | bool TileData::get_transpose() const { |
5273 | return transpose; |
5274 | } |
5275 | |
5276 | void TileData::set_texture_origin(Vector2i p_texture_origin) { |
5277 | texture_origin = p_texture_origin; |
5278 | emit_signal(SNAME("changed" )); |
5279 | } |
5280 | |
5281 | Vector2i TileData::get_texture_origin() const { |
5282 | return texture_origin; |
5283 | } |
5284 | |
5285 | void TileData::set_material(Ref<Material> p_material) { |
5286 | material = p_material; |
5287 | emit_signal(SNAME("changed" )); |
5288 | } |
5289 | Ref<Material> TileData::get_material() const { |
5290 | return material; |
5291 | } |
5292 | |
5293 | void TileData::set_modulate(Color p_modulate) { |
5294 | modulate = p_modulate; |
5295 | emit_signal(SNAME("changed" )); |
5296 | } |
5297 | Color TileData::get_modulate() const { |
5298 | return modulate; |
5299 | } |
5300 | |
5301 | void TileData::set_z_index(int p_z_index) { |
5302 | z_index = p_z_index; |
5303 | emit_signal(SNAME("changed" )); |
5304 | } |
5305 | int TileData::get_z_index() const { |
5306 | return z_index; |
5307 | } |
5308 | |
5309 | void TileData::set_y_sort_origin(int p_y_sort_origin) { |
5310 | y_sort_origin = p_y_sort_origin; |
5311 | emit_signal(SNAME("changed" )); |
5312 | } |
5313 | int TileData::get_y_sort_origin() const { |
5314 | return y_sort_origin; |
5315 | } |
5316 | |
5317 | void 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 | |
5323 | Ref<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 |
5329 | void 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 | |
5335 | Vector2 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 | |
5340 | void 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 | |
5346 | real_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 | |
5351 | void 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 | |
5362 | int 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 | |
5367 | void 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 | |
5373 | void 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 | |
5380 | void 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 | |
5404 | Vector<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 | |
5410 | void 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 | |
5417 | bool 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 | |
5423 | void 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 | |
5430 | float 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 | |
5436 | int 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 | |
5442 | Ref<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 |
5450 | void 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 | |
5467 | int TileData::get_terrain_set() const { |
5468 | return terrain_set; |
5469 | } |
5470 | |
5471 | void 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 | |
5481 | int TileData::get_terrain() const { |
5482 | return terrain; |
5483 | } |
5484 | |
5485 | void 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 | |
5497 | int 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 | |
5502 | bool 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 | |
5508 | TileSet::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 |
5522 | void 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 | |
5528 | Ref<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 |
5534 | void TileData::set_probability(float p_probability) { |
5535 | ERR_FAIL_COND(p_probability < 0.0); |
5536 | probability = p_probability; |
5537 | emit_signal(SNAME("changed" )); |
5538 | } |
5539 | float TileData::get_probability() const { |
5540 | return probability; |
5541 | } |
5542 | |
5543 | // Custom data |
5544 | void 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 | |
5551 | Variant 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 | |
5558 | void 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 | |
5564 | Variant 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 | |
5569 | bool 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 | |
5697 | bool 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 | |
5790 | void 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 | |
5876 | void 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 | |