Home | History | Annotate | Download | only in agg23
      1 
      2 //----------------------------------------------------------------------------
      3 // XYQ: 2006-01-22 Copied from AGG project.
      4 // This file uses only integer data, so it's suitable for all platforms.
      5 //----------------------------------------------------------------------------
      6 //----------------------------------------------------------------------------
      7 // Anti-Grain Geometry - Version 2.3
      8 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
      9 //
     10 // Permission to copy, use, modify, sell and distribute this software
     11 // is granted provided this copyright notice appears in all copies.
     12 // This software is provided "as is" without express or implied
     13 // warranty, and with no claim as to its suitability for any purpose.
     14 //
     15 //----------------------------------------------------------------------------
     16 //
     17 // The author gratefully acknowleges the support of David Turner,
     18 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
     19 // libray - in producing this work. See http://www.freetype.org for details.
     20 //
     21 //----------------------------------------------------------------------------
     22 // Contact: mcseem (at) antigrain.com
     23 //          mcseemagg (at) yahoo.com
     24 //          http://www.antigrain.com
     25 //----------------------------------------------------------------------------
     26 //
     27 // Adaptation for 32-bit screen coordinates has been sponsored by
     28 // Liberty Technology Systems, Inc., visit http://lib-sys.com
     29 //
     30 // Liberty Technology Systems, Inc. is the provider of
     31 // PostScript and PDF technology for software developers.
     32 //
     33 //----------------------------------------------------------------------------
     34 //
     35 // Class outline_aa - implementation.
     36 //
     37 // Initially the rendering algorithm was designed by David Turner and the
     38 // other authors of the FreeType library - see the above notice. I nearly
     39 // created a similar renderer, but still I was far from David's work.
     40 // I completely redesigned the original code and adapted it for Anti-Grain
     41 // ideas. Two functions - render_line and render_hline are the core of
     42 // the algorithm - they calculate the exact coverage of each pixel cell
     43 // of the polygon. I left these functions almost as is, because there's
     44 // no way to improve the perfection - hats off to David and his group!
     45 //
     46 // All other code is very different from the original.
     47 //
     48 //----------------------------------------------------------------------------
     49 #include "../../../../include/fxcrt/fx_ext.h"
     50 #include <limits.h>
     51 #include "agg_rasterizer_scanline_aa.h"
     52 namespace agg
     53 {
     54 AGG_INLINE void cell_aa::set_cover(int c, int a)
     55 {
     56     cover = c;
     57     area = a;
     58 }
     59 AGG_INLINE void cell_aa::add_cover(int c, int a)
     60 {
     61     cover += c;
     62     area += a;
     63 }
     64 AGG_INLINE void cell_aa::set_coord(int cx, int cy)
     65 {
     66     x = cx;
     67     y = cy;
     68 }
     69 AGG_INLINE void cell_aa::set(int cx, int cy, int c, int a)
     70 {
     71     x = cx;
     72     y = cy;
     73     cover = c;
     74     area = a;
     75 }
     76 outline_aa::~outline_aa()
     77 {
     78     if(m_num_blocks) {
     79         cell_aa** ptr = m_cells + m_num_blocks - 1;
     80         while(m_num_blocks--) {
     81             FX_Free(*ptr);
     82             ptr--;
     83         }
     84         FX_Free(m_cells);
     85     }
     86 }
     87 outline_aa::outline_aa() :
     88     m_num_blocks(0),
     89     m_max_blocks(0),
     90     m_cur_block(0),
     91     m_num_cells(0),
     92     m_cells(0),
     93     m_cur_cell_ptr(0),
     94     m_cur_x(0),
     95     m_cur_y(0),
     96     m_min_x(0x7FFFFFFF),
     97     m_min_y(0x7FFFFFFF),
     98     m_max_x(-0x7FFFFFFF),
     99     m_max_y(-0x7FFFFFFF),
    100     m_sorted(false)
    101 {
    102     m_cur_cell.set(0x7FFF, 0x7FFF, 0, 0);
    103 }
    104 void outline_aa::reset()
    105 {
    106     m_num_cells = 0;
    107     m_cur_block = 0;
    108     m_cur_cell.set(0x7FFF, 0x7FFF, 0, 0);
    109     m_sorted = false;
    110     m_min_x =  0x7FFFFFFF;
    111     m_min_y =  0x7FFFFFFF;
    112     m_max_x = -0x7FFFFFFF;
    113     m_max_y = -0x7FFFFFFF;
    114 }
    115 void outline_aa::allocate_block()
    116 {
    117     if(m_cur_block >= m_num_blocks) {
    118         if(m_num_blocks >= m_max_blocks) {
    119             cell_aa** new_cells = FX_Alloc( cell_aa*, m_max_blocks + cell_block_pool);
    120             if (!new_cells) {
    121                 return;
    122             }
    123             if(m_cells) {
    124                 FXSYS_memcpy32(new_cells, m_cells, m_max_blocks * sizeof(cell_aa*));
    125                 FX_Free(m_cells);
    126             }
    127             m_cells = new_cells;
    128             m_max_blocks += cell_block_pool;
    129         }
    130         m_cells[m_num_blocks++] = FX_Alloc(cell_aa, cell_block_size);
    131         if (!m_cells[m_num_blocks - 1]) {
    132             return;
    133         }
    134     }
    135     m_cur_cell_ptr = m_cells[m_cur_block++];
    136 }
    137 AGG_INLINE void outline_aa::add_cur_cell()
    138 {
    139     if(m_cur_cell.area | m_cur_cell.cover) {
    140         if((m_num_cells & cell_block_mask) == 0) {
    141             if(m_num_blocks >= cell_block_limit) {
    142                 return;
    143             }
    144             allocate_block();
    145         }
    146         *m_cur_cell_ptr++ = m_cur_cell;
    147         ++m_num_cells;
    148     }
    149 }
    150 AGG_INLINE void outline_aa::set_cur_cell(int x, int y)
    151 {
    152     if(m_cur_cell.x != x || m_cur_cell.y != y) {
    153         add_cur_cell();
    154         m_cur_cell.set(x, y, 0, 0);
    155         if(x < m_min_x) {
    156             m_min_x = x;
    157         }
    158         if(x > m_max_x) {
    159             m_max_x = x;
    160         }
    161         if(y < m_min_y) {
    162             m_min_y = y;
    163         }
    164         if(y > m_max_y) {
    165             m_max_y = y;
    166         }
    167     }
    168 }
    169 AGG_INLINE void outline_aa::render_hline(int ey, int x1, int y1, int x2, int y2)
    170 {
    171     int ex1 = x1 >> poly_base_shift;
    172     int ex2 = x2 >> poly_base_shift;
    173     int fx1 = x1 & poly_base_mask;
    174     int fx2 = x2 & poly_base_mask;
    175     int delta, p, first, dx;
    176     int incr, lift, mod, rem;
    177     if(y1 == y2) {
    178         set_cur_cell(ex2, ey);
    179         return;
    180     }
    181     if(ex1 == ex2) {
    182         delta = y2 - y1;
    183         m_cur_cell.add_cover(delta, (fx1 + fx2) * delta);
    184         return;
    185     }
    186     p     = (poly_base_size - fx1) * (y2 - y1);
    187     first = poly_base_size;
    188     incr  = 1;
    189     dx = x2 - x1;
    190     if(dx < 0) {
    191         p     = fx1 * (y2 - y1);
    192         first = 0;
    193         incr  = -1;
    194         dx    = -dx;
    195     }
    196     delta = p / dx;
    197     mod   = p % dx;
    198     if(mod < 0) {
    199         delta--;
    200         mod += dx;
    201     }
    202     m_cur_cell.add_cover(delta, (fx1 + first) * delta);
    203     ex1 += incr;
    204     set_cur_cell(ex1, ey);
    205     y1  += delta;
    206     if(ex1 != ex2) {
    207         p     = poly_base_size * (y2 - y1 + delta);
    208         lift  = p / dx;
    209         rem   = p % dx;
    210         if (rem < 0) {
    211             lift--;
    212             rem += dx;
    213         }
    214         mod -= dx;
    215         while (ex1 != ex2) {
    216             delta = lift;
    217             mod  += rem;
    218             if(mod >= 0) {
    219                 mod -= dx;
    220                 delta++;
    221             }
    222             m_cur_cell.add_cover(delta, (poly_base_size) * delta);
    223             y1  += delta;
    224             ex1 += incr;
    225             set_cur_cell(ex1, ey);
    226         }
    227     }
    228     delta = y2 - y1;
    229     m_cur_cell.add_cover(delta, (fx2 + poly_base_size - first) * delta);
    230 }
    231 void outline_aa::render_line(int x1, int y1, int x2, int y2)
    232 {
    233     enum dx_limit_e { dx_limit = 16384 << poly_base_shift };
    234     int dx = x2 - x1;
    235     if(dx >= dx_limit || dx <= -dx_limit) {
    236         int cx = (x1 + x2) >> 1;
    237         int cy = (y1 + y2) >> 1;
    238         render_line(x1, y1, cx, cy);
    239         render_line(cx, cy, x2, y2);
    240     }
    241     int dy = y2 - y1;
    242     int ey1 = y1 >> poly_base_shift;
    243     int ey2 = y2 >> poly_base_shift;
    244     int fy1 = y1 & poly_base_mask;
    245     int fy2 = y2 & poly_base_mask;
    246     int x_from, x_to;
    247     int p, rem, mod, lift, delta, first, incr;
    248     if(ey1 == ey2) {
    249         render_hline(ey1, x1, fy1, x2, fy2);
    250         return;
    251     }
    252     incr  = 1;
    253     if(dx == 0) {
    254         int ex = x1 >> poly_base_shift;
    255         int two_fx = (x1 - (ex << poly_base_shift)) << 1;
    256         int area;
    257         first = poly_base_size;
    258         if(dy < 0) {
    259             first = 0;
    260             incr  = -1;
    261         }
    262         x_from = x1;
    263         delta = first - fy1;
    264         m_cur_cell.add_cover(delta, two_fx * delta);
    265         ey1 += incr;
    266         set_cur_cell(ex, ey1);
    267         delta = first + first - poly_base_size;
    268         area = two_fx * delta;
    269         while(ey1 != ey2) {
    270             m_cur_cell.set_cover(delta, area);
    271             ey1 += incr;
    272             set_cur_cell(ex, ey1);
    273         }
    274         delta = fy2 - poly_base_size + first;
    275         m_cur_cell.add_cover(delta, two_fx * delta);
    276         return;
    277     }
    278     p     = (poly_base_size - fy1) * dx;
    279     first = poly_base_size;
    280     if(dy < 0) {
    281         p     = fy1 * dx;
    282         first = 0;
    283         incr  = -1;
    284         dy    = -dy;
    285     }
    286     delta = p / dy;
    287     mod   = p % dy;
    288     if(mod < 0) {
    289         delta--;
    290         mod += dy;
    291     }
    292     x_from = x1 + delta;
    293     render_hline(ey1, x1, fy1, x_from, first);
    294     ey1 += incr;
    295     set_cur_cell(x_from >> poly_base_shift, ey1);
    296     if(ey1 != ey2) {
    297         p     = poly_base_size * dx;
    298         lift  = p / dy;
    299         rem   = p % dy;
    300         if(rem < 0) {
    301             lift--;
    302             rem += dy;
    303         }
    304         mod -= dy;
    305         while(ey1 != ey2) {
    306             delta = lift;
    307             mod  += rem;
    308             if (mod >= 0) {
    309                 mod -= dy;
    310                 delta++;
    311             }
    312             x_to = x_from + delta;
    313             render_hline(ey1, x_from, poly_base_size - first, x_to, first);
    314             x_from = x_to;
    315             ey1 += incr;
    316             set_cur_cell(x_from >> poly_base_shift, ey1);
    317         }
    318     }
    319     render_hline(ey1, x_from, poly_base_size - first, x2, fy2);
    320 }
    321 void outline_aa::move_to(int x, int y)
    322 {
    323     if(m_sorted) {
    324         reset();
    325     }
    326     set_cur_cell(x >> poly_base_shift, y >> poly_base_shift);
    327     m_cur_x = x;
    328     m_cur_y = y;
    329 }
    330 void outline_aa::line_to(int x, int y)
    331 {
    332     render_line(m_cur_x, m_cur_y, x, y);
    333     m_cur_x = x;
    334     m_cur_y = y;
    335     m_sorted = false;
    336 }
    337 template <class T> static AGG_INLINE void swap_cells(T* a, T* b)
    338 {
    339     T temp = *a;
    340     *a = *b;
    341     *b = temp;
    342 }
    343 enum {
    344     qsort_threshold = 9
    345 };
    346 static void qsort_cells(cell_aa** start, unsigned num)
    347 {
    348     cell_aa**  stack[80];
    349     cell_aa*** top;
    350     cell_aa**  limit;
    351     cell_aa**  base;
    352     limit = start + num;
    353     base  = start;
    354     top   = stack;
    355     for (;;) {
    356         int len = int(limit - base);
    357         cell_aa** i;
    358         cell_aa** j;
    359         cell_aa** pivot;
    360         if(len > qsort_threshold) {
    361             pivot = base + len / 2;
    362             swap_cells(base, pivot);
    363             i = base + 1;
    364             j = limit - 1;
    365             if((*j)->x < (*i)->x) {
    366                 swap_cells(i, j);
    367             }
    368             if((*base)->x < (*i)->x) {
    369                 swap_cells(base, i);
    370             }
    371             if((*j)->x < (*base)->x) {
    372                 swap_cells(base, j);
    373             }
    374             for(;;) {
    375                 int x = (*base)->x;
    376                 do {
    377                     i++;
    378                 } while( (*i)->x < x );
    379                 do {
    380                     j--;
    381                 } while( x < (*j)->x );
    382                 if(i > j) {
    383                     break;
    384                 }
    385                 swap_cells(i, j);
    386             }
    387             swap_cells(base, j);
    388             if(j - base > limit - i) {
    389                 top[0] = base;
    390                 top[1] = j;
    391                 base   = i;
    392             } else {
    393                 top[0] = i;
    394                 top[1] = limit;
    395                 limit  = j;
    396             }
    397             top += 2;
    398         } else {
    399             j = base;
    400             i = j + 1;
    401             for(; i < limit; j = i, i++) {
    402                 for(; j[1]->x < (*j)->x; j--) {
    403                     swap_cells(j + 1, j);
    404                     if (j == base) {
    405                         break;
    406                     }
    407                 }
    408             }
    409             if(top > stack) {
    410                 top  -= 2;
    411                 base  = top[0];
    412                 limit = top[1];
    413             } else {
    414                 break;
    415             }
    416         }
    417     }
    418 }
    419 void outline_aa::sort_cells()
    420 {
    421     if(m_sorted) {
    422         return;
    423     }
    424     add_cur_cell();
    425     if(m_num_cells == 0) {
    426         return;
    427     }
    428     m_sorted_cells.allocate(m_num_cells, 16);
    429     if (m_max_y > 0 && m_min_y < 0 && -m_min_y > INT_MAX - m_max_y) {
    430         return;
    431     }
    432     unsigned size = m_max_y - m_min_y;
    433     if (size + 1 < size) {
    434         return;
    435     }
    436     size++;
    437     m_sorted_y.allocate(size, 16);
    438     m_sorted_y.zero();
    439     cell_aa** block_ptr = m_cells;
    440     cell_aa*  cell_ptr = NULL;
    441     unsigned nb = m_num_cells >> cell_block_shift;
    442     unsigned i;
    443     while(nb--) {
    444         cell_ptr = *block_ptr++;
    445         i = cell_block_size;
    446         while(i--) {
    447             m_sorted_y[cell_ptr->y - m_min_y].start++;
    448             ++cell_ptr;
    449         }
    450     }
    451     i = m_num_cells & cell_block_mask;
    452     if (i) {
    453         cell_ptr = *block_ptr++;
    454     }
    455     while(i--) {
    456         m_sorted_y[cell_ptr->y - m_min_y].start++;
    457         ++cell_ptr;
    458     }
    459     unsigned start = 0;
    460     for(i = 0; i < m_sorted_y.size(); i++) {
    461         unsigned v = m_sorted_y[i].start;
    462         m_sorted_y[i].start = start;
    463         start += v;
    464     }
    465     block_ptr = m_cells;
    466     nb = m_num_cells >> cell_block_shift;
    467     while(nb--) {
    468         cell_ptr = *block_ptr++;
    469         i = cell_block_size;
    470         while(i--) {
    471             sorted_y& cur_y = m_sorted_y[cell_ptr->y - m_min_y];
    472             m_sorted_cells[cur_y.start + cur_y.num] = cell_ptr;
    473             ++cur_y.num;
    474             ++cell_ptr;
    475         }
    476     }
    477     i = m_num_cells & cell_block_mask;
    478     if (i) {
    479         cell_ptr = *block_ptr++;
    480     }
    481     while(i--) {
    482         sorted_y& cur_y = m_sorted_y[cell_ptr->y - m_min_y];
    483         m_sorted_cells[cur_y.start + cur_y.num] = cell_ptr;
    484         ++cur_y.num;
    485         ++cell_ptr;
    486     }
    487     for(i = 0; i < m_sorted_y.size(); i++) {
    488         const sorted_y& cur_y = m_sorted_y[i];
    489         if(cur_y.num) {
    490             qsort_cells(m_sorted_cells.data() + cur_y.start, cur_y.num);
    491         }
    492     }
    493     m_sorted = true;
    494 }
    495 }
    496