diff options
Diffstat (limited to 'scene/2d/tile_map_layer.cpp')
-rw-r--r-- | scene/2d/tile_map_layer.cpp | 137 |
1 files changed, 111 insertions, 26 deletions
diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index fd1a638b58..0ac236eaa7 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -30,7 +30,6 @@ #include "tile_map_layer.h" -#include "core/core_string_names.h" #include "core/io/marshalls.h" #include "scene/2d/tile_map.h" #include "scene/gui/control.h" @@ -341,7 +340,7 @@ void TileMapLayer::_rendering_update(bool p_force_cleanup) { } // Drawing the tile in the canvas item. - TileMap::draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, get_self_modulate(), tile_data, random_animation_offset); + draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, get_self_modulate(), tile_data, random_animation_offset); } // Reset physics interpolation for any recreated canvas items. @@ -604,6 +603,7 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { 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()) { @@ -1598,11 +1598,11 @@ RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cel void TileMapLayer::_tile_set_changed() { dirty.flags[DIRTY_FLAGS_TILE_SET] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } void TileMapLayer::_renamed() { - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } void TileMapLayer::_update_notify_local_transform() { @@ -1696,18 +1696,18 @@ void TileMapLayer::_notification(int p_what) { _internal_update(true); } break; - case TileMap::NOTIFICATION_ENTER_CANVAS: { + case NOTIFICATION_ENTER_CANVAS: { dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true; _queue_internal_update(); } break; - case TileMap::NOTIFICATION_EXIT_CANVAS: { + case NOTIFICATION_EXIT_CANVAS: { dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true; // Update immediately on exiting, and force cleanup. _internal_update(true); } break; - case TileMap::NOTIFICATION_VISIBILITY_CHANGED: { + case NOTIFICATION_VISIBILITY_CHANGED: { dirty.flags[DIRTY_FLAGS_LAYER_VISIBILITY] = true; _queue_internal_update(); } break; @@ -1805,7 +1805,7 @@ void TileMapLayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "navigation_enabled"), "set_navigation_enabled", "is_navigation_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_navigation_visibility_mode", "get_navigation_visibility_mode"); - ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed)); + ADD_SIGNAL(MethodInfo(CoreStringName(changed))); ADD_PROPERTY_DEFAULT("tile_map_data_format", TileMapDataFormat::TILE_MAP_DATA_FORMAT_1); @@ -1819,7 +1819,7 @@ void TileMapLayer::_update_self_texture_filter(RS::CanvasItemTextureFilter p_tex CanvasItem::_update_self_texture_filter(p_texture_filter); dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_FILTER] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } void TileMapLayer::_update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat) { @@ -1827,7 +1827,7 @@ void TileMapLayer::_update_self_texture_repeat(RS::CanvasItemTextureRepeat p_tex CanvasItem::_update_self_texture_repeat(p_texture_repeat); dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_REPEAT] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } void TileMapLayer::set_as_tile_map_internal_node(int p_index) { @@ -2162,6 +2162,91 @@ TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords) const { } } +void TileMapLayer::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override, real_t p_normalized_animation_offset) { + ERR_FAIL_COND(p_tile_set.is_null()); + 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) { + // Check for the frame. + if (p_frame >= 0) { + ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords)); + } + + // Get the texture. + Ref<Texture2D> tex = atlas_source->get_runtime_texture(); + if (tex.is_null()) { + 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. + const TileData *tile_data = p_tile_data_override ? p_tile_data_override : atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile); + + // Get the tile modulation. + Color modulate = tile_data->get_modulate() * p_modulation; + + // Compute the offset. + Vector2 tile_offset = tile_data->get_texture_origin(); + + // Get destination rect. + Rect2 dest_rect; + dest_rect.size = atlas_source->get_runtime_tile_texture_region(p_atlas_coords).size; + dest_rect.size.x += FP_ADJUST; + dest_rect.size.y += FP_ADJUST; + + bool transpose = tile_data->get_transpose() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_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() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H)) { + dest_rect.size.x = -dest_rect.size.x; + } + + if (tile_data->get_flip_v() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V)) { + dest_rect.size.y = -dest_rect.size.y; + } + + // Draw the tile. + if (p_frame >= 0) { + Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, p_frame); + tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping()); + } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) { + Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, 0); + tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping()); + } else { + real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords); + real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed; + real_t animation_offset = p_normalized_animation_offset * animation_duration; + // Accumulate durations unaffected by the speed to avoid accumulating floating point division errors. + // Aka do `sum(duration[i]) / speed` instead of `sum(duration[i] / speed)`. + real_t time_unscaled = 0.0; + for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) { + real_t frame_duration_unscaled = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame); + real_t slice_start = time_unscaled / speed; + real_t slice_end = (time_unscaled + frame_duration_unscaled) / speed; + RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, slice_start, slice_end, animation_offset); + + Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, frame); + tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping()); + + time_unscaled += frame_duration_unscaled; + } + RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0); + } + } +} + void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile) { // Set the current cell tile (using integer position). Vector2i pk(p_coords); @@ -2212,7 +2297,7 @@ void TileMapLayer::erase_cell(const Vector2i &p_coords) { } void TileMapLayer::fix_invalid_tiles() { - ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet."); + ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot call fix_invalid_tiles() on a TileMapLayer without a valid TileSet."); RBSet<Vector2i> coords; for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { @@ -2502,7 +2587,7 @@ void TileMapLayer::update_internals() { void TileMapLayer::notify_runtime_tile_data_update() { dirty.flags[TileMapLayer::DIRTY_FLAGS_LAYER_RUNTIME_UPDATE] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } Vector2i TileMapLayer::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) { @@ -2537,7 +2622,7 @@ void TileMapLayer::set_enabled(bool p_enabled) { enabled = p_enabled; dirty.flags[DIRTY_FLAGS_LAYER_ENABLED] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } bool TileMapLayer::is_enabled() const { @@ -2563,7 +2648,7 @@ void TileMapLayer::set_tile_set(const Ref<TileSet> &p_tile_set) { tile_set->connect_changed(callable_mp(this, &TileMapLayer::_tile_set_changed)); } - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); // Trigger updates for TileSet's read-only status. notify_property_list_changed(); @@ -2675,7 +2760,7 @@ void TileMapLayer::set_self_modulate(const Color &p_self_modulate) { CanvasItem::set_self_modulate(p_self_modulate); dirty.flags[DIRTY_FLAGS_LAYER_SELF_MODULATE] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) { @@ -2685,7 +2770,7 @@ void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) { CanvasItem::set_y_sort_enabled(p_y_sort_enabled); dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); _update_notify_local_transform(); } @@ -2697,7 +2782,7 @@ void TileMapLayer::set_y_sort_origin(int p_y_sort_origin) { y_sort_origin = p_y_sort_origin; dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } int TileMapLayer::get_y_sort_origin() const { @@ -2711,7 +2796,7 @@ void TileMapLayer::set_z_index(int p_z_index) { CanvasItem::set_z_index(p_z_index); dirty.flags[DIRTY_FLAGS_LAYER_Z_INDEX] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } void TileMapLayer::set_light_mask(int p_light_mask) { @@ -2721,7 +2806,7 @@ void TileMapLayer::set_light_mask(int p_light_mask) { CanvasItem::set_light_mask(p_light_mask); dirty.flags[DIRTY_FLAGS_LAYER_LIGHT_MASK] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } void TileMapLayer::set_rendering_quadrant_size(int p_size) { @@ -2733,7 +2818,7 @@ void TileMapLayer::set_rendering_quadrant_size(int p_size) { rendering_quadrant_size = p_size; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } int TileMapLayer::get_rendering_quadrant_size() const { @@ -2747,7 +2832,7 @@ void TileMapLayer::set_collision_enabled(bool p_enabled) { collision_enabled = p_enabled; dirty.flags[DIRTY_FLAGS_LAYER_COLLISION_ENABLED] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } bool TileMapLayer::is_collision_enabled() const { @@ -2758,7 +2843,7 @@ void TileMapLayer::set_use_kinematic_bodies(bool p_use_kinematic_bodies) { use_kinematic_bodies = p_use_kinematic_bodies; dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] = p_use_kinematic_bodies; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } bool TileMapLayer::is_using_kinematic_bodies() const { @@ -2772,7 +2857,7 @@ void TileMapLayer::set_collision_visibility_mode(TileMapLayer::DebugVisibilityMo collision_visibility_mode = p_show_collision; dirty.flags[DIRTY_FLAGS_LAYER_COLLISION_VISIBILITY_MODE] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } TileMapLayer::DebugVisibilityMode TileMapLayer::get_collision_visibility_mode() const { @@ -2786,7 +2871,7 @@ void TileMapLayer::set_navigation_enabled(bool p_enabled) { navigation_enabled = p_enabled; dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } bool TileMapLayer::is_navigation_enabled() const { @@ -2800,7 +2885,7 @@ void TileMapLayer::set_navigation_map(RID p_map) { navigation_map_override = p_map; dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_MAP] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } RID TileMapLayer::get_navigation_map() const { @@ -2819,7 +2904,7 @@ void TileMapLayer::set_navigation_visibility_mode(TileMapLayer::DebugVisibilityM navigation_visibility_mode = p_show_navigation; dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_VISIBILITY_MODE] = true; _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); + emit_signal(CoreStringName(changed)); } TileMapLayer::DebugVisibilityMode TileMapLayer::get_navigation_visibility_mode() const { |