Add Image::fill_rect method
This commit is contained in:
parent
7b0458c18f
commit
91595b16e3
4 changed files with 90 additions and 10 deletions
|
@ -2697,16 +2697,15 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
|
|||
}
|
||||
}
|
||||
|
||||
void Image::fill(const Color &c) {
|
||||
void Image::fill(const Color &p_color) {
|
||||
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats.");
|
||||
|
||||
uint8_t *wp = data.ptrw();
|
||||
uint8_t *dst_data_ptr = wp;
|
||||
uint8_t *dst_data_ptr = data.ptrw();
|
||||
|
||||
int pixel_size = get_format_pixel_size(format);
|
||||
|
||||
// put first pixel with the format-aware API
|
||||
set_pixel(0, 0, c);
|
||||
// Put first pixel with the format-aware API.
|
||||
_set_color_at_ofs(dst_data_ptr, 0, p_color);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
@ -2719,6 +2718,33 @@ void Image::fill(const Color &c) {
|
|||
}
|
||||
}
|
||||
|
||||
void Image::fill_rect(const Rect2 &p_rect, const Color &p_color) {
|
||||
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats.");
|
||||
|
||||
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
|
||||
if (r.has_no_area()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *dst_data_ptr = data.ptrw();
|
||||
|
||||
int pixel_size = get_format_pixel_size(format);
|
||||
|
||||
// Put first pixel with the format-aware API.
|
||||
uint8_t *rect_first_pixel_ptr = &dst_data_ptr[(r.position.y * width + r.position.x) * pixel_size];
|
||||
_set_color_at_ofs(rect_first_pixel_ptr, 0, p_color);
|
||||
|
||||
for (int y = r.position.y; y < r.position.y + r.size.y; y++) {
|
||||
for (int x = r.position.x; x < r.position.x + r.size.x; x++) {
|
||||
uint8_t *dst = &dst_data_ptr[(y * width + x) * pixel_size];
|
||||
|
||||
for (int k = 0; k < pixel_size; k++) {
|
||||
dst[k] = rect_first_pixel_ptr[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageMemLoadFunc Image::_png_mem_loader_func = nullptr;
|
||||
ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
|
||||
ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
|
||||
|
@ -3160,6 +3186,7 @@ void Image::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("blend_rect", "src", "src_rect", "dst"), &Image::blend_rect);
|
||||
ClassDB::bind_method(D_METHOD("blend_rect_mask", "src", "mask", "src_rect", "dst"), &Image::blend_rect_mask);
|
||||
ClassDB::bind_method(D_METHOD("fill", "color"), &Image::fill);
|
||||
ClassDB::bind_method(D_METHOD("fill_rect", "rect", "color"), &Image::fill_rect);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_used_rect"), &Image::get_used_rect);
|
||||
ClassDB::bind_method(D_METHOD("get_rect", "rect"), &Image::get_rect);
|
||||
|
|
|
@ -362,7 +362,8 @@ public:
|
|||
void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest);
|
||||
void blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest);
|
||||
void blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest);
|
||||
void fill(const Color &c);
|
||||
void fill(const Color &p_color);
|
||||
void fill_rect(const Rect2 &p_rect, const Color &p_color);
|
||||
|
||||
Rect2 get_used_rect() const;
|
||||
Ref<Image> get_rect(const Rect2 &p_area) const;
|
||||
|
|
|
@ -154,7 +154,15 @@
|
|||
<return type="void" />
|
||||
<argument index="0" name="color" type="Color" />
|
||||
<description>
|
||||
Fills the image with a given [Color].
|
||||
Fills the image with [code]color[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="fill_rect">
|
||||
<return type="void" />
|
||||
<argument index="0" name="rect" type="Rect2" />
|
||||
<argument index="1" name="color" type="Color" />
|
||||
<description>
|
||||
Fills [code]rect[/code] with [code]color[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="fix_alpha_edges">
|
||||
|
|
|
@ -52,6 +52,13 @@ TEST_CASE("[Image] Instantiation") {
|
|||
"A newly created image should not be compressed.");
|
||||
CHECK(!image->has_mipmaps());
|
||||
|
||||
PackedByteArray image_data = image->get_data();
|
||||
for (int i = 0; i < image_data.size(); i++) {
|
||||
CHECK_MESSAGE(
|
||||
image_data[i] == 0,
|
||||
"An image created without data specified should have its data zeroed out.");
|
||||
}
|
||||
|
||||
Ref<Image> image_copy = memnew(Image());
|
||||
CHECK_MESSAGE(
|
||||
image_copy->is_empty(),
|
||||
|
@ -62,7 +69,7 @@ TEST_CASE("[Image] Instantiation") {
|
|||
image->get_data() == image_copy->get_data(),
|
||||
"Duplicated images should have the same data.");
|
||||
|
||||
PackedByteArray image_data = image->get_data();
|
||||
image_data = image->get_data();
|
||||
Ref<Image> image_from_data = memnew(Image(8, 4, false, Image::FORMAT_RGBA8, image_data));
|
||||
CHECK_MESSAGE(
|
||||
image->get_data() == image_from_data->get_data(),
|
||||
|
@ -214,14 +221,51 @@ TEST_CASE("[Image] Modifying pixels of an image") {
|
|||
|
||||
// Fill image with color
|
||||
image2->fill(Color(0.5, 0.5, 0.5, 0.5));
|
||||
for (int x = 0; x < image2->get_width(); x++) {
|
||||
for (int y = 0; y < image2->get_height(); y++) {
|
||||
for (int y = 0; y < image2->get_height(); y++) {
|
||||
for (int x = 0; x < image2->get_width(); x++) {
|
||||
CHECK_MESSAGE(
|
||||
image2->get_pixel(x, y).r > 0.49,
|
||||
"fill() should colorize all pixels of the image.");
|
||||
}
|
||||
}
|
||||
|
||||
// Fill rect with color
|
||||
{
|
||||
const int img_width = 3;
|
||||
const int img_height = 3;
|
||||
Vector<Rect2> rects;
|
||||
rects.push_back(Rect2());
|
||||
rects.push_back(Rect2(-5, -5, 3, 3));
|
||||
rects.push_back(Rect2(img_width, 0, 12, 12));
|
||||
rects.push_back(Rect2(0, img_height, 12, 12));
|
||||
rects.push_back(Rect2(img_width + 1, img_height + 2, 12, 12));
|
||||
rects.push_back(Rect2(1, 1, 1, 1));
|
||||
rects.push_back(Rect2(0, 1, 2, 3));
|
||||
rects.push_back(Rect2(-5, 0, img_width + 10, 2));
|
||||
rects.push_back(Rect2(0, -5, 2, img_height + 10));
|
||||
rects.push_back(Rect2(-1, -1, img_width + 1, img_height + 1));
|
||||
|
||||
for (const Rect2 &rect : rects) {
|
||||
Ref<Image> img = memnew(Image(img_width, img_height, false, Image::FORMAT_RGBA8));
|
||||
CHECK_NOTHROW_MESSAGE(
|
||||
img->fill_rect(rect, Color(1, 1, 1, 1)),
|
||||
"fill_rect() shouldn't throw for any rect.");
|
||||
for (int y = 0; y < img->get_height(); y++) {
|
||||
for (int x = 0; x < img->get_width(); x++) {
|
||||
if (rect.abs().has_point(Point2(x, y))) {
|
||||
CHECK_MESSAGE(
|
||||
img->get_pixel(x, y).is_equal_approx(Color(1, 1, 1, 1)),
|
||||
"fill_rect() should colorize all image pixels within rect bounds.");
|
||||
} else {
|
||||
CHECK_MESSAGE(
|
||||
!img->get_pixel(x, y).is_equal_approx(Color(1, 1, 1, 1)),
|
||||
"fill_rect() shouldn't colorize any image pixel out of rect bounds.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Blend two images together
|
||||
image->blend_rect(image2, Rect2(Vector2(0, 0), image2->get_size()), Vector2(0, 0));
|
||||
CHECK_MESSAGE(
|
||||
|
|
Loading…
Reference in a new issue