diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 91c95f0..a654247 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -17,7 +17,8 @@ add_executable(tests button.cpp rand.cpp fixedpoint.cpp - pixelbuffer.cpp) + pixelbuffer.cpp + pixelbuffer_effects.cpp) target_link_libraries(tests PUBLIC diff --git a/Tests/pixelbuffer.cpp b/Tests/pixelbuffer.cpp index c6dc91a..2fb9994 100644 --- a/Tests/pixelbuffer.cpp +++ b/Tests/pixelbuffer.cpp @@ -248,3 +248,17 @@ TEST_CASE("Pixelbuffer cuts off fonts when required.", TEST_WIDGET) REQUIRE(pb.data() == etalon); } + +TEST_CASE("Pixelbuffer::View provides the correct offsets.", TEST_WIDGET) +{ + PixelBuffer pb; + const auto view = pb.view<2, 2>({1, 1}); + + const auto* ptr_pb = &pb.at(2, 2); + const auto* ptr_view = &view.at(1, 1); + + REQUIRE(ptr_pb == ptr_view); + + REQUIRE(decltype(view)::width == 2); + REQUIRE(decltype(view)::height == 2); +} diff --git a/Tests/pixelbuffer_effects.cpp b/Tests/pixelbuffer_effects.cpp new file mode 100644 index 0000000..f86fe21 --- /dev/null +++ b/Tests/pixelbuffer_effects.cpp @@ -0,0 +1,15 @@ +// +// Created by erki on 22.05.21. +// + +#include "utility_fonts_5x7.hpp" +#include "utility_pixelbuffer.hpp" +#include "utility_pixelbuffer_effects.hpp" + +#include + +#define TEST_WIDGET "[utility],[pixelbuffer_effects]" + +using PixelBuffer = Utility::PixelBuffer<10, 15>; +using compare_array = std::array; +using Font = Utility::Font5x7; diff --git a/Utility/Inc/utility_pixelbuffer.hpp b/Utility/Inc/utility_pixelbuffer.hpp index 292679d..b03b523 100644 --- a/Utility/Inc/utility_pixelbuffer.hpp +++ b/Utility/Inc/utility_pixelbuffer.hpp @@ -226,6 +226,63 @@ public: } } + template + struct View + { + constexpr static std::size_t width = VW; + constexpr static std::size_t height = VH; + using parent_type = std::decay_t; + using value = typename parent_type::value; + using coordinates = typename parent_type::coordinates; + + static_assert(width <= parent_type::width, "Parent type width is smaller than view's width."); + static_assert(height <= parent_type::height, "Parent type height is smaller than view's height."); + + coordinates offset; + parent_type& parent; + + View() = delete; + explicit View(const coordinates& offset, parent_type& buffer) + : offset(offset), parent(buffer) + {} + + constexpr value& at(const std::size_t& x, const std::size_t& y) + { + return parent.at(parent.x_(offset) + x, parent.y_(offset) + y); + } + + constexpr const value& at(const std::size_t& x, const std::size_t& y) const + { + return parent.at(parent.x_(offset) + x, parent.y_(offset) + y); + } + + constexpr value& at(const coordinates& c) + { + return parent.at(parent.x_(offset) + parent.x_(c), parent.y_(offset) + parent.y_(c)); + } + + constexpr const value& at(const coordinates& c) const + { + return parent.at(parent.x_(offset) + parent.x_(c), parent.y_(offset) + parent.y_(c)); + } + + template + auto view(const coordinates& offset) + { + return View(offset, parent); + } + }; + + template + friend struct View; + + template + auto view(const coordinates& offset) -> View + { + using rtype = View; + return rtype(offset, *this); + } + private: container data_; diff --git a/Utility/Inc/utility_pixelbuffer_effects.hpp b/Utility/Inc/utility_pixelbuffer_effects.hpp new file mode 100644 index 0000000..55f50cf --- /dev/null +++ b/Utility/Inc/utility_pixelbuffer_effects.hpp @@ -0,0 +1,118 @@ +// +// Created by erki on 16.05.21. +// + +#ifndef SKULLC_UTILITY_PIXELBUFFER_EFFECTS_HPP +#define SKULLC_UTILITY_PIXELBUFFER_EFFECTS_HPP + +#include +#include +#include +#include + +namespace Utility +{ +namespace Effects +{ + +template +struct TextScroll +{ + static constexpr std::size_t width = W; + static constexpr std::size_t height = H; + using parent_type = std::decay_t; + using font = std::decay_t; + + static constexpr std::size_t chars_per_view = width / (font::width + 1); + + parent_type& parent; + std::string_view string; + typename parent_type::value color; + typename parent_type::value background; + + TextScroll() = delete; + TextScroll(parent_type& parent, const typename parent_type::value& color, const typename parent_type::value& background) + : parent(parent), color(color), background(background) + {} + + TextScroll(const TextScroll&) = delete; + TextScroll(TextScroll&&) = delete; + TextScroll& operator=(const TextScroll&) = delete; + TextScroll& operator=(TextScroll&&) = delete; + + void setText(const std::string_view& text) + { + string = text; + current_begin = text.cbegin(); + toBuffer_(current_begin); + } + + void scrollCharacter(const std::size_t& step = 1) + { + if (string.size() <= chars_per_view) + return; + + current_begin++; + if (current_begin == string.cend()) + current_begin = string.cbegin(); + + toBuffer_(current_begin); + } + + auto view() + { + return parent.template view({0, 0}); + } + +private: + std::string_view::const_iterator current_begin; + + void toBuffer_(std::string_view::const_iterator begin) + { + std::uint32_t x = 0; + const std::uint32_t y = 0; + + auto iterate_begin = [&begin, this]() { + begin++; + if (string.size() > chars_per_view && begin == string.cend()) + begin = string.cbegin(); + }; + + auto is_over = [this](const std::size_t& ci, const std::string_view::const_iterator& it) -> bool { + if (string.size() <= chars_per_view) + return it != string.cend(); + else + return ci < chars_per_view; + }; + + for (std::size_t ci = 0; is_over(ci, begin); ci++, iterate_begin()) + { + const auto [c_start, c_stop] = font::getCharacterBytes(*begin); + + for (auto it = c_start; it != c_stop; it++, x++) + { + const std::uint8_t& column_byte = *it; + + if (x >= width) + return; + + for (std::uint32_t i = 0; i < font::height && i + y < height; i++) + { + parent.at(x, y + i) = column_byte & (1 << i) ? color : background; + } + } + + x++; + } + } +}; + +template +class ScreenScroll +{ +}; + +}// namespace Effects +}// namespace Utility + +#endif//SKULLC_UTILITY_PIXELBUFFER_EFFECTS_HPP