Home | History | Annotate | Download | only in agg23
      1 
      2 //----------------------------------------------------------------------------
      3 // Anti-Grain Geometry - Version 2.3
      4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
      5 //
      6 // Permission to copy, use, modify, sell and distribute this software
      7 // is granted provided this copyright notice appears in all copies.
      8 // This software is provided "as is" without express or implied
      9 // warranty, and with no claim as to its suitability for any purpose.
     10 //
     11 //----------------------------------------------------------------------------
     12 //
     13 // The author gratefully acknowleges the support of David Turner,
     14 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
     15 // libray - in producing this work. See http://www.freetype.org for details.
     16 //
     17 //----------------------------------------------------------------------------
     18 // Contact: mcseem (at) antigrain.com
     19 //          mcseemagg (at) yahoo.com
     20 //          http://www.antigrain.com
     21 //----------------------------------------------------------------------------
     22 //
     23 // Adaptation for 32-bit screen coordinates has been sponsored by
     24 // Liberty Technology Systems, Inc., visit http://lib-sys.com
     25 //
     26 // Liberty Technology Systems, Inc. is the provider of
     27 // PostScript and PDF technology for software developers.
     28 //
     29 //----------------------------------------------------------------------------
     30 #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
     31 #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
     32 
     33 #include "agg_array.h"
     34 #include "agg_basics.h"
     35 #include "agg_clip_liang_barsky.h"
     36 #include "agg_math.h"
     37 #include "agg_render_scanlines.h"
     38 #include "core/fxcrt/fx_coordinates.h"
     39 #include "core/fxcrt/fx_memory.h"
     40 
     41 namespace agg
     42 {
     43 enum poly_base_scale_e {
     44     poly_base_shift = 8,
     45     poly_base_size  = 1 << poly_base_shift,
     46     poly_base_mask  = poly_base_size - 1
     47 };
     48 inline int poly_coord(float c)
     49 {
     50     return int(c * poly_base_size);
     51 }
     52 struct cell_aa  {
     53     int x;
     54     int y;
     55     int cover;
     56     int area;
     57     void set(int x, int y, int c, int a);
     58     void set_coord(int x, int y);
     59     void set_cover(int c, int a);
     60     void add_cover(int c, int a);
     61 };
     62 class outline_aa
     63 {
     64     enum cell_block_scale_e {
     65         cell_block_shift = 12,
     66         cell_block_size  = 1 << cell_block_shift,
     67         cell_block_mask  = cell_block_size - 1,
     68         cell_block_pool  = 256,
     69         cell_block_limit = 1024
     70     };
     71     struct sorted_y  {
     72         unsigned start;
     73         unsigned num;
     74     };
     75 public:
     76     ~outline_aa();
     77     outline_aa();
     78     void reset();
     79     void move_to(int x, int y);
     80     void line_to(int x, int y);
     81     int min_x() const
     82     {
     83         return m_min_x;
     84     }
     85     int min_y() const
     86     {
     87         return m_min_y;
     88     }
     89     int max_x() const
     90     {
     91         return m_max_x;
     92     }
     93     int max_y() const
     94     {
     95         return m_max_y;
     96     }
     97     void sort_cells();
     98     unsigned total_cells() const
     99     {
    100         return m_num_cells;
    101     }
    102     unsigned scanline_num_cells(unsigned y) const
    103     {
    104         return m_sorted_y[y - m_min_y].num;
    105     }
    106     const cell_aa* const* scanline_cells(unsigned y) const
    107     {
    108         return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start;
    109     }
    110     bool sorted() const
    111     {
    112         return m_sorted;
    113     }
    114 private:
    115     outline_aa(const outline_aa&);
    116     const outline_aa& operator = (const outline_aa&);
    117     void set_cur_cell(int x, int y);
    118     void add_cur_cell();
    119     void render_hline(int ey, int x1, int y1, int x2, int y2);
    120     void render_line(int x1, int y1, int x2, int y2);
    121     void allocate_block();
    122 private:
    123     unsigned  m_num_blocks;
    124     unsigned  m_max_blocks;
    125     unsigned  m_cur_block;
    126     unsigned  m_num_cells;
    127     cell_aa** m_cells;
    128     cell_aa*  m_cur_cell_ptr;
    129     pod_array<cell_aa*> m_sorted_cells;
    130     pod_array<sorted_y> m_sorted_y;
    131     cell_aa   m_cur_cell;
    132     int       m_cur_x;
    133     int       m_cur_y;
    134     int       m_min_x;
    135     int       m_min_y;
    136     int       m_max_x;
    137     int       m_max_y;
    138     bool      m_sorted;
    139 };
    140 class scanline_hit_test
    141 {
    142 public:
    143     scanline_hit_test(int x) : m_x(x), m_hit(false) {}
    144     void reset_spans() {}
    145     void finalize(int) {}
    146     void add_cell(int x, int)
    147     {
    148         if(m_x == x) {
    149             m_hit = true;
    150         }
    151     }
    152     void add_span(int x, int len, int)
    153     {
    154         if(m_x >= x && m_x < x + len) {
    155             m_hit = true;
    156         }
    157     }
    158     unsigned num_spans() const
    159     {
    160         return 1;
    161     }
    162     bool hit() const
    163     {
    164         return m_hit;
    165     }
    166 private:
    167     int  m_x;
    168     bool m_hit;
    169 };
    170 enum filling_rule_e {
    171     fill_non_zero,
    172     fill_even_odd
    173 };
    174 class rasterizer_scanline_aa
    175 {
    176     enum status {
    177         status_initial,
    178         status_line_to,
    179         status_closed
    180     };
    181 public:
    182     enum aa_scale_e {
    183         aa_num   = 1 << 8,
    184         aa_mask  = aa_num - 1,
    185         aa_2num  = aa_num * 2,
    186         aa_2mask = aa_2num - 1
    187     };
    188     rasterizer_scanline_aa() :
    189         m_filling_rule(fill_non_zero),
    190         m_clipped_start_x(0),
    191         m_clipped_start_y(0),
    192         m_status(status_initial),
    193         m_clipping(false)
    194     {
    195     }
    196     ~rasterizer_scanline_aa() {}
    197     void filling_rule(filling_rule_e filling_rule)
    198     {
    199         m_filling_rule = filling_rule;
    200     }
    201     int min_x() const
    202     {
    203         return m_outline.min_x();
    204     }
    205     int min_y() const
    206     {
    207         return m_outline.min_y();
    208     }
    209     int max_x() const
    210     {
    211         return m_outline.max_x();
    212     }
    213     int max_y() const
    214     {
    215         return m_outline.max_y();
    216     }
    217     void reset()
    218     {
    219         m_outline.reset();
    220         m_status = status_initial;
    221     }
    222     void clip_box(float x1, float y1, float x2, float y2)
    223     {
    224         m_clip_box = rect(poly_coord(x1), poly_coord(y1),
    225                           poly_coord(x2), poly_coord(y2));
    226         m_clip_box.normalize();
    227         m_clipping = true;
    228     }
    229     void add_vertex(float x, float y, unsigned cmd)
    230     {
    231         if(is_close(cmd)) {
    232             close_polygon();
    233         } else {
    234             if(is_move_to(cmd)) {
    235                 move_to(poly_coord(x), poly_coord(y));
    236             } else {
    237                 if(is_vertex(cmd)) {
    238                     line_to(poly_coord(x), poly_coord(y));
    239                 }
    240             }
    241         }
    242     }
    243     void move_to(int x, int y)
    244     {
    245         if(m_clipping) {
    246             if(m_outline.sorted()) {
    247                 reset();
    248             }
    249             if(m_status == status_line_to) {
    250                 close_polygon();
    251             }
    252             m_prev_x = m_start_x = x;
    253             m_prev_y = m_start_y = y;
    254             m_status = status_initial;
    255             m_prev_flags = clipping_flags(x, y, m_clip_box);
    256             if(m_prev_flags == 0) {
    257                 move_to_no_clip(x, y);
    258             }
    259         } else {
    260             move_to_no_clip(x, y);
    261         }
    262     }
    263     void line_to(int x, int y)
    264     {
    265         if(m_clipping) {
    266             clip_segment(x, y);
    267         } else {
    268             line_to_no_clip(x, y);
    269         }
    270     }
    271     void close_polygon()
    272     {
    273         if (m_status != status_line_to) {
    274             return;
    275         }
    276         if(m_clipping) {
    277             clip_segment(m_start_x, m_start_y);
    278         }
    279         close_polygon_no_clip();
    280     }
    281     AGG_INLINE unsigned calculate_alpha(int area, bool no_smooth) const
    282     {
    283         int cover = area >> (poly_base_shift * 2 + 1 - 8);
    284         if(cover < 0) {
    285             cover = -cover;
    286         }
    287         if(m_filling_rule == fill_even_odd) {
    288             cover &= aa_2mask;
    289             if(cover > aa_num) {
    290                 cover = aa_2num - cover;
    291             }
    292         }
    293         if (no_smooth) {
    294             cover = cover > aa_mask / 2 ? aa_mask : 0;
    295         }
    296         if(cover > aa_mask) {
    297             cover = aa_mask;
    298         }
    299         return cover;
    300     }
    301     AGG_INLINE void sort()
    302     {
    303         m_outline.sort_cells();
    304     }
    305     AGG_INLINE bool rewind_scanlines()
    306     {
    307         close_polygon();
    308         m_outline.sort_cells();
    309         if(m_outline.total_cells() == 0) {
    310             return false;
    311         }
    312         m_cur_y = m_outline.min_y();
    313         return true;
    314     }
    315     AGG_INLINE bool navigate_scanline(int y)
    316     {
    317         close_polygon();
    318         m_outline.sort_cells();
    319         if(m_outline.total_cells() == 0 ||
    320                 y < m_outline.min_y() ||
    321                 y > m_outline.max_y()) {
    322             return false;
    323         }
    324         m_cur_y = y;
    325         return true;
    326     }
    327     template<class Scanline> bool sweep_scanline(Scanline& sl, bool no_smooth)
    328     {
    329         for(;;) {
    330             if(m_cur_y > m_outline.max_y()) {
    331                 return false;
    332             }
    333             sl.reset_spans();
    334             unsigned num_cells = m_outline.scanline_num_cells(m_cur_y);
    335             const cell_aa* const* cells = m_outline.scanline_cells(m_cur_y);
    336             int cover = 0;
    337             while(num_cells) {
    338                 const cell_aa* cur_cell = *cells;
    339                 int x    = cur_cell->x;
    340                 int area = cur_cell->area;
    341                 unsigned alpha;
    342                 cover += cur_cell->cover;
    343                 while(--num_cells) {
    344                     cur_cell = *++cells;
    345                     if(cur_cell->x != x) {
    346                         break;
    347                     }
    348                     area  += cur_cell->area;
    349                     cover += cur_cell->cover;
    350                 }
    351                 if(area) {
    352                     alpha = calculate_alpha((cover << (poly_base_shift + 1)) - area, no_smooth);
    353                     if(alpha) {
    354                         sl.add_cell(x, alpha);
    355                     }
    356                     x++;
    357                 }
    358                 if(num_cells && cur_cell->x > x) {
    359                     alpha = calculate_alpha(cover << (poly_base_shift + 1), no_smooth);
    360                     if(alpha) {
    361                         sl.add_span(x, cur_cell->x - x, alpha);
    362                     }
    363                 }
    364             }
    365             if(sl.num_spans()) {
    366                 break;
    367             }
    368             ++m_cur_y;
    369         }
    370         sl.finalize(m_cur_y);
    371         ++m_cur_y;
    372         return true;
    373     }
    374     template<class VertexSource>
    375     void add_path(VertexSource& vs, unsigned path_id = 0)
    376     {
    377         float x;
    378         float y;
    379         unsigned cmd;
    380         vs.rewind(path_id);
    381         while(!is_stop(cmd = vs.vertex(&x, &y))) {
    382             add_vertex(x, y, cmd);
    383         }
    384     }
    385     template<class VertexSource>
    386     void add_path_transformed(VertexSource& vs, const CFX_Matrix* pMatrix, unsigned path_id = 0)
    387     {
    388         float x;
    389         float y;
    390         unsigned cmd;
    391         vs.rewind(path_id);
    392         while(!is_stop(cmd = vs.vertex(&x, &y))) {
    393           if (pMatrix) {
    394             CFX_PointF ret = pMatrix->Transform(CFX_PointF(x, y));
    395             x = ret.x;
    396             y = ret.y;
    397           }
    398           add_vertex(x, y, cmd);
    399         }
    400     }
    401 private:
    402     rasterizer_scanline_aa(const rasterizer_scanline_aa&);
    403     const rasterizer_scanline_aa&
    404     operator = (const rasterizer_scanline_aa&);
    405     void move_to_no_clip(int x, int y)
    406     {
    407         if(m_status == status_line_to) {
    408             close_polygon_no_clip();
    409         }
    410         m_outline.move_to(x * 1, y);
    411         m_clipped_start_x = x;
    412         m_clipped_start_y = y;
    413         m_status = status_line_to;
    414     }
    415     void line_to_no_clip(int x, int y)
    416     {
    417         if(m_status != status_initial) {
    418             m_outline.line_to(x * 1, y);
    419             m_status = status_line_to;
    420         }
    421     }
    422     void close_polygon_no_clip()
    423     {
    424         if(m_status == status_line_to) {
    425             m_outline.line_to(m_clipped_start_x * 1, m_clipped_start_y);
    426             m_status = status_closed;
    427         }
    428     }
    429     void clip_segment(int x, int y)
    430     {
    431         unsigned flags = clipping_flags(x, y, m_clip_box);
    432         if(m_prev_flags == flags) {
    433             if(flags == 0) {
    434                 if(m_status == status_initial) {
    435                     move_to_no_clip(x, y);
    436                 } else {
    437                     line_to_no_clip(x, y);
    438                 }
    439             }
    440         } else {
    441             int cx[4];
    442             int cy[4];
    443             unsigned n = clip_liang_barsky(m_prev_x, m_prev_y,
    444                                            x, y,
    445                                            m_clip_box,
    446                                            cx, cy);
    447             const int* px = cx;
    448             const int* py = cy;
    449             while(n--) {
    450                 if(m_status == status_initial) {
    451                     move_to_no_clip(*px++, *py++);
    452                 } else {
    453                     line_to_no_clip(*px++, *py++);
    454                 }
    455             }
    456         }
    457         m_prev_flags = flags;
    458         m_prev_x = x;
    459         m_prev_y = y;
    460     }
    461 private:
    462     outline_aa     m_outline;
    463     filling_rule_e m_filling_rule;
    464     int            m_clipped_start_x;
    465     int            m_clipped_start_y;
    466     int            m_start_x;
    467     int            m_start_y;
    468     int            m_prev_x;
    469     int            m_prev_y;
    470     unsigned       m_prev_flags;
    471     unsigned       m_status;
    472     rect           m_clip_box;
    473     bool           m_clipping;
    474     int            m_cur_y;
    475 };
    476 }
    477 #endif
    478