Skip to content

Commit

Permalink
Merge pull request #83489 from groud/implement_tile_map_normals
Browse files Browse the repository at this point in the history
Allow normal maps on TileMaps that use texture padding
  • Loading branch information
akien-mga committed Oct 18, 2023
2 parents 5fd3354 + 73f7240 commit 65e7dda
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 33 deletions.
27 changes: 27 additions & 0 deletions scene/main/canvas_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,9 @@ CanvasItem::~CanvasItem() {

void CanvasTexture::set_diffuse_texture(const Ref<Texture2D> &p_diffuse) {
ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(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();
Expand All @@ -1508,54 +1511,78 @@ Ref<Texture2D> CanvasTexture::get_diffuse_texture() const {

void CanvasTexture::set_normal_texture(const Ref<Texture2D> &p_normal) {
ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(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<Texture2D> CanvasTexture::get_normal_texture() const {
return normal_texture;
}

void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) {
ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(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<Texture2D> CanvasTexture::get_specular_texture() const {
return specular_texture;
}

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 {
return specular;
}

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 {
return shininess;
}

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;
Expand Down
117 changes: 85 additions & 32 deletions scene/resources/tile_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<ImageTexture>();
Ref<ImageTexture> TileSetAtlasSource::_create_padded_image_texture(const Ref<Texture2D> &p_source) {
ERR_FAIL_COND_V(p_source.is_null(), Ref<ImageTexture>());

if (!texture.is_valid()) {
return;
}

if (!use_texture_padding) {
return;
Ref<Image> src_image = p_source->get_image();
if (src_image.is_null()) {
Ref<ImageTexture> ret;
ret.instantiate();
return ret;
}

Size2 size = get_atlas_grid_size() * (texture_region_size + Vector2i(2, 2));

Ref<Image> src = texture->get_image();

if (!src.is_valid()) {
return;
}

Ref<Image> image = Image::create_empty(size.x, size.y, false, src->get_format());
Ref<Image> image = Image::create_empty(size.x, size.y, false, src_image->get_format());

for (KeyValue<Vector2i, TileAlternativesData> kv : tiles) {
for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) {
Expand All @@ -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<CanvasTexture>();

if (texture.is_null()) {
return;
}

if (!use_texture_padding) {
return;
}

padded_texture.instantiate();

Ref<CanvasTexture> src_canvas_texture = texture;
if (src_canvas_texture.is_valid()) {
// Use all textures.
// Diffuse
Ref<Texture2D> src = src_canvas_texture->get_diffuse_texture();
Ref<ImageTexture> 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<ImageTexture> 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();
}

Expand Down
3 changes: 2 additions & 1 deletion scene/resources/tile_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,9 +641,10 @@ class TileSetAtlasSource : public TileSetSource {
void _create_coords_mapping_cache(Vector2i p_atlas_coords);

bool use_texture_padding = true;
Ref<ImageTexture> padded_texture;
Ref<CanvasTexture> padded_texture;
bool padded_texture_needs_update = false;
void _queue_update_padded_texture();
Ref<ImageTexture> _create_padded_image_texture(const Ref<Texture2D> &p_source);
void _update_padded_texture();

protected:
Expand Down

0 comments on commit 65e7dda

Please sign in to comment.