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