1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
10 // The author gratefully acknowleges the support of David Turner,
11 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
12 // libray - in producing this work. See http://www.freetype.org for details.
14 //----------------------------------------------------------------------------
15 // Contact: mcseem@antigrain.com
16 // mcseemagg@yahoo.com
17 // http://www.antigrain.com
18 //----------------------------------------------------------------------------
20 // Class outline_aa - implementation.
22 // Initially the rendering algorithm was designed by David Turner and the
23 // other authors of the FreeType library - see the above notice. I nearly
24 // created a similar renderer, but still I was far from David's work.
25 // I completely redesigned the original code and adapted it for Anti-Grain
26 // ideas. Two functions - render_line and render_hline are the core of
27 // the algorithm - they calculate the exact coverage of each pixel cell
28 // of the polygon. I left these functions almost as is, because there's
29 // no way to improve the perfection - hats off to David and his group!
31 // All other code is very different from the original.
33 //----------------------------------------------------------------------------
36 #include "agg_rasterizer_scanline_aa.h"
42 //------------------------------------------------------------------------
43 AGG_INLINE
void cell_aa::set_cover(int c
, int a
)
49 //------------------------------------------------------------------------
50 AGG_INLINE
void cell_aa::add_cover(int c
, int a
)
56 //------------------------------------------------------------------------
57 AGG_INLINE
void cell_aa::set_coord(int cx
, int cy
)
61 packed_coord
= (cy
<< 16) + cx
;
64 //------------------------------------------------------------------------
65 AGG_INLINE
void cell_aa::set(int cx
, int cy
, int c
, int a
)
69 packed_coord
= (cy
<< 16) + cx
;
74 //------------------------------------------------------------------------
75 outline_aa::~outline_aa()
77 delete [] m_sorted_cells
;
80 cell_aa
** ptr
= m_cells
+ m_num_blocks
- 1;
91 //------------------------------------------------------------------------
92 outline_aa::outline_aa() :
105 m_max_x(-0x7FFFFFFF),
106 m_max_y(-0x7FFFFFFF),
109 m_cur_cell
.set(0x7FFF, 0x7FFF, 0, 0);
113 //------------------------------------------------------------------------
114 void outline_aa::reset()
118 m_cur_cell
.set(0x7FFF, 0x7FFF, 0, 0);
120 m_min_x
= 0x7FFFFFFF;
121 m_min_y
= 0x7FFFFFFF;
122 m_max_x
= -0x7FFFFFFF;
123 m_max_y
= -0x7FFFFFFF;
128 //------------------------------------------------------------------------
129 void outline_aa::allocate_block()
131 if(m_cur_block
>= m_num_blocks
)
133 if(m_num_blocks
>= m_max_blocks
)
135 cell_aa
** new_cells
= new cell_aa
* [m_max_blocks
+ cell_block_pool
];
138 memcpy(new_cells
, m_cells
, m_max_blocks
* sizeof(cell_aa
*));
142 m_max_blocks
+= cell_block_pool
;
144 m_cells
[m_num_blocks
++] = new cell_aa
[unsigned(cell_block_size
)];
146 m_cur_cell_ptr
= m_cells
[m_cur_block
++];
150 //------------------------------------------------------------------------
151 AGG_INLINE
void outline_aa::add_cur_cell()
153 if(m_cur_cell
.area
| m_cur_cell
.cover
)
155 if((m_num_cells
& cell_block_mask
) == 0)
157 if(m_num_blocks
>= cell_block_limit
) return;
160 *m_cur_cell_ptr
++ = m_cur_cell
;
162 if(m_cur_cell
.x
< m_min_x
) m_min_x
= m_cur_cell
.x
;
163 if(m_cur_cell
.x
> m_max_x
) m_max_x
= m_cur_cell
.x
;
169 //------------------------------------------------------------------------
170 AGG_INLINE
void outline_aa::set_cur_cell(int x
, int y
)
172 if(m_cur_cell
.packed_coord
!= (y
<< 16) + x
)
175 m_cur_cell
.set(x
, y
, 0, 0);
181 //------------------------------------------------------------------------
182 AGG_INLINE
void outline_aa::render_hline(int ey
, int x1
, int y1
, int x2
, int y2
)
184 int ex1
= x1
>> poly_base_shift
;
185 int ex2
= x2
>> poly_base_shift
;
186 int fx1
= x1
& poly_base_mask
;
187 int fx2
= x2
& poly_base_mask
;
189 int delta
, p
, first
, dx
;
190 int incr
, lift
, mod
, rem
;
192 //trivial case. Happens often
195 set_cur_cell(ex2
, ey
);
199 //everything is located in a single cell. That is easy!
203 m_cur_cell
.add_cover(delta
, (fx1
+ fx2
) * delta
);
207 //ok, we'll have to render a run of adjacent cells on the same
209 p
= (poly_base_size
- fx1
) * (y2
- y1
);
210 first
= poly_base_size
;
232 m_cur_cell
.add_cover(delta
, (fx1
+ first
) * delta
);
235 set_cur_cell(ex1
, ey
);
240 p
= poly_base_size
* (y2
- y1
+ delta
);
262 m_cur_cell
.add_cover(delta
, (poly_base_size
) * delta
);
265 set_cur_cell(ex1
, ey
);
269 m_cur_cell
.add_cover(delta
, (fx2
+ poly_base_size
- first
) * delta
);
277 //------------------------------------------------------------------------
278 void outline_aa::render_line(int x1
, int y1
, int x2
, int y2
)
280 int ey1
= y1
>> poly_base_shift
;
281 int ey2
= y2
>> poly_base_shift
;
282 int fy1
= y1
& poly_base_mask
;
283 int fy2
= y2
& poly_base_mask
;
285 int dx
, dy
, x_from
, x_to
;
286 int p
, rem
, mod
, lift
, delta
, first
, incr
;
291 //everything is on a single hline
294 render_hline(ey1
, x1
, fy1
, x2
, fy2
);
298 //Vertical line - we have to calculate start and end cells,
299 //and then - the common values of the area and coverage for
300 //all cells of the line. We know exactly there's only one
301 //cell, so, we don't have to call render_hline().
305 int ex
= x1
>> poly_base_shift
;
306 int two_fx
= (x1
- (ex
<< poly_base_shift
)) << 1;
309 first
= poly_base_size
;
318 //render_hline(ey1, x_from, fy1, x_from, first);
320 m_cur_cell
.add_cover(delta
, two_fx
* delta
);
323 set_cur_cell(ex
, ey1
);
325 delta
= first
+ first
- poly_base_size
;
326 area
= two_fx
* delta
;
329 //render_hline(ey1, x_from, poly_base_size - first, x_from, first);
330 m_cur_cell
.set_cover(delta
, area
);
332 set_cur_cell(ex
, ey1
);
334 //render_hline(ey1, x_from, poly_base_size - first, x_from, fy2);
335 delta
= fy2
- poly_base_size
+ first
;
336 m_cur_cell
.add_cover(delta
, two_fx
* delta
);
340 //ok, we have to render several hlines
341 p
= (poly_base_size
- fy1
) * dx
;
342 first
= poly_base_size
;
362 render_hline(ey1
, x1
, fy1
, x_from
, first
);
365 set_cur_cell(x_from
>> poly_base_shift
, ey1
);
369 p
= poly_base_size
* dx
;
390 x_to
= x_from
+ delta
;
391 render_hline(ey1
, x_from
, poly_base_size
- first
, x_to
, first
);
395 set_cur_cell(x_from
>> poly_base_shift
, ey1
);
398 render_hline(ey1
, x_from
, poly_base_size
- first
, x2
, fy2
);
402 //------------------------------------------------------------------------
403 void outline_aa::move_to(int x
, int y
)
405 if(m_sorted
) reset();
406 set_cur_cell(x
>> poly_base_shift
, y
>> poly_base_shift
);
413 //------------------------------------------------------------------------
414 void outline_aa::line_to(int x
, int y
)
416 render_line(m_cur_x
, m_cur_y
, x
, y
);
423 //------------------------------------------------------------------------
430 //------------------------------------------------------------------------
431 template <class T
> AGG_INLINE
void swap_cells(T
* a
, T
* b
)
438 //------------------------------------------------------------------------
439 template <class T
> AGG_INLINE
bool less_than(T
* a
, T
* b
)
441 return (*a
)->packed_coord
< (*b
)->packed_coord
;
446 //------------------------------------------------------------------------
447 void outline_aa::qsort_cells(cell_aa
** start
, unsigned num
)
460 int len
= int(limit
- base
);
466 if(len
> qsort_threshold
)
468 // we use base + len/2 as the pivot
469 pivot
= base
+ len
/ 2;
470 swap_cells(base
, pivot
);
475 // now ensure that *i <= *base <= *j
481 if(less_than(base
, i
))
486 if(less_than(j
, base
))
493 do i
++; while( less_than(i
, base
) );
494 do j
--; while( less_than(base
, j
) );
506 // now, push the largest sub-array
507 if(j
- base
> limit
- i
)
523 // the sub-array is small, perform insertion sort
527 for(; i
< limit
; j
= i
, i
++)
529 for(; less_than(j
+ 1, j
); j
--)
531 swap_cells(j
+ 1, j
);
556 //------------------------------------------------------------------------
557 void outline_aa::sort_cells()
559 if(m_num_cells
== 0) return;
560 if(m_num_cells
> m_sorted_size
)
562 delete [] m_sorted_cells
;
563 m_sorted_size
= m_num_cells
;
564 m_sorted_cells
= new cell_aa
* [m_num_cells
+ 1];
567 cell_aa
** sorted_ptr
= m_sorted_cells
;
568 cell_aa
** block_ptr
= m_cells
;
571 unsigned nb
= m_num_cells
>> cell_block_shift
;
576 cell_ptr
= *block_ptr
++;
580 *sorted_ptr
++ = cell_ptr
++;
584 cell_ptr
= *block_ptr
++;
585 i
= m_num_cells
& cell_block_mask
;
588 *sorted_ptr
++ = cell_ptr
++;
590 m_sorted_cells
[m_num_cells
] = 0;
591 qsort_cells(m_sorted_cells
, m_num_cells
);
592 m_min_y
= m_sorted_cells
[0]->y
;
593 m_max_y
= m_sorted_cells
[m_num_cells
- 1]->y
;
599 //------------------------------------------------------------------------
600 const cell_aa
* const* outline_aa::cells()
602 //Perform sort only the first time.
609 return m_sorted_cells
;