Browse Source

Merge pull request #76775 from lawnjelly/multirect_refine_bug

Multirect - Fix refining regions in derived Textures
Rémi Verschelde 2 years ago
parent
commit
6fc3fb5d62
3 changed files with 48 additions and 26 deletions
  1. 21 8
      scene/2d/tile_map.cpp
  2. 15 16
      scene/resources/texture.cpp
  3. 12 2
      scene/resources/texture.h

+ 21 - 8
scene/2d/tile_map.cpp

@@ -565,17 +565,30 @@ void TileMap::update_dirty_quadrants() {
 
 			Ref<Texture> normal_map = tile_set->tile_get_normal_map(c.id);
 			Color modulate = tile_set->tile_get_modulate(c.id) * get_self_modulate();
+
 			if (r == Rect2()) {
 				tex->draw_rect(canvas_item, rect, false, modulate, c.transpose, normal_map);
 			} else {
-				Rect2 dst_rect;
-				Rect2 src_rect;
-				if (tex->get_combined_rect_region(rect, r, dst_rect, src_rect)) {
-					if (!multirect_started) {
-						multirect_started = true;
-						VisualServerCanvasHelper::tilemap_begin();
-					}
-					VisualServerCanvasHelper::tilemap_add_rect(canvas_item, dst_rect, tex->get_rid(), src_rect, modulate, c.transpose, normal_map.is_valid() ? normal_map->get_rid() : RID(), clip_uv);
+				Texture::RefineRectResult res = tex->refine_rect_region(rect, r);
+				switch (res) {
+					case Texture::REFINE_RECT_RESULT_DRAW: {
+						if (!multirect_started) {
+							multirect_started = true;
+							VisualServerCanvasHelper::tilemap_begin();
+						}
+						VisualServerCanvasHelper::tilemap_add_rect(canvas_item, rect, tex->get_rid(), r, modulate, c.transpose, normal_map.is_valid() ? normal_map->get_rid() : RID(), clip_uv);
+					} break;
+					case Texture::REFINE_RECT_RESULT_FALLBACK: {
+						if (multirect_started) {
+							// If we are currently writing a multirect, we must flush
+							// to ensure there are no issues due to overlap.
+							VisualServerCanvasHelper::tilemap_end();
+							multirect_started = false;
+						}
+						tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, normal_map, clip_uv);
+					} break;
+					default: {
+					} break;
 				}
 			}
 

+ 15 - 16
scene/resources/texture.cpp

@@ -66,10 +66,6 @@ bool Texture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect
 	return true;
 }
 
-bool Texture::get_combined_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_combined_rect, Rect2 &r_combined_src_rect) const {
-	return get_rect_region(p_rect, p_src_rect, r_combined_rect, r_combined_src_rect);
-}
-
 void Texture::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_width"), &Texture::get_width);
 	ClassDB::bind_method(D_METHOD("get_height"), &Texture::get_height);
@@ -1032,6 +1028,21 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
 
 	atlas->draw_rect_region(p_canvas_item, dr, rc, p_modulate, p_transpose, p_normal_map);
 }
+
+Texture::RefineRectResult AtlasTexture::refine_rect_region(Rect2 &r_dst_rect, Rect2 &r_src_rect) const {
+	if (!atlas.is_valid()) {
+		return REFINE_RECT_RESULT_NO_DRAW;
+	}
+	Rect2 temp_rect = r_dst_rect;
+	Rect2 temp_src_rect = r_src_rect;
+
+	if (get_rect_region(temp_rect, temp_src_rect, r_dst_rect, r_src_rect)) {
+		return atlas->refine_rect_region(r_dst_rect, r_src_rect);
+	}
+
+	return REFINE_RECT_RESULT_NO_DRAW;
+}
+
 void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
 	if (!atlas.is_valid()) {
 		return;
@@ -1074,18 +1085,6 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
 	return true;
 }
 
-bool AtlasTexture::get_combined_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_combined_rect, Rect2 &r_combined_src_rect) const {
-	if (!atlas.is_valid()) {
-		return false;
-	}
-	Rect2 dst;
-	Rect2 src;
-	if (get_rect_region(p_rect, p_src_rect, dst, src)) {
-		return atlas->get_combined_rect_region(dst, src, r_combined_rect, r_combined_src_rect);
-	}
-	return false;
-}
-
 bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
 	if (!atlas.is_valid()) {
 		return true;

+ 12 - 2
scene/resources/texture.h

@@ -61,6 +61,12 @@ public:
 		FLAG_MIRRORED_REPEAT = VisualServer::TEXTURE_FLAG_MIRRORED_REPEAT
 	};
 
+	enum RefineRectResult {
+		REFINE_RECT_RESULT_DRAW,
+		REFINE_RECT_RESULT_FALLBACK,
+		REFINE_RECT_RESULT_NO_DRAW,
+	};
+
 	virtual int get_width() const = 0;
 	virtual int get_height() const = 0;
 	virtual Size2 get_size() const;
@@ -77,7 +83,7 @@ public:
 	virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
 	virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const;
-	virtual bool get_combined_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_combined_rect, Rect2 &r_combined_src_rect) const;
+	virtual RefineRectResult refine_rect_region(Rect2 &r_dst_rect, Rect2 &r_src_rect) const { return REFINE_RECT_RESULT_DRAW; }
 
 	virtual Ref<Image> get_data() const { return Ref<Image>(); }
 
@@ -145,6 +151,7 @@ public:
 	virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
+	virtual RefineRectResult refine_rect_region(Rect2 &r_dst_rect, Rect2 &r_src_rect) const { return ((w | h) == 0) ? REFINE_RECT_RESULT_NO_DRAW : REFINE_RECT_RESULT_DRAW; }
 	void set_storage(Storage p_storage);
 	Storage get_storage() const;
 
@@ -216,6 +223,7 @@ public:
 	virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
+	virtual RefineRectResult refine_rect_region(Rect2 &r_dst_rect, Rect2 &r_src_rect) const { return ((w | h) == 0) ? REFINE_RECT_RESULT_NO_DRAW : REFINE_RECT_RESULT_DRAW; }
 
 	virtual bool has_alpha() const;
 	virtual void set_flags(uint32_t p_flags);
@@ -277,7 +285,7 @@ public:
 	virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
 	virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const;
-	virtual bool get_combined_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_combined_rect, Rect2 &r_combined_src_rect) const;
+	virtual RefineRectResult refine_rect_region(Rect2 &r_dst_rect, Rect2 &r_src_rect) const;
 
 	bool is_pixel_opaque(int p_x, int p_y) const;
 
@@ -319,6 +327,7 @@ public:
 	virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
+	virtual RefineRectResult refine_rect_region(Rect2 &r_dst_rect, Rect2 &r_src_rect) const { return REFINE_RECT_RESULT_FALLBACK; }
 
 	bool is_pixel_opaque(int p_x, int p_y) const;
 
@@ -367,6 +376,7 @@ public:
 	virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
 	virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
+	virtual RefineRectResult refine_rect_region(Rect2 &r_dst_rect, Rect2 &r_src_rect) const { return REFINE_RECT_RESULT_FALLBACK; }
 
 	bool is_pixel_opaque(int p_x, int p_y) const;