|
@@ -62,11 +62,6 @@ const char *TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[] = {
|
|
"top_right_corner"
|
|
"top_right_corner"
|
|
};
|
|
};
|
|
|
|
|
|
-// --- Plugins ---
|
|
|
|
-Vector<TileSetPlugin *> TileSet::get_tile_set_atlas_plugins() const {
|
|
|
|
- return tile_set_plugins_vector;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
// -- Shape and layout --
|
|
// -- Shape and layout --
|
|
void TileSet::set_tile_shape(TileSet::TileShape p_shape) {
|
|
void TileSet::set_tile_shape(TileSet::TileShape p_shape) {
|
|
tile_shape = p_shape;
|
|
tile_shape = p_shape;
|
|
@@ -205,21 +200,11 @@ void TileSet::set_uv_clipping(bool p_uv_clipping) {
|
|
uv_clipping = p_uv_clipping;
|
|
uv_clipping = p_uv_clipping;
|
|
emit_changed();
|
|
emit_changed();
|
|
}
|
|
}
|
|
|
|
+
|
|
bool TileSet::is_uv_clipping() const {
|
|
bool TileSet::is_uv_clipping() const {
|
|
return uv_clipping;
|
|
return uv_clipping;
|
|
};
|
|
};
|
|
|
|
|
|
-void TileSet::set_y_sorting(bool p_y_sort) {
|
|
|
|
- if (y_sorting == p_y_sort) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- y_sorting = p_y_sort;
|
|
|
|
- emit_changed();
|
|
|
|
-}
|
|
|
|
-bool TileSet::is_y_sorting() const {
|
|
|
|
- return y_sorting;
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
void TileSet::set_occlusion_layers_count(int p_occlusion_layers_count) {
|
|
void TileSet::set_occlusion_layers_count(int p_occlusion_layers_count) {
|
|
ERR_FAIL_COND(p_occlusion_layers_count < 0);
|
|
ERR_FAIL_COND(p_occlusion_layers_count < 0);
|
|
if (occlusion_layers.size() == p_occlusion_layers_count) {
|
|
if (occlusion_layers.size() == p_occlusion_layers_count) {
|
|
@@ -2604,8 +2589,6 @@ void TileSet::_bind_methods() {
|
|
// Rendering.
|
|
// Rendering.
|
|
ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping);
|
|
ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping);
|
|
ClassDB::bind_method(D_METHOD("is_uv_clipping"), &TileSet::is_uv_clipping);
|
|
ClassDB::bind_method(D_METHOD("is_uv_clipping"), &TileSet::is_uv_clipping);
|
|
- ClassDB::bind_method(D_METHOD("set_y_sorting", "y_sorting"), &TileSet::set_y_sorting);
|
|
|
|
- ClassDB::bind_method(D_METHOD("is_y_sorting"), &TileSet::is_y_sorting);
|
|
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_occlusion_layers_count", "occlusion_layers_count"), &TileSet::set_occlusion_layers_count);
|
|
ClassDB::bind_method(D_METHOD("set_occlusion_layers_count", "occlusion_layers_count"), &TileSet::set_occlusion_layers_count);
|
|
ClassDB::bind_method(D_METHOD("get_occlusion_layers_count"), &TileSet::get_occlusion_layers_count);
|
|
ClassDB::bind_method(D_METHOD("get_occlusion_layers_count"), &TileSet::get_occlusion_layers_count);
|
|
@@ -2670,7 +2653,6 @@ void TileSet::_bind_methods() {
|
|
|
|
|
|
ADD_GROUP("Rendering", "");
|
|
ADD_GROUP("Rendering", "");
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
|
|
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "y_sorting"), "set_y_sorting", "is_y_sorting");
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "occlusion_layers_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_occlusion_layers_count", "get_occlusion_layers_count");
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "occlusion_layers_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_occlusion_layers_count", "get_occlusion_layers_count");
|
|
|
|
|
|
ADD_GROUP("Physics", "");
|
|
ADD_GROUP("Physics", "");
|
|
@@ -2727,12 +2709,6 @@ TileSet::TileSet() {
|
|
// Instantiate the tile meshes.
|
|
// Instantiate the tile meshes.
|
|
tile_lines_mesh.instantiate();
|
|
tile_lines_mesh.instantiate();
|
|
tile_filled_mesh.instantiate();
|
|
tile_filled_mesh.instantiate();
|
|
-
|
|
|
|
- // Instantiate and list all plugins.
|
|
|
|
- tile_set_plugins_vector.append(memnew(TileSetPluginAtlasRendering));
|
|
|
|
- tile_set_plugins_vector.append(memnew(TileSetPluginAtlasPhysics));
|
|
|
|
- tile_set_plugins_vector.append(memnew(TileSetPluginAtlasNavigation));
|
|
|
|
- tile_set_plugins_vector.append(memnew(TileSetPluginScenesCollections));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
TileSet::~TileSet() {
|
|
TileSet::~TileSet() {
|
|
@@ -2744,9 +2720,6 @@ TileSet::~TileSet() {
|
|
while (!source_ids.is_empty()) {
|
|
while (!source_ids.is_empty()) {
|
|
remove_source(source_ids[0]);
|
|
remove_source(source_ids[0]);
|
|
}
|
|
}
|
|
- for (int i = 0; i < tile_set_plugins_vector.size(); i++) {
|
|
|
|
- memdelete(tile_set_plugins_vector[i]);
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////// TileSetSource //////////////////////////////////////
|
|
/////////////////////////////// TileSetSource //////////////////////////////////////
|
|
@@ -2972,23 +2945,22 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
|
|
// Get the alternative tile's properties and append them to the list of properties.
|
|
// Get the alternative tile's properties and append them to the list of properties.
|
|
List<PropertyInfo> alternative_property_list;
|
|
List<PropertyInfo> alternative_property_list;
|
|
E_alternative->get()->get_property_list(&alternative_property_list);
|
|
E_alternative->get()->get_property_list(&alternative_property_list);
|
|
- for (List<PropertyInfo>::Element *E_property = alternative_property_list.front(); E_property; E_property = E_property->next()) {
|
|
|
|
- property_info = E_property->get();
|
|
|
|
|
|
+ for (PropertyInfo &alternative_property_info : alternative_property_list) {
|
|
bool valid;
|
|
bool valid;
|
|
- Variant default_value = ClassDB::class_get_default_property_value("TileData", property_info.name, &valid);
|
|
|
|
- Variant value = E_alternative->get()->get(property_info.name);
|
|
|
|
|
|
+ Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name, &valid);
|
|
|
|
+ Variant value = E_alternative->get()->get(alternative_property_info.name);
|
|
if (valid && value == default_value) {
|
|
if (valid && value == default_value) {
|
|
property_info.usage ^= PROPERTY_USAGE_STORAGE;
|
|
property_info.usage ^= PROPERTY_USAGE_STORAGE;
|
|
}
|
|
}
|
|
- property_info.name = vformat("%s/%s", vformat("%d", E_alternative->key()), property_info.name);
|
|
|
|
- tile_property_list.push_back(property_info);
|
|
|
|
|
|
+ alternative_property_info.name = vformat("%s/%s", vformat("%d", E_alternative->key()), alternative_property_info.name);
|
|
|
|
+ tile_property_list.push_back(alternative_property_info);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Add all alternative.
|
|
// Add all alternative.
|
|
- for (List<PropertyInfo>::Element *E_property = tile_property_list.front(); E_property; E_property = E_property->next()) {
|
|
|
|
- E_property->get().name = vformat("%s/%s", vformat("%d:%d", E_tile->key().x, E_tile->key().y), E_property->get().name);
|
|
|
|
- p_list->push_back(E_property->get());
|
|
|
|
|
|
+ for (PropertyInfo &tile_property_info : tile_property_list) {
|
|
|
|
+ tile_property_info.name = vformat("%s/%s", vformat("%d:%d", E_tile->key().x, E_tile->key().y), tile_property_info.name);
|
|
|
|
+ p_list->push_back(tile_property_info);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -4238,842 +4210,3 @@ void TileData::_bind_methods() {
|
|
|
|
|
|
ADD_SIGNAL(MethodInfo("changed"));
|
|
ADD_SIGNAL(MethodInfo("changed"));
|
|
}
|
|
}
|
|
-/////////////////////////////// TileSetPluginAtlasRendering //////////////////////////////////////
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasRendering::tilemap_notification(TileMap *p_tile_map, int p_what) {
|
|
|
|
- switch (p_what) {
|
|
|
|
- case CanvasItem::NOTIFICATION_VISIBILITY_CHANGED: {
|
|
|
|
- bool visible = p_tile_map->is_visible_in_tree();
|
|
|
|
- for (Map<Vector2i, TileMapQuadrant>::Element *E_quadrant = p_tile_map->get_quadrant_map().front(); E_quadrant; E_quadrant = E_quadrant->next()) {
|
|
|
|
- TileMapQuadrant &q = E_quadrant->get();
|
|
|
|
-
|
|
|
|
- // Update occluders transform.
|
|
|
|
- for (Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator>::Element *E_cell = q.world_to_map.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(E_cell->key());
|
|
|
|
- for (List<RID>::Element *E_occluder_id = q.occluders.front(); E_occluder_id; E_occluder_id = E_occluder_id->next()) {
|
|
|
|
- RS::get_singleton()->canvas_light_occluder_set_enabled(E_occluder_id->get(), visible);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } break;
|
|
|
|
- case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: {
|
|
|
|
- if (!p_tile_map->is_inside_tree()) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (Map<Vector2i, TileMapQuadrant>::Element *E_quadrant = p_tile_map->get_quadrant_map().front(); E_quadrant; E_quadrant = E_quadrant->next()) {
|
|
|
|
- TileMapQuadrant &q = E_quadrant->get();
|
|
|
|
-
|
|
|
|
- // Update occluders transform.
|
|
|
|
- for (Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator>::Element *E_cell = q.world_to_map.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(E_cell->key());
|
|
|
|
- for (List<RID>::Element *E_occluder_id = q.occluders.front(); E_occluder_id; E_occluder_id = E_occluder_id->next()) {
|
|
|
|
- RS::get_singleton()->canvas_light_occluder_set_transform(E_occluder_id->get(), p_tile_map->get_global_transform() * xform);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } break;
|
|
|
|
- case CanvasItem::NOTIFICATION_DRAW: {
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- if (tile_set.is_valid() || p_tile_map->is_y_sort_enabled()) {
|
|
|
|
- RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(p_tile_map->get_canvas_item(), tile_set->is_y_sorting() || p_tile_map->is_y_sort_enabled());
|
|
|
|
- }
|
|
|
|
- } break;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasRendering::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation) {
|
|
|
|
- ERR_FAIL_COND(!p_tile_set.is_valid());
|
|
|
|
- ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
|
|
|
|
- ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
|
|
|
|
- ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
|
|
|
|
-
|
|
|
|
- TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
|
|
|
|
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
|
|
|
- if (atlas_source) {
|
|
|
|
- // Get the texture.
|
|
|
|
- Ref<Texture2D> tex = atlas_source->get_texture();
|
|
|
|
- if (!tex.is_valid()) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Check if we are in the texture, return otherwise.
|
|
|
|
- Vector2i grid_size = atlas_source->get_atlas_grid_size();
|
|
|
|
- if (p_atlas_coords.x >= grid_size.x || p_atlas_coords.y >= grid_size.y) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Get tile data.
|
|
|
|
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile));
|
|
|
|
-
|
|
|
|
- // Compute the offset
|
|
|
|
- Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords);
|
|
|
|
- Vector2i tile_offset = atlas_source->get_tile_effective_texture_offset(p_atlas_coords, p_alternative_tile);
|
|
|
|
-
|
|
|
|
- // Compute the destination rectangle in the CanvasItem.
|
|
|
|
- Rect2 dest_rect;
|
|
|
|
- dest_rect.size = source_rect.size;
|
|
|
|
- dest_rect.size.x += fp_adjust;
|
|
|
|
- dest_rect.size.y += fp_adjust;
|
|
|
|
-
|
|
|
|
- bool transpose = tile_data->get_transpose();
|
|
|
|
- if (transpose) {
|
|
|
|
- dest_rect.position = (p_position - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
|
|
|
|
- } else {
|
|
|
|
- dest_rect.position = (p_position - dest_rect.size / 2 - tile_offset);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (tile_data->get_flip_h()) {
|
|
|
|
- dest_rect.size.x = -dest_rect.size.x;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (tile_data->get_flip_v()) {
|
|
|
|
- dest_rect.size.y = -dest_rect.size.y;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Get the tile modulation.
|
|
|
|
- Color modulate = tile_data->get_modulate();
|
|
|
|
- modulate = Color(modulate.r * p_modulation.r, modulate.g * p_modulation.g, modulate.b * p_modulation.b, modulate.a * p_modulation.a);
|
|
|
|
-
|
|
|
|
- // Draw the tile.
|
|
|
|
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasRendering::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
|
|
|
|
- ERR_FAIL_COND(!p_tile_map);
|
|
|
|
- ERR_FAIL_COND(!p_tile_map->is_inside_tree());
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- bool visible = p_tile_map->is_visible_in_tree();
|
|
|
|
-
|
|
|
|
- SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
|
|
|
|
- while (q_list_element) {
|
|
|
|
- TileMapQuadrant &q = *q_list_element->self();
|
|
|
|
-
|
|
|
|
- RenderingServer *rs = RenderingServer::get_singleton();
|
|
|
|
-
|
|
|
|
- // Free the canvas items.
|
|
|
|
- for (const RID &E : q.canvas_items) {
|
|
|
|
- rs->free(E);
|
|
|
|
- }
|
|
|
|
- q.canvas_items.clear();
|
|
|
|
-
|
|
|
|
- // Free the occluders.
|
|
|
|
- for (const RID &E : q.occluders) {
|
|
|
|
- rs->free(E);
|
|
|
|
- }
|
|
|
|
- q.occluders.clear();
|
|
|
|
-
|
|
|
|
- // Those allow to group cell per material or z-index.
|
|
|
|
- Ref<ShaderMaterial> prev_material;
|
|
|
|
- int prev_z_index = 0;
|
|
|
|
- RID prev_canvas_item;
|
|
|
|
-
|
|
|
|
- // Iterate over the cells of the quadrant.
|
|
|
|
- for (Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator>::Element *E_cell = q.world_to_map.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- TileMapCell c = p_tile_map->get_cell(E_cell->value(), true);
|
|
|
|
-
|
|
|
|
- TileSetSource *source;
|
|
|
|
- if (tile_set->has_source(c.source_id)) {
|
|
|
|
- source = *tile_set->get_source(c.source_id);
|
|
|
|
-
|
|
|
|
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
|
|
|
- if (atlas_source) {
|
|
|
|
- // Get the tile data.
|
|
|
|
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
|
|
|
|
- Ref<ShaderMaterial> mat = tile_data->tile_get_material();
|
|
|
|
- int z_index = tile_data->get_z_index();
|
|
|
|
-
|
|
|
|
- // Quandrant pos.
|
|
|
|
- Vector2 position = p_tile_map->map_to_world(q.coords * p_tile_map->get_effective_quadrant_size());
|
|
|
|
- if (tile_set->is_y_sorting()) {
|
|
|
|
- // When Y-sorting, the quandrant size is sure to be 1, we can thus offset the CanvasItem.
|
|
|
|
- position.y += tile_data->get_y_sort_origin();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // --- CanvasItems ---
|
|
|
|
- // Create two canvas items, for rendering and debug.
|
|
|
|
- RID canvas_item;
|
|
|
|
-
|
|
|
|
- // Check if the material or the z_index changed.
|
|
|
|
- if (prev_canvas_item == RID() || prev_material != mat || prev_z_index != z_index) {
|
|
|
|
- // If so, create a new CanvasItem.
|
|
|
|
- canvas_item = rs->canvas_item_create();
|
|
|
|
- if (mat.is_valid()) {
|
|
|
|
- rs->canvas_item_set_material(canvas_item, mat->get_rid());
|
|
|
|
- }
|
|
|
|
- rs->canvas_item_set_parent(canvas_item, p_tile_map->get_canvas_item());
|
|
|
|
- rs->canvas_item_set_use_parent_material(canvas_item, p_tile_map->get_use_parent_material() || p_tile_map->get_material().is_valid());
|
|
|
|
-
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(position);
|
|
|
|
- rs->canvas_item_set_transform(canvas_item, xform);
|
|
|
|
-
|
|
|
|
- rs->canvas_item_set_light_mask(canvas_item, p_tile_map->get_light_mask());
|
|
|
|
- rs->canvas_item_set_z_index(canvas_item, z_index);
|
|
|
|
-
|
|
|
|
- rs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(p_tile_map->CanvasItem::get_texture_filter()));
|
|
|
|
- rs->canvas_item_set_default_texture_repeat(canvas_item, RS::CanvasItemTextureRepeat(p_tile_map->CanvasItem::get_texture_repeat()));
|
|
|
|
-
|
|
|
|
- q.canvas_items.push_back(canvas_item);
|
|
|
|
-
|
|
|
|
- prev_canvas_item = canvas_item;
|
|
|
|
- prev_material = mat;
|
|
|
|
- prev_z_index = z_index;
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
- // Keep the same canvas_item to draw on.
|
|
|
|
- canvas_item = prev_canvas_item;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Drawing the tile in the canvas item.
|
|
|
|
- draw_tile(canvas_item, E_cell->key() - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, p_tile_map->get_self_modulate());
|
|
|
|
-
|
|
|
|
- // --- Occluders ---
|
|
|
|
- for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(E_cell->key());
|
|
|
|
- if (tile_data->get_occluder(i).is_valid()) {
|
|
|
|
- RID occluder_id = rs->canvas_light_occluder_create();
|
|
|
|
- rs->canvas_light_occluder_set_enabled(occluder_id, visible);
|
|
|
|
- rs->canvas_light_occluder_set_transform(occluder_id, p_tile_map->get_global_transform() * xform);
|
|
|
|
- rs->canvas_light_occluder_set_polygon(occluder_id, tile_data->get_occluder(i)->get_rid());
|
|
|
|
- rs->canvas_light_occluder_attach_to_canvas(occluder_id, p_tile_map->get_canvas());
|
|
|
|
- rs->canvas_light_occluder_set_light_mask(occluder_id, tile_set->get_occlusion_layer_light_mask(i));
|
|
|
|
- q.occluders.push_back(occluder_id);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- quadrant_order_dirty = true;
|
|
|
|
- q_list_element = q_list_element->next();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Reset the drawing indices
|
|
|
|
- if (quadrant_order_dirty) {
|
|
|
|
- int index = -(int64_t)0x80000000; //always must be drawn below children.
|
|
|
|
-
|
|
|
|
- // Sort the quadrants coords per world coordinates
|
|
|
|
- Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> world_to_map;
|
|
|
|
- Map<Vector2i, TileMapQuadrant> quadrant_map = p_tile_map->get_quadrant_map();
|
|
|
|
- for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
|
|
|
|
- world_to_map[p_tile_map->map_to_world(E->key())] = E->key();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Sort the quadrants
|
|
|
|
- for (Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator>::Element *E = world_to_map.front(); E; E = E->next()) {
|
|
|
|
- TileMapQuadrant &q = quadrant_map[E->value()];
|
|
|
|
- for (const RID &F : q.canvas_items) {
|
|
|
|
- RS::get_singleton()->canvas_item_set_draw_index(F, index++);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- quadrant_order_dirty = false;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasRendering::create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- quadrant_order_dirty = true;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasRendering::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- // Free the canvas items.
|
|
|
|
- for (const RID &E : p_quadrant->canvas_items) {
|
|
|
|
- RenderingServer::get_singleton()->free(E);
|
|
|
|
- }
|
|
|
|
- p_quadrant->canvas_items.clear();
|
|
|
|
-
|
|
|
|
- // Free the occluders.
|
|
|
|
- for (const RID &E : p_quadrant->occluders) {
|
|
|
|
- RenderingServer::get_singleton()->free(E);
|
|
|
|
- }
|
|
|
|
- p_quadrant->occluders.clear();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasRendering::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- if (!Engine::get_singleton()->is_editor_hint()) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Draw a placeholder for scenes needing one.
|
|
|
|
- RenderingServer *rs = RenderingServer::get_singleton();
|
|
|
|
- Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size());
|
|
|
|
- for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- const TileMapCell &c = p_tile_map->get_cell(E_cell->get(), true);
|
|
|
|
-
|
|
|
|
- TileSetSource *source;
|
|
|
|
- if (tile_set->has_source(c.source_id)) {
|
|
|
|
- source = *tile_set->get_source(c.source_id);
|
|
|
|
-
|
|
|
|
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
|
|
|
- if (atlas_source) {
|
|
|
|
- Vector2i grid_size = atlas_source->get_atlas_grid_size();
|
|
|
|
- if (!atlas_source->get_texture().is_valid() || c.get_atlas_coords().x >= grid_size.x || c.get_atlas_coords().y >= grid_size.y) {
|
|
|
|
- // Generate a random color from the hashed values of the tiles.
|
|
|
|
- Array to_hash;
|
|
|
|
- to_hash.push_back(c.source_id);
|
|
|
|
- to_hash.push_back(c.get_atlas_coords());
|
|
|
|
- to_hash.push_back(c.alternative_tile);
|
|
|
|
- uint32_t hash = RandomPCG(to_hash.hash()).rand();
|
|
|
|
-
|
|
|
|
- Color color;
|
|
|
|
- color = color.from_hsv(
|
|
|
|
- (float)((hash >> 24) & 0xFF) / 256.0,
|
|
|
|
- Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
|
|
|
|
- Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
|
|
|
|
- 0.8);
|
|
|
|
-
|
|
|
|
- // Draw a placeholder tile.
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
|
|
|
|
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
|
|
|
|
- rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/////////////////////////////// TileSetPluginAtlasPhysics //////////////////////////////////////
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasPhysics::tilemap_notification(TileMap *p_tile_map, int p_what) {
|
|
|
|
- switch (p_what) {
|
|
|
|
- case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: {
|
|
|
|
- // Update the bodies transforms.
|
|
|
|
- if (p_tile_map->is_inside_tree()) {
|
|
|
|
- Map<Vector2i, TileMapQuadrant> quadrant_map = p_tile_map->get_quadrant_map();
|
|
|
|
- Transform2D global_transform = p_tile_map->get_global_transform();
|
|
|
|
-
|
|
|
|
- for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
|
|
|
|
- TileMapQuadrant &q = E->get();
|
|
|
|
-
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(p_tile_map->map_to_world(E->key() * p_tile_map->get_effective_quadrant_size()));
|
|
|
|
- xform = global_transform * xform;
|
|
|
|
-
|
|
|
|
- for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_state(q.bodies[body_index], PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } break;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasPhysics::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
|
|
|
|
- ERR_FAIL_COND(!p_tile_map);
|
|
|
|
- ERR_FAIL_COND(!p_tile_map->is_inside_tree());
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- Transform2D global_transform = p_tile_map->get_global_transform();
|
|
|
|
- PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
|
|
|
|
-
|
|
|
|
- SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
|
|
|
|
- while (q_list_element) {
|
|
|
|
- TileMapQuadrant &q = *q_list_element->self();
|
|
|
|
-
|
|
|
|
- Vector2 quadrant_pos = p_tile_map->map_to_world(q.coords * p_tile_map->get_effective_quadrant_size());
|
|
|
|
-
|
|
|
|
- // Clear shapes.
|
|
|
|
- for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
|
|
|
|
- ps->body_clear_shapes(q.bodies[body_index]);
|
|
|
|
-
|
|
|
|
- // Position the bodies.
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(quadrant_pos);
|
|
|
|
- xform = global_transform * xform;
|
|
|
|
- ps->body_set_state(q.bodies[body_index], PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- TileMapCell c = p_tile_map->get_cell(E_cell->get(), true);
|
|
|
|
-
|
|
|
|
- TileSetSource *source;
|
|
|
|
- if (tile_set->has_source(c.source_id)) {
|
|
|
|
- source = *tile_set->get_source(c.source_id);
|
|
|
|
-
|
|
|
|
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
|
|
|
- if (atlas_source) {
|
|
|
|
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
|
|
|
|
-
|
|
|
|
- for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
|
|
|
|
- // Add the shapes again.
|
|
|
|
- for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(body_index); polygon_index++) {
|
|
|
|
- bool one_way_collision = tile_data->is_collision_polygon_one_way(body_index, polygon_index);
|
|
|
|
- float one_way_collision_margin = tile_data->get_collision_polygon_one_way_margin(body_index, polygon_index);
|
|
|
|
-
|
|
|
|
- int shapes_count = tile_data->get_collision_polygon_shapes_count(body_index, polygon_index);
|
|
|
|
- for (int shape_index = 0; shape_index < shapes_count; shape_index++) {
|
|
|
|
- Transform2D xform = Transform2D();
|
|
|
|
- xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
|
|
|
|
-
|
|
|
|
- // Add decomposed convex shapes.
|
|
|
|
- Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(body_index, polygon_index, shape_index);
|
|
|
|
- ps->body_add_shape(q.bodies[body_index], shape->get_rid(), xform);
|
|
|
|
- ps->body_set_shape_metadata(q.bodies[body_index], shape_index, E_cell->get());
|
|
|
|
- ps->body_set_shape_as_one_way_collision(q.bodies[body_index], shape_index, one_way_collision, one_way_collision_margin);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- q_list_element = q_list_element->next();
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasPhysics::create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- //Get the TileMap's gobla transform.
|
|
|
|
- Transform2D global_transform;
|
|
|
|
- if (p_tile_map->is_inside_tree()) {
|
|
|
|
- global_transform = p_tile_map->get_global_transform();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Clear all bodies.
|
|
|
|
- p_quadrant->bodies.clear();
|
|
|
|
-
|
|
|
|
- // Create the body and set its parameters.
|
|
|
|
- for (int layer_index = 0; layer_index < tile_set->get_physics_layers_count(); layer_index++) {
|
|
|
|
- RID body = PhysicsServer2D::get_singleton()->body_create();
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_mode(body, PhysicsServer2D::BODY_MODE_STATIC);
|
|
|
|
-
|
|
|
|
- PhysicsServer2D::get_singleton()->body_attach_object_instance_id(body, p_tile_map->get_instance_id());
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_collision_layer(body, tile_set->get_physics_layer_collision_layer(layer_index));
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_collision_mask(body, tile_set->get_physics_layer_collision_mask(layer_index));
|
|
|
|
-
|
|
|
|
- Ref<PhysicsMaterial> physics_material = tile_set->get_physics_layer_physics_material(layer_index);
|
|
|
|
- if (!physics_material.is_valid()) {
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, 1);
|
|
|
|
- } else {
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material->computed_bounce());
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, physics_material->computed_friction());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (p_tile_map->is_inside_tree()) {
|
|
|
|
- RID space = p_tile_map->get_world_2d()->get_space();
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_space(body, space);
|
|
|
|
-
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size()));
|
|
|
|
- xform = global_transform * xform;
|
|
|
|
- PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- p_quadrant->bodies.push_back(body);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasPhysics::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- // Remove a quadrant.
|
|
|
|
- for (int body_index = 0; body_index < p_quadrant->bodies.size(); body_index++) {
|
|
|
|
- PhysicsServer2D::get_singleton()->free(p_quadrant->bodies[body_index]);
|
|
|
|
- }
|
|
|
|
- p_quadrant->bodies.clear();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasPhysics::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- // Draw the debug collision shapes.
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- if (!p_tile_map->get_tree()) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- bool show_collision = false;
|
|
|
|
- switch (p_tile_map->get_collision_visibility_mode()) {
|
|
|
|
- case TileMap::VISIBILITY_MODE_DEFAULT:
|
|
|
|
- show_collision = !Engine::get_singleton()->is_editor_hint() && (p_tile_map->get_tree() && p_tile_map->get_tree()->is_debugging_navigation_hint());
|
|
|
|
- break;
|
|
|
|
- case TileMap::VISIBILITY_MODE_FORCE_HIDE:
|
|
|
|
- show_collision = false;
|
|
|
|
- break;
|
|
|
|
- case TileMap::VISIBILITY_MODE_FORCE_SHOW:
|
|
|
|
- show_collision = true;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (!show_collision) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- RenderingServer *rs = RenderingServer::get_singleton();
|
|
|
|
-
|
|
|
|
- Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size());
|
|
|
|
-
|
|
|
|
- Color debug_collision_color = p_tile_map->get_tree()->get_debug_collisions_color();
|
|
|
|
- for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- TileMapCell c = p_tile_map->get_cell(E_cell->get(), true);
|
|
|
|
-
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
|
|
|
|
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
|
|
|
|
-
|
|
|
|
- if (tile_set->has_source(c.source_id)) {
|
|
|
|
- TileSetSource *source = *tile_set->get_source(c.source_id);
|
|
|
|
-
|
|
|
|
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
|
|
|
- if (atlas_source) {
|
|
|
|
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
|
|
|
|
-
|
|
|
|
- for (int body_index = 0; body_index < p_quadrant->bodies.size(); body_index++) {
|
|
|
|
- for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(body_index); polygon_index++) {
|
|
|
|
- // Draw the debug polygon.
|
|
|
|
- Vector<Vector2> polygon = tile_data->get_collision_polygon_points(body_index, polygon_index);
|
|
|
|
- if (polygon.size() >= 3) {
|
|
|
|
- Vector<Color> color;
|
|
|
|
- color.push_back(debug_collision_color);
|
|
|
|
- rs->canvas_item_add_polygon(p_quadrant->debug_canvas_item, polygon, color);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, Transform2D());
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-/////////////////////////////// TileSetPluginAtlasNavigation //////////////////////////////////////
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasNavigation::tilemap_notification(TileMap *p_tile_map, int p_what) {
|
|
|
|
- switch (p_what) {
|
|
|
|
- case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: {
|
|
|
|
- if (p_tile_map->is_inside_tree()) {
|
|
|
|
- Map<Vector2i, TileMapQuadrant> quadrant_map = p_tile_map->get_quadrant_map();
|
|
|
|
- Transform2D tilemap_xform = p_tile_map->get_global_transform();
|
|
|
|
- for (Map<Vector2i, TileMapQuadrant>::Element *E_quadrant = quadrant_map.front(); E_quadrant; E_quadrant = E_quadrant->next()) {
|
|
|
|
- TileMapQuadrant &q = E_quadrant->get();
|
|
|
|
- for (Map<Vector2i, Vector<RID>>::Element *E_region = q.navigation_regions.front(); E_region; E_region = E_region->next()) {
|
|
|
|
- for (int layer_index = 0; layer_index < E_region->get().size(); layer_index++) {
|
|
|
|
- RID region = E_region->get()[layer_index];
|
|
|
|
- if (!region.is_valid()) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- Transform2D tile_transform;
|
|
|
|
- tile_transform.set_origin(p_tile_map->map_to_world(E_region->key()));
|
|
|
|
- NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } break;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasNavigation::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
|
|
|
|
- ERR_FAIL_COND(!p_tile_map);
|
|
|
|
- ERR_FAIL_COND(!p_tile_map->is_inside_tree());
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- // Get colors for debug.
|
|
|
|
- SceneTree *st = SceneTree::get_singleton();
|
|
|
|
- Color debug_navigation_color;
|
|
|
|
- bool debug_navigation = st && st->is_debugging_navigation_hint();
|
|
|
|
- if (debug_navigation) {
|
|
|
|
- debug_navigation_color = st->get_debug_navigation_color();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Transform2D tilemap_xform = p_tile_map->get_global_transform();
|
|
|
|
- SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
|
|
|
|
- while (q_list_element) {
|
|
|
|
- TileMapQuadrant &q = *q_list_element->self();
|
|
|
|
-
|
|
|
|
- // Clear navigation shapes in the quadrant.
|
|
|
|
- for (Map<Vector2i, Vector<RID>>::Element *E = q.navigation_regions.front(); E; E = E->next()) {
|
|
|
|
- for (int i = 0; i < E->get().size(); i++) {
|
|
|
|
- RID region = E->get()[i];
|
|
|
|
- if (!region.is_valid()) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- NavigationServer2D::get_singleton()->region_set_map(region, RID());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- q.navigation_regions.clear();
|
|
|
|
-
|
|
|
|
- // Get the navigation polygons and create regions.
|
|
|
|
- for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- TileMapCell c = p_tile_map->get_cell(E_cell->get(), true);
|
|
|
|
-
|
|
|
|
- TileSetSource *source;
|
|
|
|
- if (tile_set->has_source(c.source_id)) {
|
|
|
|
- source = *tile_set->get_source(c.source_id);
|
|
|
|
-
|
|
|
|
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
|
|
|
- if (atlas_source) {
|
|
|
|
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
|
|
|
|
- q.navigation_regions[E_cell->get()].resize(tile_set->get_navigation_layers_count());
|
|
|
|
-
|
|
|
|
- for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
|
|
|
|
- Ref<NavigationPolygon> navpoly;
|
|
|
|
- navpoly = tile_data->get_navigation_polygon(layer_index);
|
|
|
|
-
|
|
|
|
- if (navpoly.is_valid()) {
|
|
|
|
- Transform2D tile_transform;
|
|
|
|
- tile_transform.set_origin(p_tile_map->map_to_world(E_cell->get()));
|
|
|
|
-
|
|
|
|
- RID region = NavigationServer2D::get_singleton()->region_create();
|
|
|
|
- NavigationServer2D::get_singleton()->region_set_map(region, p_tile_map->get_world_2d()->get_navigation_map());
|
|
|
|
- NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
|
|
|
|
- NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
|
|
|
|
- q.navigation_regions[E_cell->get()].write[layer_index] = region;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- q_list_element = q_list_element->next();
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasNavigation::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- // Clear navigation shapes in the quadrant.
|
|
|
|
- for (Map<Vector2i, Vector<RID>>::Element *E = p_quadrant->navigation_regions.front(); E; E = E->next()) {
|
|
|
|
- for (int i = 0; i < E->get().size(); i++) {
|
|
|
|
- RID region = E->get()[i];
|
|
|
|
- if (!region.is_valid()) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- NavigationServer2D::get_singleton()->free(region);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- p_quadrant->navigation_regions.clear();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginAtlasNavigation::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- // Draw the debug collision shapes.
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- if (!p_tile_map->get_tree()) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- bool show_navigation = false;
|
|
|
|
- switch (p_tile_map->get_navigation_visibility_mode()) {
|
|
|
|
- case TileMap::VISIBILITY_MODE_DEFAULT:
|
|
|
|
- show_navigation = !Engine::get_singleton()->is_editor_hint() && (p_tile_map->get_tree() && p_tile_map->get_tree()->is_debugging_navigation_hint());
|
|
|
|
- break;
|
|
|
|
- case TileMap::VISIBILITY_MODE_FORCE_HIDE:
|
|
|
|
- show_navigation = false;
|
|
|
|
- break;
|
|
|
|
- case TileMap::VISIBILITY_MODE_FORCE_SHOW:
|
|
|
|
- show_navigation = true;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (!show_navigation) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- RenderingServer *rs = RenderingServer::get_singleton();
|
|
|
|
-
|
|
|
|
- Color color = p_tile_map->get_tree()->get_debug_navigation_color();
|
|
|
|
- RandomPCG rand;
|
|
|
|
-
|
|
|
|
- Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size());
|
|
|
|
-
|
|
|
|
- for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- TileMapCell c = p_tile_map->get_cell(E_cell->get(), true);
|
|
|
|
-
|
|
|
|
- TileSetSource *source;
|
|
|
|
- if (tile_set->has_source(c.source_id)) {
|
|
|
|
- source = *tile_set->get_source(c.source_id);
|
|
|
|
-
|
|
|
|
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
|
|
|
- if (atlas_source) {
|
|
|
|
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
|
|
|
|
-
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
|
|
|
|
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
|
|
|
|
-
|
|
|
|
- for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
|
|
|
|
- Ref<NavigationPolygon> navpoly = tile_data->get_navigation_polygon(layer_index);
|
|
|
|
- if (navpoly.is_valid()) {
|
|
|
|
- PackedVector2Array navigation_polygon_vertices = navpoly->get_vertices();
|
|
|
|
-
|
|
|
|
- for (int i = 0; i < navpoly->get_polygon_count(); i++) {
|
|
|
|
- // An array of vertices for this polygon.
|
|
|
|
- Vector<int> polygon = navpoly->get_polygon(i);
|
|
|
|
- Vector<Vector2> vertices;
|
|
|
|
- vertices.resize(polygon.size());
|
|
|
|
- for (int j = 0; j < polygon.size(); j++) {
|
|
|
|
- ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size());
|
|
|
|
- vertices.write[j] = navigation_polygon_vertices[polygon[j]];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Generate the polygon color, slightly randomly modified from the settings one.
|
|
|
|
- Color random_variation_color;
|
|
|
|
- random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1);
|
|
|
|
- random_variation_color.a = color.a;
|
|
|
|
- Vector<Color> colors;
|
|
|
|
- colors.push_back(random_variation_color);
|
|
|
|
-
|
|
|
|
- rs->canvas_item_add_polygon(p_quadrant->debug_canvas_item, vertices, colors);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/////////////////////////////// TileSetPluginScenesCollections //////////////////////////////////////
|
|
|
|
-
|
|
|
|
-void TileSetPluginScenesCollections::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
|
|
|
|
- while (q_list_element) {
|
|
|
|
- TileMapQuadrant &q = *q_list_element->self();
|
|
|
|
-
|
|
|
|
- // Clear the scenes.
|
|
|
|
- for (Map<Vector2i, String>::Element *E = q.scenes.front(); E; E = E->next()) {
|
|
|
|
- Node *node = p_tile_map->get_node(E->get());
|
|
|
|
- if (node) {
|
|
|
|
- node->queue_delete();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- q.scenes.clear();
|
|
|
|
-
|
|
|
|
- // Recreate the scenes.
|
|
|
|
- for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- const TileMapCell &c = p_tile_map->get_cell(E_cell->get(), true);
|
|
|
|
-
|
|
|
|
- TileSetSource *source;
|
|
|
|
- if (tile_set->has_source(c.source_id)) {
|
|
|
|
- source = *tile_set->get_source(c.source_id);
|
|
|
|
-
|
|
|
|
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
|
|
|
|
- if (scenes_collection_source) {
|
|
|
|
- Ref<PackedScene> packed_scene = scenes_collection_source->get_scene_tile_scene(c.alternative_tile);
|
|
|
|
- if (packed_scene.is_valid()) {
|
|
|
|
- Node *scene = packed_scene->instantiate();
|
|
|
|
- p_tile_map->add_child(scene);
|
|
|
|
- Control *scene_as_control = Object::cast_to<Control>(scene);
|
|
|
|
- Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene);
|
|
|
|
- if (scene_as_control) {
|
|
|
|
- scene_as_control->set_position(p_tile_map->map_to_world(E_cell->get()) + scene_as_control->get_position());
|
|
|
|
- } else if (scene_as_node2d) {
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(p_tile_map->map_to_world(E_cell->get()));
|
|
|
|
- scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
|
|
|
|
- }
|
|
|
|
- q.scenes[E_cell->get()] = scene->get_name();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- q_list_element = q_list_element->next();
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginScenesCollections::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- // Clear the scenes.
|
|
|
|
- for (Map<Vector2i, String>::Element *E = p_quadrant->scenes.front(); E; E = E->next()) {
|
|
|
|
- Node *node = p_tile_map->get_node(E->get());
|
|
|
|
- if (node) {
|
|
|
|
- node->queue_delete();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- p_quadrant->scenes.clear();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-void TileSetPluginScenesCollections::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
|
|
|
|
- Ref<TileSet> tile_set = p_tile_map->get_tileset();
|
|
|
|
- ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
-
|
|
|
|
- if (!Engine::get_singleton()->is_editor_hint()) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Draw a placeholder for scenes needing one.
|
|
|
|
- RenderingServer *rs = RenderingServer::get_singleton();
|
|
|
|
- Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size());
|
|
|
|
- for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
|
|
|
|
- const TileMapCell &c = p_tile_map->get_cell(E_cell->get(), true);
|
|
|
|
-
|
|
|
|
- TileSetSource *source;
|
|
|
|
- if (tile_set->has_source(c.source_id)) {
|
|
|
|
- source = *tile_set->get_source(c.source_id);
|
|
|
|
-
|
|
|
|
- if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
|
|
|
|
- if (scenes_collection_source) {
|
|
|
|
- if (!scenes_collection_source->get_scene_tile_scene(c.alternative_tile).is_valid() || scenes_collection_source->get_scene_tile_display_placeholder(c.alternative_tile)) {
|
|
|
|
- // Generate a random color from the hashed values of the tiles.
|
|
|
|
- Array to_hash;
|
|
|
|
- to_hash.push_back(c.source_id);
|
|
|
|
- to_hash.push_back(c.alternative_tile);
|
|
|
|
- uint32_t hash = RandomPCG(to_hash.hash()).rand();
|
|
|
|
-
|
|
|
|
- Color color;
|
|
|
|
- color = color.from_hsv(
|
|
|
|
- (float)((hash >> 24) & 0xFF) / 256.0,
|
|
|
|
- Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
|
|
|
|
- Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
|
|
|
|
- 0.8);
|
|
|
|
-
|
|
|
|
- // Draw a placeholder tile.
|
|
|
|
- Transform2D xform;
|
|
|
|
- xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
|
|
|
|
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
|
|
|
|
- rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|