Merge pull request #93029 from groud/multiple_occlusion_polygons
Implement multiple occlusion polygons within each TileSet occlusion layer
This commit is contained in:
commit
ec7fc97972
8 changed files with 345 additions and 114 deletions
|
@ -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" />
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue