Merge pull request #93029 from groud/multiple_occlusion_polygons

Implement multiple occlusion polygons within each TileSet occlusion layer
This commit is contained in:
Rémi Verschelde 2024-09-03 16:13:36 +02:00
commit ec7fc97972
No known key found for this signature in database
GPG Key ID: C3336907360768E1
8 changed files with 345 additions and 114 deletions

View File

@ -16,6 +16,13 @@
Adds a collision polygon to the tile on the given TileSet physics layer.
</description>
</method>
<method name="add_occluder_polygon">
<return type="void" />
<param index="0" name="layer_id" type="int" />
<description>
Adds an occlusion polygon to the tile on the TileSet occlusion layer with index [param layer_id].
</description>
</method>
<method name="get_collision_polygon_one_way_margin" qualifiers="const">
<return type="float" />
<param index="0" name="layer_id" type="int" />
@ -78,7 +85,7 @@
[param flip_h], [param flip_v], and [param transpose] allow transforming the returned polygon.
</description>
</method>
<method name="get_occluder" qualifiers="const">
<method name="get_occluder" qualifiers="const" deprecated="Use [method get_occluder_polygon] instead.">
<return type="OccluderPolygon2D" />
<param index="0" name="layer_id" type="int" />
<param index="1" name="flip_h" type="bool" default="false" />
@ -89,6 +96,25 @@
[param flip_h], [param flip_v], and [param transpose] allow transforming the returned polygon.
</description>
</method>
<method name="get_occluder_polygon" qualifiers="const">
<return type="OccluderPolygon2D" />
<param index="0" name="layer_id" type="int" />
<param index="1" name="polygon_index" type="int" />
<param index="2" name="flip_h" type="bool" default="false" />
<param index="3" name="flip_v" type="bool" default="false" />
<param index="4" name="transpose" type="bool" default="false" />
<description>
Returns the occluder polygon at index [param polygon_index] from the TileSet occlusion layer with index [param layer_id].
The [param flip_h], [param flip_v], and [param transpose] parameters can be [code]true[/code] to transform the returned polygon.
</description>
</method>
<method name="get_occluder_polygons_count" qualifiers="const">
<return type="int" />
<param index="0" name="layer_id" type="int" />
<description>
Returns the number of occluder polygons of the tile in the TileSet occlusion layer with index [param layer_id].
</description>
</method>
<method name="get_terrain_peering_bit" qualifiers="const">
<return type="int" />
<param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
@ -119,6 +145,14 @@
Removes the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="remove_occluder_polygon">
<return type="void" />
<param index="0" name="layer_id" type="int" />
<param index="1" name="polygon_index" type="int" />
<description>
Removes the polygon at index [param polygon_index] for TileSet occlusion layer with index [param layer_id].
</description>
</method>
<method name="set_collision_polygon_one_way">
<return type="void" />
<param index="0" name="layer_id" type="int" />
@ -194,7 +228,7 @@
Sets the navigation polygon for the TileSet navigation layer with index [param layer_id].
</description>
</method>
<method name="set_occluder">
<method name="set_occluder" deprecated="Use [method set_occluder_polygon] instead.">
<return type="void" />
<param index="0" name="layer_id" type="int" />
<param index="1" name="occluder_polygon" type="OccluderPolygon2D" />
@ -202,6 +236,23 @@
Sets the occluder for the TileSet occlusion layer with index [param layer_id].
</description>
</method>
<method name="set_occluder_polygon">
<return type="void" />
<param index="0" name="layer_id" type="int" />
<param index="1" name="polygon_index" type="int" />
<param index="2" name="polygon" type="OccluderPolygon2D" />
<description>
Sets the occluder for polygon with index [param polygon_index] in the TileSet occlusion layer with index [param layer_id].
</description>
</method>
<method name="set_occluder_polygons_count">
<return type="void" />
<param index="0" name="layer_id" type="int" />
<param index="1" name="polygons_count" type="int" />
<description>
Sets the occluder polygon count in the TileSet occlusion layer with index [param layer_id].
</description>
</method>
<method name="set_terrain_peering_bit">
<return type="void" />
<param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />

View File

@ -1482,30 +1482,36 @@ void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Tra
debug_occlusion_color.push_back(color);
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
Ref<OccluderPolygon2D> occluder = tile_data->get_occluder(occlusion_layer);
if (occluder.is_valid() && occluder->get_polygon().size() >= 3) {
p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color);
for (int i = 0; i < tile_data->get_occluder_polygons_count(occlusion_layer); i++) {
Ref<OccluderPolygon2D> occluder = tile_data->get_occluder_polygon(occlusion_layer, i);
if (occluder.is_valid() && occluder->get_polygon().size() >= 3) {
p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color);
}
}
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
}
Variant TileDataOcclusionShapeEditor::_get_painted_value() {
Ref<OccluderPolygon2D> occluder_polygon;
if (polygon_editor->get_polygon_count() >= 1) {
Array polygons;
for (int i = 0; i < polygon_editor->get_polygon_count(); i++) {
Ref<OccluderPolygon2D> occluder_polygon;
occluder_polygon.instantiate();
occluder_polygon->set_polygon(polygon_editor->get_polygon(0));
occluder_polygon->set_polygon(polygon_editor->get_polygon(i));
polygons.push_back(occluder_polygon);
}
return occluder_polygon;
return polygons;
}
void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_NULL(tile_data);
Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer);
polygon_editor->clear_polygons();
if (occluder_polygon.is_valid()) {
polygon_editor->add_polygon(occluder_polygon->get_polygon());
for (int i = 0; i < tile_data->get_occluder_polygons_count(occlusion_layer); i++) {
Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder_polygon(occlusion_layer, i);
if (occluder_polygon.is_valid()) {
polygon_editor->add_polygon(occluder_polygon->get_polygon());
}
}
polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile);
}
@ -1513,8 +1519,13 @@ void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile
void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_NULL(tile_data);
Ref<OccluderPolygon2D> occluder_polygon = p_value;
tile_data->set_occluder(occlusion_layer, occluder_polygon);
Array polygons = p_value;
tile_data->set_occluder_polygons_count(occlusion_layer, polygons.size());
for (int i = 0; i < polygons.size(); i++) {
Ref<OccluderPolygon2D> occluder_polygon = polygons[i];
tile_data->set_occluder_polygon(occlusion_layer, i, occluder_polygon);
}
polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile);
}
@ -1522,7 +1533,11 @@ void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atl
Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_NULL_V(tile_data, Variant());
return tile_data->get_occluder(occlusion_layer);
Array polygons;
for (int i = 0; i < tile_data->get_occluder_polygons_count(occlusion_layer); i++) {
polygons.push_back(tile_data->get_occluder_polygon(occlusion_layer, i));
}
return polygons;
}
void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value) {
@ -1548,6 +1563,7 @@ void TileDataOcclusionShapeEditor::_notification(int p_what) {
TileDataOcclusionShapeEditor::TileDataOcclusionShapeEditor() {
polygon_editor = memnew(GenericTilePolygonEditor);
polygon_editor->set_multiple_polygon_mode(true);
add_child(polygon_editor);
}

View File

@ -2768,15 +2768,7 @@ void EditorPropertyTilePolygon::_add_focusable_children(Node *p_node) {
void EditorPropertyTilePolygon::_polygons_changed() {
if (String(count_property).is_empty()) {
if (base_type == "OccluderPolygon2D") {
// Single OccluderPolygon2D.
Ref<OccluderPolygon2D> occluder;
if (generic_tile_polygon_editor->get_polygon_count() >= 1) {
occluder.instantiate();
occluder->set_polygon(generic_tile_polygon_editor->get_polygon(0));
}
emit_changed(get_edited_property(), occluder);
} else if (base_type == "NavigationPolygon") {
if (base_type == "NavigationPolygon") {
Ref<NavigationPolygon> navigation_polygon;
if (generic_tile_polygon_editor->get_polygon_count() >= 1) {
navigation_polygon.instantiate();
@ -2798,19 +2790,24 @@ void EditorPropertyTilePolygon::_polygons_changed() {
emit_changed(get_edited_property(), navigation_polygon);
}
} else {
if (base_type.is_empty()) {
// Multiple array of vertices.
Vector<String> changed_properties;
Array values;
int count = generic_tile_polygon_editor->get_polygon_count();
changed_properties.push_back(count_property);
values.push_back(count);
for (int i = 0; i < count; i++) {
changed_properties.push_back(vformat(element_pattern, i));
// Multiple array of vertices or OccluderPolygon2D.
Vector<String> changed_properties;
Array values;
int count = generic_tile_polygon_editor->get_polygon_count();
changed_properties.push_back(count_property);
values.push_back(count);
for (int i = 0; i < count; i++) {
changed_properties.push_back(vformat(element_pattern, i));
if (base_type.is_empty()) {
values.push_back(generic_tile_polygon_editor->get_polygon(i));
} else if (base_type == "OccluderPolygon2D") {
Ref<OccluderPolygon2D> occluder;
occluder.instantiate();
occluder->set_polygon(generic_tile_polygon_editor->get_polygon(i));
values.push_back(occluder);
}
emit_signal(SNAME("multiple_properties_changed"), changed_properties, values, false);
}
emit_signal(SNAME("multiple_properties_changed"), changed_properties, values, false);
}
}
@ -2834,15 +2831,8 @@ void EditorPropertyTilePolygon::update_property() {
generic_tile_polygon_editor->clear_polygons();
if (String(count_property).is_empty()) {
if (base_type == "OccluderPolygon2D") {
// Single OccluderPolygon2D.
Ref<OccluderPolygon2D> occluder = get_edited_property_value();
generic_tile_polygon_editor->clear_polygons();
if (occluder.is_valid()) {
generic_tile_polygon_editor->add_polygon(occluder->get_polygon());
}
} else if (base_type == "NavigationPolygon") {
// Single OccluderPolygon2D.
if (base_type == "NavigationPolygon") {
// Single NavigationPolygon.
Ref<NavigationPolygon> navigation_polygon = get_edited_property_value();
generic_tile_polygon_editor->clear_polygons();
if (navigation_polygon.is_valid()) {
@ -2859,6 +2849,15 @@ void EditorPropertyTilePolygon::update_property() {
for (int i = 0; i < count; i++) {
generic_tile_polygon_editor->add_polygon(get_edited_object()->get(vformat(element_pattern, i)));
}
} else if (base_type == "OccluderPolygon2D") {
// Multiple OccluderPolygon2D.
generic_tile_polygon_editor->clear_polygons();
for (int i = 0; i < count; i++) {
Ref<OccluderPolygon2D> occluder = get_edited_object()->get(vformat(element_pattern, i));
if (occluder.is_valid()) {
generic_tile_polygon_editor->add_polygon(occluder->get_polygon());
}
}
}
}
}
@ -2899,16 +2898,30 @@ bool EditorInspectorPluginTileData::can_handle(Object *p_object) {
bool EditorInspectorPluginTileData::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
Vector<String> components = String(p_path).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") {
if (components[1] == "polygons_count") {
EditorPropertyTilePolygon *ep = memnew(EditorPropertyTilePolygon);
ep->setup_single_mode(p_path, "OccluderPolygon2D");
add_property_editor(p_path, ep);
ep->setup_multiple_mode(vformat("occlusion_layer_%d/polygons", layer_index), vformat("occlusion_layer_%d/polygons_count", layer_index), vformat("occlusion_layer_%d/polygon_%%d/polygon", layer_index), "OccluderPolygon2D");
Vector<String> properties;
properties.push_back(p_path);
int count = p_object->get(vformat("occlusion_layer_%d/polygons_count", layer_index));
for (int i = 0; i < count; i++) {
properties.push_back(vformat("occlusion_layer_%d/polygon_%d/polygon", layer_index, i));
}
add_property_editor_for_multiple_properties("Polygons", properties, ep);
return true;
}
// We keep the original editor for now, but here is the code that could be used if we need a custom editor for each polygon:
/*else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
int polygon_index = components[1].trim_prefix("polygon_").to_int();
ERR_FAIL_COND_V(polygon_index < 0, false);
if (components[2] == "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.
int layer_index = components[0].trim_prefix("physics_layer_").to_int();

View File

@ -443,13 +443,15 @@ void TileMapLayer::_rendering_notification(int p_what) {
Transform2D tilemap_xform = get_global_transform();
for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) {
const CellData &cell_data = kv.value;
for (const RID &occluder : cell_data.occluders) {
if (occluder.is_null()) {
continue;
for (const LocalVector<RID> &polygons : cell_data.occluders) {
for (const RID &rid : polygons) {
if (rid.is_null()) {
continue;
}
Transform2D xform(0, tile_set->map_to_local(kv.key));
rs->canvas_light_occluder_attach_to_canvas(rid, get_canvas());
rs->canvas_light_occluder_set_transform(rid, tilemap_xform * xform);
}
Transform2D xform(0, tile_set->map_to_local(kv.key));
rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
rs->canvas_light_occluder_set_transform(occluder, tilemap_xform * xform);
}
}
}
@ -557,8 +559,10 @@ void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) {
RenderingServer *rs = RenderingServer::get_singleton();
// Free the occluders.
for (const RID &rid : r_cell_data.occluders) {
rs->free(rid);
for (const LocalVector<RID> &polygons : r_cell_data.occluders) {
for (const RID &rid : polygons) {
rs->free(rid);
}
}
r_cell_data.occluders.clear();
}
@ -566,11 +570,12 @@ void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) {
void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) {
RenderingServer *rs = RenderingServer::get_singleton();
// Free unused occluders then resize the occluders array.
// Free unused occluders then resize the occluder array.
for (uint32_t i = tile_set->get_occlusion_layers_count(); i < r_cell_data.occluders.size(); i++) {
RID occluder_id = r_cell_data.occluders[i];
if (occluder_id.is_valid()) {
rs->free(occluder_id);
for (const RID &occluder_id : r_cell_data.occluders[i]) {
if (occluder_id.is_valid()) {
rs->free(occluder_id);
}
}
}
r_cell_data.occluders.resize(tile_set->get_occlusion_layers_count());
@ -598,30 +603,42 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) {
// Create, update or clear occluders.
bool needs_set_not_interpolated = is_inside_tree() && get_tree()->is_physics_interpolation_enabled() && !is_physics_interpolated();
for (uint32_t occlusion_layer_index = 0; occlusion_layer_index < r_cell_data.occluders.size(); occlusion_layer_index++) {
Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer_index);
LocalVector<RID> &occluders = r_cell_data.occluders[occlusion_layer_index];
RID &occluder = r_cell_data.occluders[occlusion_layer_index];
if (occluder_polygon.is_valid()) {
// Create or update occluder.
Transform2D xform;
xform.set_origin(tile_set->map_to_local(r_cell_data.coords));
if (!occluder.is_valid()) {
occluder = rs->canvas_light_occluder_create();
if (needs_set_not_interpolated) {
rs->canvas_light_occluder_set_interpolated(occluder, false);
}
// Free unused occluders then resize the occluders array.
for (uint32_t i = tile_data->get_occluder_polygons_count(occlusion_layer_index); i < r_cell_data.occluders[occlusion_layer_index].size(); i++) {
RID occluder_id = occluders[i];
if (occluder_id.is_valid()) {
rs->free(occluder_id);
}
rs->canvas_light_occluder_set_transform(occluder, get_global_transform() * xform);
rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder(occlusion_layer_index, flip_h, flip_v, transpose)->get_rid());
rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index));
rs->canvas_light_occluder_set_as_sdf_collision(occluder, tile_set->get_occlusion_layer_sdf_collision(occlusion_layer_index));
} else {
// Clear occluder.
if (occluder.is_valid()) {
rs->free(occluder);
occluder = RID();
}
occluders.resize(tile_data->get_occluder_polygons_count(occlusion_layer_index));
for (uint32_t occlusion_polygon_index = 0; occlusion_polygon_index < occluders.size(); occlusion_polygon_index++) {
RID &occluder = occluders[occlusion_polygon_index];
Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder_polygon(occlusion_layer_index, occlusion_polygon_index);
if (occluder_polygon.is_valid()) {
// Create or update occluder.
Transform2D xform;
xform.set_origin(tile_set->map_to_local(r_cell_data.coords));
if (!occluder.is_valid()) {
occluder = rs->canvas_light_occluder_create();
if (needs_set_not_interpolated) {
rs->canvas_light_occluder_set_interpolated(occluder, false);
}
}
rs->canvas_light_occluder_set_transform(occluder, get_global_transform() * xform);
rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder_polygon(occlusion_layer_index, occlusion_polygon_index, flip_h, flip_v, transpose)->get_rid());
rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index));
rs->canvas_light_occluder_set_as_sdf_collision(occluder, tile_set->get_occlusion_layer_sdf_collision(occlusion_layer_index));
} else {
// Clear occluder.
if (occluder.is_valid()) {
rs->free(occluder);
occluder = RID();
}
}
}
}
@ -1709,11 +1726,13 @@ void TileMapLayer::_physics_interpolated_changed() {
}
for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) {
for (const RID &occluder : E.value.occluders) {
if (occluder.is_valid()) {
rs->canvas_light_occluder_set_interpolated(occluder, interpolated);
if (needs_reset) {
rs->canvas_light_occluder_reset_physics_interpolation(occluder);
for (const LocalVector<RID> &polygons : E.value.occluders) {
for (const RID &occluder_id : polygons) {
if (occluder_id.is_valid()) {
rs->canvas_light_occluder_set_interpolated(occluder_id, interpolated);
if (needs_reset) {
rs->canvas_light_occluder_reset_physics_interpolation(occluder_id);
}
}
}
}

View File

@ -108,7 +108,7 @@ struct CellData {
// Rendering.
Ref<RenderingQuadrant> rendering_quadrant;
SelfList<CellData> rendering_quadrant_list_element;
LocalVector<RID> occluders;
LocalVector<LocalVector<RID>> occluders;
// Physics.
LocalVector<RID> bodies;

View File

@ -37,7 +37,7 @@ Ref<NavigationPolygon> TileData::_get_navigation_polygon_bind_compat_84660(int p
}
Ref<OccluderPolygon2D> TileData::_get_occluder_bind_compat_84660(int p_layer_id) const {
return get_occluder(p_layer_id, false, false, false);
return get_occluder_polygon(p_layer_id, 0, false, false, false);
}
void TileData::_bind_compatibility_methods() {

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);

View File

@ -841,8 +841,11 @@ private:
int z_index = 0;
int y_sort_origin = 0;
struct OcclusionLayerTileData {
Ref<OccluderPolygon2D> occluder;
mutable HashMap<int, Ref<OccluderPolygon2D>> transformed_occluders;
struct PolygonOccluderTileData {
Ref<OccluderPolygon2D> occluder_polygon;
mutable HashMap<int, Ref<OccluderPolygon2D>> transformed_polygon_occluders;
};
Vector<PolygonOccluderTileData> polygons;
};
Vector<OcclusionLayerTileData> occluders;
@ -941,8 +944,17 @@ public:
void set_y_sort_origin(int p_y_sort_origin);
int get_y_sort_origin() const;
#ifndef DISABLE_DEPRECATED
void set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon);
Ref<OccluderPolygon2D> get_occluder(int p_layer_id, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false) const;
#endif // DISABLE_DEPRECATED
void set_occluder_polygons_count(int p_layer_id, int p_polygons_count);
int get_occluder_polygons_count(int p_layer_id) const;
void add_occluder_polygon(int p_layer_id);
void remove_occluder_polygon(int p_layer_id, int p_polygon_index);
void set_occluder_polygon(int p_layer_id, int p_polygon_index, const Ref<OccluderPolygon2D> &p_occluder_polygon);
Ref<OccluderPolygon2D> get_occluder_polygon(int p_layer_id, int p_polygon_index, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false) const;
// Physics
void set_constant_linear_velocity(int p_layer_id, const Vector2 &p_velocity);