From 57e23f239f0734ec825975dc1db628b2b9dd0dbe Mon Sep 17 00:00:00 2001 From: Ivan Gagis Date: Thu, 7 Nov 2024 13:30:52 +0200 Subject: [PATCH] implement image_span::blit() --- src/rasterimage/image_span.hpp | 45 +++++++++++++++++++- tests/unit/src/image_span.cpp | 78 ++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/src/rasterimage/image_span.hpp b/src/rasterimage/image_span.hpp index e5070cd..1d2d150 100644 --- a/src/rasterimage/image_span.hpp +++ b/src/rasterimage/image_span.hpp @@ -392,7 +392,50 @@ class image_span : public dimensioned { static_assert(!is_const_span, "image_span is const, cannot blit to it"); - // TODO: + auto this_rect = r4::rectangle( + 0, // + this->dims().to() + ); + + auto span_rect_relative_to_this_rect = r4::rectangle( + position, // + span.dims().template to() + ); + + auto dst_rect = this_rect.intersect(span_rect_relative_to_this_rect); + + if (dst_rect.d.is_any_zero()) { + // image to blit is out of destination span + return; + } + + ASSERT(dst_rect.p.is_positive_or_zero()) + ASSERT(dst_rect.d.is_positive()) + + // rectangle on the source span which will actually be blitted + auto src_rect = r4::rectangle(max(-position, 0), dst_rect.d); + + ASSERT(src_rect.p.is_positive_or_zero()) + ASSERT(src_rect.d.is_positive()) + ASSERT(r4::rectangle(0, span.dims().template to()).contains(src_rect)) + + auto dst_span = this->subspan(dst_rect.to()); + auto src_span = span.subspan(src_rect.to()); + + ASSERT(!dst_span.empty()) + ASSERT(!src_span.empty()) + ASSERT(src_span.dims() == dst_span.dims()) + + // TODO: use zip_view + auto src_line = src_span.begin(); + auto dst_line = dst_span.begin(); + for (; src_line != src_span.end(); ++src_line, ++dst_line) { + std::copy( + src_line->begin(), // + src_line->end(), + dst_line->begin() + ); + } } void swap_red_blue() noexcept diff --git a/tests/unit/src/image_span.cpp b/tests/unit/src/image_span.cpp index e63fde6..e4cb116 100644 --- a/tests/unit/src/image_span.cpp +++ b/tests/unit/src/image_span.cpp @@ -464,5 +464,83 @@ const tst::set set("image_span", [](tst::suite& suite) { tst::check_eq(span.stride_pixels(), unsigned(0), SL); tst::check_eq(span.stride_bytes(), size_t(0), SL); }); + + suite.add("blit__fully_within", []() { + rasterimage::image dst_img(rasterimage::dimensioned::dimensions_type{20, 10}); + dst_img.span().clear(0); + tst::check_eq(dst_img[0][0], decltype(dst_img)::pixel_type(0), SL); + + rasterimage::image src_img(rasterimage::dimensioned::dimensions_type{3, 2}); + src_img.span().clear(13); + tst::check_eq(src_img[0][0], decltype(src_img)::pixel_type(13), SL); + + dst_img.span().blit(src_img.span(), {2, 1}); + + tst::check_eq(dst_img[0][0], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[0][1], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[0][2], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[0][3], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[0][4], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[0][5], decltype(dst_img)::pixel_type(0), SL); + + tst::check_eq(dst_img[1][0], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[1][1], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[1][2], decltype(dst_img)::pixel_type(13), SL); + tst::check_eq(dst_img[1][3], decltype(dst_img)::pixel_type(13), SL); + tst::check_eq(dst_img[1][4], decltype(dst_img)::pixel_type(13), SL); + tst::check_eq(dst_img[1][5], decltype(dst_img)::pixel_type(0), SL); + + tst::check_eq(dst_img[2][0], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[2][1], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[2][2], decltype(dst_img)::pixel_type(13), SL); + tst::check_eq(dst_img[2][3], decltype(dst_img)::pixel_type(13), SL); + tst::check_eq(dst_img[2][4], decltype(dst_img)::pixel_type(13), SL); + tst::check_eq(dst_img[2][5], decltype(dst_img)::pixel_type(0), SL); + + tst::check_eq(dst_img[3][0], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[3][1], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[3][2], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[3][3], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[3][4], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[3][5], decltype(dst_img)::pixel_type(0), SL); + }); + + suite.add("blit__partly_negative", []() { + rasterimage::image dst_img(rasterimage::dimensioned::dimensions_type{20, 10}); + dst_img.span().clear(0); + tst::check_eq(dst_img[0][0], decltype(dst_img)::pixel_type(0), SL); + + rasterimage::image src_img(rasterimage::dimensioned::dimensions_type{3, 2}); + src_img.span().clear(13); + tst::check_eq(src_img[0][0], decltype(src_img)::pixel_type(13), SL); + + dst_img.span().blit(src_img.span(), {-2, -1}); + + tst::check_eq(dst_img[0][0], decltype(dst_img)::pixel_type(13), SL); + tst::check_eq(dst_img[0][1], decltype(dst_img)::pixel_type(0), SL); + + tst::check_eq(dst_img[1][0], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[1][1], decltype(dst_img)::pixel_type(0), SL); + }); + + suite.add("blit__partly_over", []() { + rasterimage::image dst_img(rasterimage::dimensioned::dimensions_type{20, 10}); + dst_img.span().clear(0); + tst::check_eq(dst_img[0][0], decltype(dst_img)::pixel_type(0), SL); + + rasterimage::image src_img(rasterimage::dimensioned::dimensions_type{3, 2}); + src_img.span().clear(13); + tst::check_eq(src_img[0][0], decltype(src_img)::pixel_type(13), SL); + + dst_img.span().blit(src_img.span(), {18, 9}); + + tst::check_eq(dst_img[8][17], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[8][18], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[8][19], decltype(dst_img)::pixel_type(0), SL); + + tst::check_eq(dst_img[9][17], decltype(dst_img)::pixel_type(0), SL); + tst::check_eq(dst_img[9][18], decltype(dst_img)::pixel_type(13), SL); + tst::check_eq(dst_img[9][19], decltype(dst_img)::pixel_type(13), SL); + }); }); } // namespace