Browse Source

Merge pull request #83489 from groud/implement_tile_map_normals

Allow normal maps on TileMaps that use texture padding
Rémi Verschelde 1 year ago
parent
commit
65e7ddadd7
3 changed files with 114 additions and 33 deletions
  1. 27 0
      scene/main/canvas_item.cpp
  2. 85 32
      scene/resources/tile_set.cpp
  3. 2 1
      scene/resources/tile_set.h

+ 27 - 0
scene/main/canvas_item.cpp

@@ -1496,6 +1496,9 @@ CanvasItem::~CanvasItem() {
 
 
 void CanvasTexture::set_diffuse_texture(const Ref<Texture2D> &p_diffuse) {
 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");
 	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;
 	diffuse_texture = p_diffuse;
 
 
 	RID tex_rid = diffuse_texture.is_valid() ? diffuse_texture->get_rid() : RID();
 	RID tex_rid = diffuse_texture.is_valid() ? diffuse_texture->get_rid() : RID();
@@ -1508,9 +1511,13 @@ Ref<Texture2D> CanvasTexture::get_diffuse_texture() const {
 
 
 void CanvasTexture::set_normal_texture(const Ref<Texture2D> &p_normal) {
 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");
 	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;
 	normal_texture = p_normal;
 	RID tex_rid = normal_texture.is_valid() ? normal_texture->get_rid() : RID();
 	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);
 	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 {
 Ref<Texture2D> CanvasTexture::get_normal_texture() const {
 	return normal_texture;
 	return normal_texture;
@@ -1518,9 +1525,13 @@ Ref<Texture2D> CanvasTexture::get_normal_texture() const {
 
 
 void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) {
 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");
 	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;
 	specular_texture = p_specular;
 	RID tex_rid = specular_texture.is_valid() ? specular_texture->get_rid() : RID();
 	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);
 	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 {
 Ref<Texture2D> CanvasTexture::get_specular_texture() const {
@@ -1528,8 +1539,12 @@ Ref<Texture2D> CanvasTexture::get_specular_texture() const {
 }
 }
 
 
 void CanvasTexture::set_specular_color(const Color &p_color) {
 void CanvasTexture::set_specular_color(const Color &p_color) {
+	if (specular == p_color) {
+		return;
+	}
 	specular = p_color;
 	specular = p_color;
 	RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
 	RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
+	emit_changed();
 }
 }
 
 
 Color CanvasTexture::get_specular_color() const {
 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) {
 void CanvasTexture::set_specular_shininess(real_t p_shininess) {
+	if (shininess == p_shininess) {
+		return;
+	}
 	shininess = p_shininess;
 	shininess = p_shininess;
 	RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
 	RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
+	emit_changed();
 }
 }
 
 
 real_t CanvasTexture::get_specular_shininess() const {
 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) {
 void CanvasTexture::set_texture_filter(CanvasItem::TextureFilter p_filter) {
+	if (texture_filter == p_filter) {
+		return;
+	}
 	texture_filter = p_filter;
 	texture_filter = p_filter;
 	RS::get_singleton()->canvas_texture_set_texture_filter(canvas_texture, RS::CanvasItemTextureFilter(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 {
 CanvasItem::TextureFilter CanvasTexture::get_texture_filter() const {
 	return texture_filter;
 	return texture_filter;
 }
 }
 
 
 void CanvasTexture::set_texture_repeat(CanvasItem::TextureRepeat p_repeat) {
 void CanvasTexture::set_texture_repeat(CanvasItem::TextureRepeat p_repeat) {
+	if (texture_repeat == p_repeat) {
+		return;
+	}
 	texture_repeat = p_repeat;
 	texture_repeat = p_repeat;
 	RS::get_singleton()->canvas_texture_set_texture_repeat(canvas_texture, RS::CanvasItemTextureRepeat(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 {
 CanvasItem::TextureRepeat CanvasTexture::get_texture_repeat() const {
 	return texture_repeat;
 	return texture_repeat;

+ 85 - 32
scene/resources/tile_set.cpp

@@ -4758,30 +4758,18 @@ void TileSetAtlasSource::_queue_update_padded_texture() {
 	call_deferred(SNAME("_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));
 	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 (KeyValue<Vector2i, TileAlternativesData> kv : tiles) {
 		for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) {
 		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 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);
 			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();
 	emit_changed();
 }
 }
 
 

+ 2 - 1
scene/resources/tile_set.h

@@ -641,9 +641,10 @@ private:
 	void _create_coords_mapping_cache(Vector2i p_atlas_coords);
 	void _create_coords_mapping_cache(Vector2i p_atlas_coords);
 
 
 	bool use_texture_padding = true;
 	bool use_texture_padding = true;
-	Ref<ImageTexture> padded_texture;
+	Ref<CanvasTexture> padded_texture;
 	bool padded_texture_needs_update = false;
 	bool padded_texture_needs_update = false;
 	void _queue_update_padded_texture();
 	void _queue_update_padded_texture();
+	Ref<ImageTexture> _create_padded_image_texture(const Ref<Texture2D> &p_source);
 	void _update_padded_texture();
 	void _update_padded_texture();
 
 
 protected:
 protected: