Implement multiple occlusion polygons within each TileSet occlusion layer

This commit is contained in:
Gilles Roudière 2024-06-11 12:59:55 +02:00
parent 8120e0324a
commit d75c5ec7ba
8 changed files with 345 additions and 114 deletions

View file

@ -3444,7 +3444,8 @@ void TileSet::_compatibility_conversion() {
polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0);
}
occluder->set_polygon(polygon);
tile_data->set_occluder(0, occluder);
tile_data->add_occluder_polygon(0);
tile_data->set_occluder_polygon(0, 0, occluder);
}
if (ctd->navigation.is_valid()) {
if (get_navigation_layers_count() < 1) {
@ -3558,7 +3559,8 @@ void TileSet::_compatibility_conversion() {
polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0);
}
occluder->set_polygon(polygon);
tile_data->set_occluder(0, occluder);
tile_data->add_occluder_polygon(0);
tile_data->set_occluder_polygon(0, 0, occluder);
}
if (ctd->autotile_navpoly_map.has(coords)) {
if (get_navigation_layers_count() < 1) {
@ -6220,33 +6222,86 @@ int TileData::get_y_sort_origin() const {
return y_sort_origin;
}
#ifndef DISABLE_DEPRECATED
void TileData::set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon) {
ERR_FAIL_INDEX(p_layer_id, occluders.size());
occluders.write[p_layer_id].occluder = p_occluder_polygon;
occluders.write[p_layer_id].transformed_occluders.clear();
if (get_occluder_polygons_count(p_layer_id) == 0) {
add_occluder_polygon(p_layer_id);
}
set_occluder_polygon(p_layer_id, 0, p_occluder_polygon);
emit_signal(CoreStringName(changed));
}
Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref<OccluderPolygon2D>());
if (get_occluder_polygons_count(p_layer_id) == 0) {
return Ref<OccluderPolygon2D>();
}
return get_occluder_polygon(p_layer_id, 0, p_flip_h, p_flip_v, p_transpose);
}
#endif // DISABLE_DEPRECATED
void TileData::set_occluder_polygons_count(int p_layer_id, int p_polygons_count) {
ERR_FAIL_INDEX(p_layer_id, occluders.size());
ERR_FAIL_COND(p_polygons_count < 0);
if (p_polygons_count == occluders.write[p_layer_id].polygons.size()) {
return;
}
occluders.write[p_layer_id].polygons.resize(p_polygons_count);
notify_property_list_changed();
emit_signal(CoreStringName(changed));
}
int TileData::get_occluder_polygons_count(int p_layer_id) const {
ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), 0);
return occluders[p_layer_id].polygons.size();
}
void TileData::add_occluder_polygon(int p_layer_id) {
ERR_FAIL_INDEX(p_layer_id, occluders.size());
occluders.write[p_layer_id].polygons.push_back(OcclusionLayerTileData::PolygonOccluderTileData());
emit_signal(CoreStringName(changed));
}
void TileData::remove_occluder_polygon(int p_layer_id, int p_polygon_index) {
ERR_FAIL_INDEX(p_layer_id, occluders.size());
ERR_FAIL_INDEX(p_polygon_index, occluders[p_layer_id].polygons.size());
occluders.write[p_layer_id].polygons.remove_at(p_polygon_index);
emit_signal(CoreStringName(changed));
}
void TileData::set_occluder_polygon(int p_layer_id, int p_polygon_index, const Ref<OccluderPolygon2D> &p_occluder_polygon) {
ERR_FAIL_INDEX(p_layer_id, occluders.size());
ERR_FAIL_INDEX(p_polygon_index, occluders[p_layer_id].polygons.size());
OcclusionLayerTileData::PolygonOccluderTileData &polygon_occluder_tile_data = occluders.write[p_layer_id].polygons.write[p_polygon_index];
polygon_occluder_tile_data.occluder_polygon = p_occluder_polygon;
polygon_occluder_tile_data.transformed_polygon_occluders.clear();
emit_signal(CoreStringName(changed));
}
Ref<OccluderPolygon2D> TileData::get_occluder_polygon(int p_layer_id, int p_polygon_index, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref<OccluderPolygon2D>());
ERR_FAIL_INDEX_V(p_polygon_index, occluders[p_layer_id].polygons.size(), Ref<OccluderPolygon2D>());
const OcclusionLayerTileData &layer_tile_data = occluders[p_layer_id];
const Ref<OccluderPolygon2D> &occluder_polygon = layer_tile_data.polygons[p_polygon_index].occluder_polygon;
int key = int(p_flip_h) | int(p_flip_v) << 1 | int(p_transpose) << 2;
if (key == 0) {
return layer_tile_data.occluder;
return occluder_polygon;
}
if (layer_tile_data.occluder.is_null()) {
if (occluder_polygon.is_null()) {
return Ref<OccluderPolygon2D>();
}
HashMap<int, Ref<OccluderPolygon2D>>::Iterator I = layer_tile_data.transformed_occluders.find(key);
HashMap<int, Ref<OccluderPolygon2D>>::Iterator I = layer_tile_data.polygons[p_polygon_index].transformed_polygon_occluders.find(key);
if (!I) {
Ref<OccluderPolygon2D> transformed_polygon;
transformed_polygon.instantiate();
transformed_polygon->set_polygon(get_transformed_vertices(layer_tile_data.occluder->get_polygon(), p_flip_h, p_flip_v, p_transpose));
layer_tile_data.transformed_occluders[key] = transformed_polygon;
transformed_polygon->set_polygon(get_transformed_vertices(occluder_polygon->get_polygon(), p_flip_h, p_flip_v, p_transpose));
layer_tile_data.polygons[p_polygon_index].transformed_polygon_occluders[key] = transformed_polygon;
return transformed_polygon;
} else {
return I->value;
@ -6594,13 +6649,37 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
#endif
Vector<String> components = String(p_name).split("/", true, 2);
if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
if (components.size() >= 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
// Occlusion layers.
int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
ERR_FAIL_COND_V(layer_index < 0, false);
if (components[1] == "polygon") {
Ref<OccluderPolygon2D> polygon = p_value;
if (components.size() == 2) {
if (components[1] == "polygon") {
// Kept for compatibility.
Ref<OccluderPolygon2D> polygon = p_value;
if (layer_index >= occluders.size()) {
if (tile_set) {
return false;
} else {
occluders.resize(layer_index + 1);
}
}
if (get_occluder_polygons_count(layer_index) == 0) {
add_occluder_polygon(layer_index);
}
set_occluder_polygon(layer_index, 0, polygon);
return true;
} else if (components[1] == "polygons_count") {
if (p_value.get_type() != Variant::INT) {
return false;
}
set_occluder_polygons_count(layer_index, p_value);
return true;
}
} else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
// Polygons.
int polygon_index = components[1].trim_prefix("polygon_").to_int();
ERR_FAIL_COND_V(polygon_index < 0, false);
if (layer_index >= occluders.size()) {
if (tile_set) {
@ -6609,8 +6688,16 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
occluders.resize(layer_index + 1);
}
}
set_occluder(layer_index, polygon);
return true;
if (polygon_index >= occluders[layer_index].polygons.size()) {
occluders.write[layer_index].polygons.resize(polygon_index + 1);
}
if (components[2] == "polygon") {
Ref<OccluderPolygon2D> polygon = p_value;
set_occluder_polygon(layer_index, polygon_index, polygon);
return true;
}
}
} else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
// Physics layers.
@ -6638,6 +6725,7 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
} else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
// Polygons.
int polygon_index = components[1].trim_prefix("polygon_").to_int();
ERR_FAIL_COND_V(polygon_index < 0, false);
@ -6724,16 +6812,36 @@ bool TileData::_get(const StringName &p_name, Variant &r_ret) const {
Vector<String> components = String(p_name).split("/", true, 2);
if (tile_set) {
if (components.size() == 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
if (components.size() >= 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
// Occlusion layers.
int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
ERR_FAIL_COND_V(layer_index < 0, false);
if (layer_index >= occluders.size()) {
return false;
}
if (components[1] == "polygon") {
r_ret = get_occluder(layer_index);
return true;
if (components.size() == 2) {
if (components[1] == "polygon") {
// Kept for compatibility.
if (occluders[layer_index].polygons.is_empty()) {
return false;
}
r_ret = get_occluder_polygon(layer_index, 0);
return true;
} else if (components[1] == "polygons_count") {
r_ret = get_occluder_polygons_count(layer_index);
return true;
}
} else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
// Polygons.
int polygon_index = components[1].trim_prefix("polygon_").to_int();
ERR_FAIL_COND_V(polygon_index < 0, false);
if (polygon_index >= occluders[layer_index].polygons.size()) {
return false;
}
if (components[2] == "polygon") {
r_ret = get_occluder_polygon(layer_index, polygon_index);
return true;
}
}
} else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
// Physics layers.
@ -6813,12 +6921,15 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
// Occlusion layers.
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Rendering", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
for (int i = 0; i < occluders.size(); i++) {
// occlusion_layer_%d/polygon
property_info = PropertyInfo(Variant::OBJECT, vformat("occlusion_layer_%d/%s", i, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_DEFAULT);
if (occluders[i].occluder.is_null()) {
property_info.usage ^= PROPERTY_USAGE_STORAGE;
p_list->push_back(PropertyInfo(Variant::INT, vformat("occlusion_layer_%d/%s", i, PNAME("polygons_count")), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
for (int j = 0; j < occluders[i].polygons.size(); j++) {
// occlusion_layer_%d/polygon_%d/polygon
property_info = PropertyInfo(Variant::OBJECT, vformat("occlusion_layer_%d/polygon_%d/%s", i, j, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_DEFAULT);
if (occluders[i].polygons[j].occluder_polygon.is_null()) {
property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
p_list->push_back(property_info);
}
p_list->push_back(property_info);
}
// Physics layers.
@ -6923,8 +7034,17 @@ void TileData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_y_sort_origin", "y_sort_origin"), &TileData::set_y_sort_origin);
ClassDB::bind_method(D_METHOD("get_y_sort_origin"), &TileData::get_y_sort_origin);
ClassDB::bind_method(D_METHOD("set_occluder_polygons_count", "layer_id", "polygons_count"), &TileData::set_occluder_polygons_count);
ClassDB::bind_method(D_METHOD("get_occluder_polygons_count", "layer_id"), &TileData::get_occluder_polygons_count);
ClassDB::bind_method(D_METHOD("add_occluder_polygon", "layer_id"), &TileData::add_occluder_polygon);
ClassDB::bind_method(D_METHOD("remove_occluder_polygon", "layer_id", "polygon_index"), &TileData::remove_occluder_polygon);
ClassDB::bind_method(D_METHOD("set_occluder_polygon", "layer_id", "polygon_index", "polygon"), &TileData::set_occluder_polygon);
ClassDB::bind_method(D_METHOD("get_occluder_polygon", "layer_id", "polygon_index", "flip_h", "flip_v", "transpose"), &TileData::get_occluder_polygon, DEFVAL(false), DEFVAL(false), DEFVAL(false));
#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_occluder", "layer_id", "occluder_polygon"), &TileData::set_occluder);
ClassDB::bind_method(D_METHOD("get_occluder", "layer_id", "flip_h", "flip_v", "transpose"), &TileData::get_occluder, DEFVAL(false), DEFVAL(false), DEFVAL(false));
#endif // DISABLE_DEPRECATED
// Physics.
ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "layer_id", "velocity"), &TileData::set_constant_linear_velocity);