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