odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

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