diff --git a/core/image.cpp b/core/image.cpp index 827618020a6..579c1c1f6c3 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -2217,6 +2217,69 @@ void Image::blit_rect(const Image &p_src, const Rect2 &p_src_rect, const Point2 } } +void Image::blit_rect_mask(const Image &p_src, const Image &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) { + + int dsize = data.size(); + int srcdsize = p_src.data.size(); + int maskdsize = p_mask.data.size(); + ERR_FAIL_COND(dsize == 0); + ERR_FAIL_COND(srcdsize == 0); + ERR_FAIL_COND(maskdsize == 0); + ERR_FAIL_COND(p_src.width != p_mask.width); + ERR_FAIL_COND(p_src.height != p_mask.height); + + Rect2 rrect = Rect2(0, 0, p_src.width, p_src.height).clip(p_src_rect); + + DVector::Write wp = data.write(); + unsigned char *dst_data_ptr = wp.ptr(); + + DVector::Read rp = p_src.data.read(); + const unsigned char *src_data_ptr = rp.ptr(); + + DVector::Read mp = p_mask.data.read(); + const unsigned char *mask_data_ptr = mp.ptr(); + + if ((format == FORMAT_INDEXED || format == FORMAT_INDEXED_ALPHA) && (p_src.format == FORMAT_INDEXED || p_src.format == FORMAT_INDEXED_ALPHA)) { + + Point2i desti(p_dest.x, p_dest.y); + Point2i srci(rrect.pos.x, rrect.pos.y); + + for (int i = 0; i < rrect.size.y; i++) { + + if (i + desti.y < 0 || i + desti.y >= height) + continue; + for (int j = 0; j < rrect.size.x; j++) { + + if (j + desti.x < 0 || j + desti.x >= width) + continue; + + BColor msk = p_mask._get_pixel(rrect.pos.x + j, rrect.pos.y + i, mask_data_ptr, maskdsize); + if (msk.a != 0) { + dst_data_ptr[width * (desti.y + i) + desti.x + j] = src_data_ptr[p_src.width * (srci.y + i) + srci.x + j]; + } + } + } + + } else { + + for (int i = 0; i < rrect.size.y; i++) { + + if (i + p_dest.y < 0 || i + p_dest.y >= height) + continue; + for (int j = 0; j < rrect.size.x; j++) { + + if (j + p_dest.x < 0 || j + p_dest.x >= width) + continue; + + BColor msk = p_mask._get_pixel(rrect.pos.x + j, rrect.pos.y + i, mask_data_ptr, maskdsize); + if (msk.a != 0) { + _put_pixel(p_dest.x + j, p_dest.y + i, p_src._get_pixel(rrect.pos.x + j, rrect.pos.y + i, src_data_ptr, srcdsize), dst_data_ptr); + } + } + } + } +} + void Image::blend_rect(const Image &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) { int dsize = data.size(); @@ -2234,7 +2297,7 @@ void Image::blend_rect(const Image &p_src, const Rect2 &p_src_rect, const Point2 DVector::Read rp = p_src.data.read(); const unsigned char *src_data_ptr = rp.ptr(); - if (format == FORMAT_INDEXED || format == FORMAT_INDEXED || p_src.format == FORMAT_INDEXED || p_src.format == FORMAT_INDEXED_ALPHA) { + if (format == FORMAT_INDEXED || format == FORMAT_INDEXED_ALPHA || p_src.format == FORMAT_INDEXED || p_src.format == FORMAT_INDEXED_ALPHA) { return; @@ -2287,7 +2350,7 @@ void Image::blend_rect_mask(const Image &p_src, const Image &p_mask, const Rect2 DVector::Read mrp = p_mask.data.read(); const unsigned char *mask_data_ptr = mrp.ptr(); - if (format == FORMAT_INDEXED || format == FORMAT_INDEXED || p_src.format == FORMAT_INDEXED || p_src.format == FORMAT_INDEXED_ALPHA) { + if (format == FORMAT_INDEXED || format == FORMAT_INDEXED_ALPHA || p_src.format == FORMAT_INDEXED || p_src.format == FORMAT_INDEXED_ALPHA) { return; diff --git a/core/image.h b/core/image.h index 484e44a1a63..0ecf0eec08c 100644 --- a/core/image.h +++ b/core/image.h @@ -351,6 +351,7 @@ public: void normalmap_to_xy(); void blit_rect(const Image &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); + void blit_rect_mask(const Image &p_src, const Image &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest); void blend_rect(const Image &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); void blend_rect_mask(const Image &p_src, const Image &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 748a1f1a8d8..cc4da88195e 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -621,6 +621,7 @@ struct _VariantCall { VCALL_PTR3R(Image, resized); VCALL_PTR0R(Image, get_data); VCALL_PTR3(Image, blit_rect); + VCALL_PTR4(Image, blit_rect_mask); VCALL_PTR3(Image, blend_rect); VCALL_PTR4(Image, blend_rect_mask); VCALL_PTR1(Image, fill); @@ -1474,6 +1475,7 @@ void register_variant_methods() { ADDFUNC3(IMAGE, IMAGE, Image, resized, INT, "x", INT, "y", INT, "interpolation", varray(((int)Image::INTERPOLATE_BILINEAR))); ADDFUNC0(IMAGE, RAW_ARRAY, Image, get_data, varray()); ADDFUNC3(IMAGE, NIL, Image, blit_rect, IMAGE, "src", RECT2, "src_rect", VECTOR2, "dest", varray(0)); + ADDFUNC4(IMAGE, NIL, Image, blit_rect_mask, IMAGE, "src", IMAGE, "mask", RECT2, "src_rect", VECTOR2, "dest", varray(0)); ADDFUNC3(IMAGE, NIL, Image, blend_rect, IMAGE, "src", RECT2, "src_rect", VECTOR2, "dest", varray(0)); ADDFUNC4(IMAGE, NIL, Image, blend_rect_mask, IMAGE, "src", IMAGE, "mask", RECT2, "src_rect", VECTOR2, "dest", varray(0)); ADDFUNC1(IMAGE, NIL, Image, fill, COLOR, "color", varray(0)); diff --git a/doc/base/classes.xml b/doc/base/classes.xml index 1cbae37837c..fadc62ed8ab 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -15890,6 +15890,19 @@ Copy a "src_rect" [Rect2] from "src" [Image] to this [Image] on coordinates "dest". + + + + + + + + + + + Blits a "src_rect" [Rect2] from "src" [Image] to this [Image] using a "mask" [Image] on coordinates "dest". Alpha channel is required for "mask", will copy src pixel onto dest if the corresponding mask pixel's alpha value is not 0. "src" [Image] and "mask" [Image] *must* have the same size (width and height) but they can have different formats + + @@ -31944,6 +31957,30 @@ Return a copy of the [Rect2] grown a given amount of units towards all the sides. + + + + + + + + + + + + + + + + + + + + + + + + @@ -32651,7 +32688,7 @@ - + @@ -32726,7 +32763,7 @@ - + @@ -37939,7 +37976,9 @@ - + + +