edgestorage_p.h (5624B)
1 // This file is part of Blend2D project <https://blend2d.com> 2 // 3 // See blend2d.h or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #ifndef BLEND2D_RASTER_EDGESTORAGE_P_H_INCLUDED 7 #define BLEND2D_RASTER_EDGESTORAGE_P_H_INCLUDED 8 9 #include "../support/intops_p.h" 10 #include "../support/math_p.h" 11 #include "../support/traits_p.h" 12 13 //! \cond INTERNAL 14 //! \addtogroup blend2d_raster_engine_impl 15 //! \{ 16 17 namespace bl::RasterEngine { 18 19 //! Parametrized point used by edge builder that should represent either 16-bit 20 //! or 32-bit fixed point. 21 template<typename T> 22 struct EdgePoint { 23 T x, y; 24 25 BL_INLINE void reset(T x_, T y_) noexcept { 26 this->x = x_; 27 this->y = y_; 28 } 29 }; 30 31 static BL_INLINE size_t pack_count_and_sign_bit(size_t count, uint32_t sign_bit) noexcept { 32 BL_ASSERT(count <= (~size_t(0) >> 1)); 33 BL_ASSERT(sign_bit <= 0x1u); 34 35 return (count << 1u) | sign_bit; 36 } 37 38 template<typename CoordT> 39 struct alignas(8) EdgeVector { 40 EdgeVector<CoordT>* next; 41 size_t count_and_sign; 42 EdgePoint<CoordT> pts[1]; 43 44 BL_INLINE size_t count() const noexcept { return count_and_sign >> 1u; } 45 BL_INLINE uint32_t sign_bit() const noexcept { return uint32_t(count_and_sign & 0x1u); } 46 47 static constexpr uint32_t min_size_of() noexcept { 48 return uint32_t(sizeof(EdgeVector<CoordT>) + sizeof(EdgePoint<CoordT>)); 49 } 50 }; 51 52 template<typename CoordT> 53 struct EdgeList { 54 EdgeVector<CoordT>* _first; 55 EdgeVector<CoordT>* _last; 56 57 BL_INLINE void reset() noexcept { 58 _first = nullptr; 59 _last = nullptr; 60 } 61 62 BL_INLINE bool is_empty() const noexcept { return _last == nullptr; } 63 64 BL_INLINE EdgeVector<CoordT>* first() const noexcept { return _first; } 65 BL_INLINE EdgeVector<CoordT>* last() const noexcept { return _last; } 66 67 BL_INLINE void append(EdgeVector<CoordT>* item) noexcept { 68 item->next = nullptr; 69 if (is_empty()) { 70 _first = item; 71 _last = item; 72 } 73 else { 74 _last->next = item; 75 _last = item; 76 } 77 } 78 }; 79 80 template<typename CoordT> 81 class EdgeStorage { 82 public: 83 //! Start edge vectors of each band. 84 EdgeList<CoordT>* _band_edges; 85 //! Length of `_band_edges` array. 86 uint32_t _band_count; 87 //! Capacity of `_band_edges` array. 88 uint32_t _band_capacity; 89 //! Height of a single band (in pixels). 90 uint32_t _band_height; 91 //! Shift to get a band_id from a fixed-point y coordinate. 92 uint32_t _fixed_band_height_shift; 93 //! Bounding box in fixed-point. 94 BLBoxI _bounding_box; 95 96 BL_INLINE EdgeStorage() noexcept { reset(); } 97 BL_INLINE EdgeStorage(const EdgeStorage& other) noexcept = default; 98 99 BL_INLINE void reset() noexcept { 100 _band_edges = nullptr; 101 _band_count = 0; 102 _band_capacity = 0; 103 _band_height = 0; 104 _fixed_band_height_shift = 0; 105 reset_bounding_box(); 106 } 107 108 BL_INLINE void clear() noexcept { 109 if (!is_empty()) { 110 size_t band_start = bandStartFromBBox(); 111 size_t band_end = bandEndFromBBox(); 112 113 for (size_t i = band_start; i < band_end; i++) 114 _band_edges[i].reset(); 115 116 reset_bounding_box(); 117 } 118 } 119 120 BL_INLINE bool is_empty() const noexcept { return _bounding_box.y0 == Traits::max_value<int>(); } 121 122 BL_INLINE EdgeList<CoordT>* band_edges() const noexcept { return _band_edges; } 123 BL_INLINE uint32_t band_count() const noexcept { return _band_count; } 124 BL_INLINE uint32_t band_capacity() const noexcept { return _band_capacity; } 125 BL_INLINE uint32_t band_height() const noexcept { return _band_height; } 126 BL_INLINE uint32_t fixed_band_height_shift() const noexcept { return _fixed_band_height_shift; } 127 BL_INLINE const BLBoxI& bounding_box() const noexcept { return _bounding_box; } 128 129 BL_INLINE void init_data(EdgeList<CoordT>* band_edges, uint32_t band_count, uint32_t band_capacity, uint32_t band_height) noexcept { 130 _band_edges = band_edges; 131 _band_count = band_count; 132 _band_capacity = band_capacity; 133 _band_height = band_height; 134 _fixed_band_height_shift = IntOps::ctz(band_height) + Pipeline::A8Info::kShift; 135 } 136 137 BL_INLINE void reset_bounding_box() noexcept { 138 _bounding_box.reset(Traits::max_value<int>(), Traits::max_value<int>(), Traits::min_value<int>(), Traits::min_value<int>()); 139 } 140 141 BL_INLINE uint32_t bandStartFromBBox() const noexcept { 142 return unsigned(bounding_box().y0) >> fixed_band_height_shift(); 143 } 144 145 BL_INLINE uint32_t bandEndFromBBox() const noexcept { 146 // NOTE: Calculating `band_end` is tricky, because in some rare cases 147 // the bounding box can end exactly at some band's initial coordinate. 148 // In such case we don't know whether the band has data there or not, 149 // so we must consider it initially. 150 return bl_min((unsigned(bounding_box().y1) >> fixed_band_height_shift()) + 1, band_count()); 151 } 152 153 BL_INLINE EdgeVector<CoordT>* flatten_edge_links() noexcept { 154 EdgeList<int>* band_edges = this->band_edges(); 155 156 size_t band_id = bandStartFromBBox(); 157 size_t band_end = bandEndFromBBox(); 158 159 EdgeVector<CoordT>* first = band_edges[band_id].first(); 160 EdgeVector<CoordT>* current = band_edges[band_id].last(); 161 162 // The first band must always be non-null as it starts the edges. 163 BL_ASSERT(first != nullptr); 164 BL_ASSERT(current != nullptr); 165 166 band_edges[band_id].reset(); 167 while (++band_id < band_end) { 168 EdgeVector<int>* band_first = band_edges[band_id].first(); 169 if (!band_first) 170 continue; 171 current->next = band_first; 172 current = band_edges[band_id].last(); 173 band_edges[band_id].reset(); 174 } 175 176 return first; 177 } 178 }; 179 180 } // {bl::RasterEngine} 181 182 //! \} 183 //! \endcond 184 185 #endif // BLEND2D_RASTER_EDGESTORAGE_P_H_INCLUDED 186