From 73f72409f510ae22370e6d5c3edcff058f1f00a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gilles=20Roudi=C3=A8re?= Date: Tue, 17 Oct 2023 12:11:01 +0200 Subject: [PATCH] Allow normal maps on TileMaps that use texture padding --- scene/main/canvas_item.cpp | 27 ++++++++ scene/resources/tile_set.cpp | 117 +++++++++++++++++++++++++---------- scene/resources/tile_set.h | 3 +- 3 files changed, 114 insertions(+), 33 deletions(-) diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 8f38a6f6c8ed..a350b97bc8e5 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -1496,6 +1496,9 @@ CanvasItem::~CanvasItem() { void CanvasTexture::set_diffuse_texture(const Ref &p_diffuse) { ERR_FAIL_COND_MSG(Object::cast_to(p_diffuse.ptr()) != nullptr, "Can't self-assign a CanvasTexture"); + if (diffuse_texture == p_diffuse) { + return; + } diffuse_texture = p_diffuse; RID tex_rid = diffuse_texture.is_valid() ? diffuse_texture->get_rid() : RID(); @@ -1508,9 +1511,13 @@ Ref CanvasTexture::get_diffuse_texture() const { void CanvasTexture::set_normal_texture(const Ref &p_normal) { ERR_FAIL_COND_MSG(Object::cast_to(p_normal.ptr()) != nullptr, "Can't self-assign a CanvasTexture"); + if (normal_texture == p_normal) { + return; + } normal_texture = p_normal; RID tex_rid = normal_texture.is_valid() ? normal_texture->get_rid() : RID(); RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_NORMAL, tex_rid); + emit_changed(); } Ref CanvasTexture::get_normal_texture() const { return normal_texture; @@ -1518,9 +1525,13 @@ Ref CanvasTexture::get_normal_texture() const { void CanvasTexture::set_specular_texture(const Ref &p_specular) { ERR_FAIL_COND_MSG(Object::cast_to(p_specular.ptr()) != nullptr, "Can't self-assign a CanvasTexture"); + if (specular_texture == p_specular) { + return; + } specular_texture = p_specular; RID tex_rid = specular_texture.is_valid() ? specular_texture->get_rid() : RID(); RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_SPECULAR, tex_rid); + emit_changed(); } Ref CanvasTexture::get_specular_texture() const { @@ -1528,8 +1539,12 @@ Ref CanvasTexture::get_specular_texture() const { } void CanvasTexture::set_specular_color(const Color &p_color) { + if (specular == p_color) { + return; + } specular = p_color; RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess); + emit_changed(); } Color CanvasTexture::get_specular_color() const { @@ -1537,8 +1552,12 @@ Color CanvasTexture::get_specular_color() const { } void CanvasTexture::set_specular_shininess(real_t p_shininess) { + if (shininess == p_shininess) { + return; + } shininess = p_shininess; RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess); + emit_changed(); } real_t CanvasTexture::get_specular_shininess() const { @@ -1546,16 +1565,24 @@ real_t CanvasTexture::get_specular_shininess() const { } void CanvasTexture::set_texture_filter(CanvasItem::TextureFilter p_filter) { + if (texture_filter == p_filter) { + return; + } texture_filter = p_filter; RS::get_singleton()->canvas_texture_set_texture_filter(canvas_texture, RS::CanvasItemTextureFilter(p_filter)); + emit_changed(); } CanvasItem::TextureFilter CanvasTexture::get_texture_filter() const { return texture_filter; } void CanvasTexture::set_texture_repeat(CanvasItem::TextureRepeat p_repeat) { + if (texture_repeat == p_repeat) { + return; + } texture_repeat = p_repeat; RS::get_singleton()->canvas_texture_set_texture_repeat(canvas_texture, RS::CanvasItemTextureRepeat(p_repeat)); + emit_changed(); } CanvasItem::TextureRepeat CanvasTexture::get_texture_repeat() const { return texture_repeat; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index dce0d87d1009..121d29b728d5 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -4758,30 +4758,18 @@ void TileSetAtlasSource::_queue_update_padded_texture() { call_deferred(SNAME("_update_padded_texture")); } -void TileSetAtlasSource::_update_padded_texture() { - if (!padded_texture_needs_update) { - return; - } - padded_texture_needs_update = false; - padded_texture = Ref(); +Ref TileSetAtlasSource::_create_padded_image_texture(const Ref &p_source) { + ERR_FAIL_COND_V(p_source.is_null(), Ref()); - if (!texture.is_valid()) { - return; - } - - if (!use_texture_padding) { - return; + Ref src_image = p_source->get_image(); + if (src_image.is_null()) { + Ref ret; + ret.instantiate(); + return ret; } Size2 size = get_atlas_grid_size() * (texture_region_size + Vector2i(2, 2)); - - Ref src = texture->get_image(); - - if (!src.is_valid()) { - return; - } - - Ref image = Image::create_empty(size.x, size.y, false, src->get_format()); + Ref image = Image::create_empty(size.x, size.y, false, src_image->get_format()); for (KeyValue kv : tiles) { for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) { @@ -4797,24 +4785,89 @@ void TileSetAtlasSource::_update_padded_texture() { Vector2i frame_coords = kv.key + (kv.value.size_in_atlas + kv.value.animation_separation) * ((kv.value.animation_columns > 0) ? Vector2i(frame % kv.value.animation_columns, frame / kv.value.animation_columns) : Vector2i(frame, 0)); Vector2i base_pos = frame_coords * (texture_region_size + Vector2i(2, 2)) + Vector2i(1, 1); - image->blit_rect(*src, src_rect, base_pos); + image->blit_rect(*src_image, src_rect, base_pos); - image->blit_rect(*src, top_src_rect, base_pos + Vector2i(0, -1)); - image->blit_rect(*src, bottom_src_rect, base_pos + Vector2i(0, src_rect.size.y)); - image->blit_rect(*src, left_src_rect, base_pos + Vector2i(-1, 0)); - image->blit_rect(*src, right_src_rect, base_pos + Vector2i(src_rect.size.x, 0)); + image->blit_rect(*src_image, top_src_rect, base_pos + Vector2i(0, -1)); + image->blit_rect(*src_image, bottom_src_rect, base_pos + Vector2i(0, src_rect.size.y)); + image->blit_rect(*src_image, left_src_rect, base_pos + Vector2i(-1, 0)); + image->blit_rect(*src_image, right_src_rect, base_pos + Vector2i(src_rect.size.x, 0)); - image->set_pixelv(base_pos + Vector2i(-1, -1), src->get_pixelv(src_rect.position)); - image->set_pixelv(base_pos + Vector2i(src_rect.size.x, -1), src->get_pixelv(src_rect.position + Vector2i(src_rect.size.x - 1, 0))); - image->set_pixelv(base_pos + Vector2i(-1, src_rect.size.y), src->get_pixelv(src_rect.position + Vector2i(0, src_rect.size.y - 1))); - image->set_pixelv(base_pos + Vector2i(src_rect.size.x, src_rect.size.y), src->get_pixelv(src_rect.position + Vector2i(src_rect.size.x - 1, src_rect.size.y - 1))); + image->set_pixelv(base_pos + Vector2i(-1, -1), src_image->get_pixelv(src_rect.position)); + image->set_pixelv(base_pos + Vector2i(src_rect.size.x, -1), src_image->get_pixelv(src_rect.position + Vector2i(src_rect.size.x - 1, 0))); + image->set_pixelv(base_pos + Vector2i(-1, src_rect.size.y), src_image->get_pixelv(src_rect.position + Vector2i(0, src_rect.size.y - 1))); + image->set_pixelv(base_pos + Vector2i(src_rect.size.x, src_rect.size.y), src_image->get_pixelv(src_rect.position + Vector2i(src_rect.size.x - 1, src_rect.size.y - 1))); } } - if (!padded_texture.is_valid()) { - padded_texture.instantiate(); + return ImageTexture::create_from_image(image); +} + +void TileSetAtlasSource::_update_padded_texture() { + if (!padded_texture_needs_update) { + return; + } + padded_texture_needs_update = false; + + if (padded_texture.is_valid()) { + padded_texture->disconnect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture)); + } + + padded_texture = Ref(); + + if (texture.is_null()) { + return; + } + + if (!use_texture_padding) { + return; + } + + padded_texture.instantiate(); + + Ref src_canvas_texture = texture; + if (src_canvas_texture.is_valid()) { + // Use all textures. + // Diffuse + Ref src = src_canvas_texture->get_diffuse_texture(); + Ref image_texture; + if (src.is_valid()) { + image_texture = _create_padded_image_texture(src); + } else { + image_texture.instantiate(); + } + padded_texture->set_diffuse_texture(image_texture); + + // Normal + src = src_canvas_texture->get_normal_texture(); + image_texture.instantiate(); + if (src.is_valid()) { + image_texture = _create_padded_image_texture(src); + } else { + image_texture.instantiate(); + } + padded_texture->set_normal_texture(image_texture); + + // Specular + src = src_canvas_texture->get_specular_texture(); + image_texture.instantiate(); + if (src.is_valid()) { + image_texture = _create_padded_image_texture(src); + } else { + image_texture.instantiate(); + } + padded_texture->set_specular_texture(image_texture); + + // Other properties. + padded_texture->set_specular_color(src_canvas_texture->get_specular_color()); + padded_texture->set_specular_shininess(src_canvas_texture->get_specular_shininess()); + padded_texture->set_texture_filter(src_canvas_texture->get_texture_filter()); + padded_texture->set_texture_repeat(src_canvas_texture->get_texture_repeat()); + } else { + // Use only diffuse. + Ref image_texture = _create_padded_image_texture(texture); + padded_texture->set_diffuse_texture(image_texture); } - padded_texture->set_image(image); + padded_texture->connect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture)); emit_changed(); } diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 722d615b093c..313c4df65de3 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -641,9 +641,10 @@ class TileSetAtlasSource : public TileSetSource { void _create_coords_mapping_cache(Vector2i p_atlas_coords); bool use_texture_padding = true; - Ref padded_texture; + Ref padded_texture; bool padded_texture_needs_update = false; void _queue_update_padded_texture(); + Ref _create_padded_image_texture(const Ref &p_source); void _update_padded_texture(); protected: