1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
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 //----------------------------------------------------------------------------
12 // The author gratefully acknowleges the support of David Turner,
13 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
14 // libray - in producing this work. See http://www.freetype.org for details.
16 //----------------------------------------------------------------------------
17 // Contact: mcseem@antigrain.com
18 // mcseemagg@yahoo.com
19 // http://www.antigrain.com
20 //----------------------------------------------------------------------------
22 // Adaptation for 32-bit screen coordinates has been sponsored by
23 // Liberty Technology Systems, Inc., visit http://lib-sys.com
25 // Liberty Technology Systems, Inc. is the provider of
26 // PostScript and PDF technology for software developers.
28 //----------------------------------------------------------------------------
29 #ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED
30 #define AGG_RASTERIZER_CELLS_AA_INCLUDED
35 #include "agg_array.h"
41 //-----------------------------------------------------rasterizer_cells_aa
42 // An internal class that implements the main rasterization algorithm.
43 // Used in the rasterizer. Should not be used direcly.
44 template<class Cell
> class rasterizer_cells_aa
46 enum cell_block_scale_e
48 cell_block_shift
= 12,
49 cell_block_size
= 1 << cell_block_shift
,
50 cell_block_mask
= cell_block_size
- 1,
51 cell_block_pool
= 256,
52 cell_block_limit
= 1024
62 typedef Cell cell_type
;
63 typedef rasterizer_cells_aa
<Cell
> self_type
;
65 ~rasterizer_cells_aa();
66 rasterizer_cells_aa();
69 void style(const cell_type
& style_cell
);
70 void line(int x1
, int y1
, int x2
, int y2
);
72 int min_x() const { return m_min_x
; }
73 int min_y() const { return m_min_y
; }
74 int max_x() const { return m_max_x
; }
75 int max_y() const { return m_max_y
; }
79 unsigned total_cells() const
84 unsigned scanline_num_cells(unsigned y
) const
86 return m_sorted_y
[y
- m_min_y
].num
;
89 const cell_type
* const* scanline_cells(unsigned y
) const
91 return m_sorted_cells
.data() + m_sorted_y
[y
- m_min_y
].start
;
94 bool sorted() const { return m_sorted
; }
97 rasterizer_cells_aa(const self_type
&);
98 const self_type
& operator = (const self_type
&);
100 void set_curr_cell(int x
, int y
);
101 void add_curr_cell();
102 void render_hline(int ey
, int x1
, int y1
, int x2
, int y2
);
103 void allocate_block();
106 unsigned m_num_blocks
;
107 unsigned m_max_blocks
;
108 unsigned m_curr_block
;
109 unsigned m_num_cells
;
111 cell_type
* m_curr_cell_ptr
;
112 pod_vector
<cell_type
*> m_sorted_cells
;
113 pod_vector
<sorted_y
> m_sorted_y
;
114 cell_type m_curr_cell
;
115 cell_type m_style_cell
;
126 //------------------------------------------------------------------------
128 rasterizer_cells_aa
<Cell
>::~rasterizer_cells_aa()
132 cell_type
** ptr
= m_cells
+ m_num_blocks
- 1;
133 while(m_num_blocks
--)
135 pod_allocator
<cell_type
>::deallocate(*ptr
, cell_block_size
);
138 pod_allocator
<cell_type
*>::deallocate(m_cells
, m_max_blocks
);
142 //------------------------------------------------------------------------
144 rasterizer_cells_aa
<Cell
>::rasterizer_cells_aa() :
155 m_max_x(-0x7FFFFFFF),
156 m_max_y(-0x7FFFFFFF),
159 m_style_cell
.initial();
160 m_curr_cell
.initial();
163 //------------------------------------------------------------------------
165 void rasterizer_cells_aa
<Cell
>::reset()
169 m_curr_cell
.initial();
170 m_style_cell
.initial();
172 m_min_x
= 0x7FFFFFFF;
173 m_min_y
= 0x7FFFFFFF;
174 m_max_x
= -0x7FFFFFFF;
175 m_max_y
= -0x7FFFFFFF;
178 //------------------------------------------------------------------------
180 AGG_INLINE
void rasterizer_cells_aa
<Cell
>::add_curr_cell()
182 if(m_curr_cell
.area
| m_curr_cell
.cover
)
184 if((m_num_cells
& cell_block_mask
) == 0)
186 if(m_num_blocks
>= cell_block_limit
) return;
189 *m_curr_cell_ptr
++ = m_curr_cell
;
194 //------------------------------------------------------------------------
196 AGG_INLINE
void rasterizer_cells_aa
<Cell
>::set_curr_cell(int x
, int y
)
198 if(m_curr_cell
.not_equal(x
, y
, m_style_cell
))
201 m_curr_cell
.style(m_style_cell
);
204 m_curr_cell
.cover
= 0;
205 m_curr_cell
.area
= 0;
209 //------------------------------------------------------------------------
211 AGG_INLINE
void rasterizer_cells_aa
<Cell
>::render_hline(int ey
,
215 int ex1
= x1
>> poly_subpixel_shift
;
216 int ex2
= x2
>> poly_subpixel_shift
;
217 int fx1
= x1
& poly_subpixel_mask
;
218 int fx2
= x2
& poly_subpixel_mask
;
220 int delta
, p
, first
, dx
;
221 int incr
, lift
, mod
, rem
;
223 //trivial case. Happens often
226 set_curr_cell(ex2
, ey
);
230 //everything is located in a single cell. That is easy!
234 m_curr_cell
.cover
+= delta
;
235 m_curr_cell
.area
+= (fx1
+ fx2
) * delta
;
239 //ok, we'll have to render a run of adjacent cells on the same
241 p
= (poly_subpixel_scale
- fx1
) * (y2
- y1
);
242 first
= poly_subpixel_scale
;
264 m_curr_cell
.cover
+= delta
;
265 m_curr_cell
.area
+= (fx1
+ first
) * delta
;
268 set_curr_cell(ex1
, ey
);
273 p
= poly_subpixel_scale
* (y2
- y1
+ delta
);
295 m_curr_cell
.cover
+= delta
;
296 m_curr_cell
.area
+= poly_subpixel_scale
* delta
;
299 set_curr_cell(ex1
, ey
);
303 m_curr_cell
.cover
+= delta
;
304 m_curr_cell
.area
+= (fx2
+ poly_subpixel_scale
- first
) * delta
;
307 //------------------------------------------------------------------------
309 AGG_INLINE
void rasterizer_cells_aa
<Cell
>::style(const cell_type
& style_cell
)
311 m_style_cell
.style(style_cell
);
314 //------------------------------------------------------------------------
316 void rasterizer_cells_aa
<Cell
>::line(int x1
, int y1
, int x2
, int y2
)
318 enum dx_limit_e
{ dx_limit
= 16384 << poly_subpixel_shift
};
322 if(dx
>= dx_limit
|| dx
<= -dx_limit
)
324 int cx
= (x1
+ x2
) >> 1;
325 int cy
= (y1
+ y2
) >> 1;
326 line(x1
, y1
, cx
, cy
);
327 line(cx
, cy
, x2
, y2
);
331 int ex1
= x1
>> poly_subpixel_shift
;
332 int ex2
= x2
>> poly_subpixel_shift
;
333 int ey1
= y1
>> poly_subpixel_shift
;
334 int ey2
= y2
>> poly_subpixel_shift
;
335 int fy1
= y1
& poly_subpixel_mask
;
336 int fy2
= y2
& poly_subpixel_mask
;
339 int p
, rem
, mod
, lift
, delta
, first
, incr
;
341 if(ex1
< m_min_x
) m_min_x
= ex1
;
342 if(ex1
> m_max_x
) m_max_x
= ex1
;
343 if(ey1
< m_min_y
) m_min_y
= ey1
;
344 if(ey1
> m_max_y
) m_max_y
= ey1
;
345 if(ex2
< m_min_x
) m_min_x
= ex2
;
346 if(ex2
> m_max_x
) m_max_x
= ex2
;
347 if(ey2
< m_min_y
) m_min_y
= ey2
;
348 if(ey2
> m_max_y
) m_max_y
= ey2
;
350 set_curr_cell(ex1
, ey1
);
352 //everything is on a single hline
355 render_hline(ey1
, x1
, fy1
, x2
, fy2
);
359 //Vertical line - we have to calculate start and end cells,
360 //and then - the common values of the area and coverage for
361 //all cells of the line. We know exactly there's only one
362 //cell, so, we don't have to call render_hline().
366 int ex
= x1
>> poly_subpixel_shift
;
367 int two_fx
= (x1
- (ex
<< poly_subpixel_shift
)) << 1;
370 first
= poly_subpixel_scale
;
379 //render_hline(ey1, x_from, fy1, x_from, first);
381 m_curr_cell
.cover
+= delta
;
382 m_curr_cell
.area
+= two_fx
* delta
;
385 set_curr_cell(ex
, ey1
);
387 delta
= first
+ first
- poly_subpixel_scale
;
388 area
= two_fx
* delta
;
391 //render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, first);
392 m_curr_cell
.cover
= delta
;
393 m_curr_cell
.area
= area
;
395 set_curr_cell(ex
, ey1
);
397 //render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, fy2);
398 delta
= fy2
- poly_subpixel_scale
+ first
;
399 m_curr_cell
.cover
+= delta
;
400 m_curr_cell
.area
+= two_fx
* delta
;
404 //ok, we have to render several hlines
405 p
= (poly_subpixel_scale
- fy1
) * dx
;
406 first
= poly_subpixel_scale
;
426 render_hline(ey1
, x1
, fy1
, x_from
, first
);
429 set_curr_cell(x_from
>> poly_subpixel_shift
, ey1
);
433 p
= poly_subpixel_scale
* dx
;
454 x_to
= x_from
+ delta
;
455 render_hline(ey1
, x_from
, poly_subpixel_scale
- first
, x_to
, first
);
459 set_curr_cell(x_from
>> poly_subpixel_shift
, ey1
);
462 render_hline(ey1
, x_from
, poly_subpixel_scale
- first
, x2
, fy2
);
465 //------------------------------------------------------------------------
467 void rasterizer_cells_aa
<Cell
>::allocate_block()
469 if(m_curr_block
>= m_num_blocks
)
471 if(m_num_blocks
>= m_max_blocks
)
473 cell_type
** new_cells
=
474 pod_allocator
<cell_type
*>::allocate(m_max_blocks
+
479 memcpy(new_cells
, m_cells
, m_max_blocks
* sizeof(cell_type
*));
480 pod_allocator
<cell_type
*>::deallocate(m_cells
, m_max_blocks
);
483 m_max_blocks
+= cell_block_pool
;
486 m_cells
[m_num_blocks
++] =
487 pod_allocator
<cell_type
>::allocate(cell_block_size
);
490 m_curr_cell_ptr
= m_cells
[m_curr_block
++];
495 //------------------------------------------------------------------------
496 template <class T
> static AGG_INLINE
void swap_cells(T
* a
, T
* b
)
504 //------------------------------------------------------------------------
511 //------------------------------------------------------------------------
513 void qsort_cells(Cell
** start
, unsigned num
)
526 int len
= int(limit
- base
);
532 if(len
> qsort_threshold
)
534 // we use base + len/2 as the pivot
535 pivot
= base
+ len
/ 2;
536 swap_cells(base
, pivot
);
541 // now ensure that *i <= *base <= *j
542 if((*j
)->x
< (*i
)->x
)
547 if((*base
)->x
< (*i
)->x
)
552 if((*j
)->x
< (*base
)->x
)
560 do i
++; while( (*i
)->x
< x
);
561 do j
--; while( x
< (*j
)->x
);
573 // now, push the largest sub-array
574 if(j
- base
> limit
- i
)
590 // the sub-array is small, perform insertion sort
594 for(; i
< limit
; j
= i
, i
++)
596 for(; j
[1]->x
< (*j
)->x
; j
--)
598 swap_cells(j
+ 1, j
);
621 //------------------------------------------------------------------------
623 void rasterizer_cells_aa
<Cell
>::sort_cells()
625 if(m_sorted
) return; //Perform sort only the first time.
628 m_curr_cell
.x
= 0x7FFFFFFF;
629 m_curr_cell
.y
= 0x7FFFFFFF;
630 m_curr_cell
.cover
= 0;
631 m_curr_cell
.area
= 0;
633 if(m_num_cells
== 0) return;
635 // DBG: Check to see if min/max works well.
636 //for(unsigned nc = 0; nc < m_num_cells; nc++)
638 // cell_type* cell = m_cells[nc >> cell_block_shift] + (nc & cell_block_mask);
639 // if(cell->x < m_min_x ||
640 // cell->y < m_min_y ||
641 // cell->x > m_max_x ||
642 // cell->y > m_max_y)
644 // cell = cell; // Breakpoint here
648 // Allocate the array of cell pointers
649 m_sorted_cells
.allocate(m_num_cells
, 16);
651 // Allocate and zero the Y array
652 m_sorted_y
.allocate(m_max_y
- m_min_y
+ 1, 16);
655 // Create the Y-histogram (count the numbers of cells for each Y)
656 cell_type
** block_ptr
= m_cells
;
658 unsigned nb
= m_num_cells
>> cell_block_shift
;
662 cell_ptr
= *block_ptr
++;
666 m_sorted_y
[cell_ptr
->y
- m_min_y
].start
++;
671 cell_ptr
= *block_ptr
++;
672 i
= m_num_cells
& cell_block_mask
;
675 m_sorted_y
[cell_ptr
->y
- m_min_y
].start
++;
679 // Convert the Y-histogram into the array of starting indexes
681 for(i
= 0; i
< m_sorted_y
.size(); i
++)
683 unsigned v
= m_sorted_y
[i
].start
;
684 m_sorted_y
[i
].start
= start
;
688 // Fill the cell pointer array sorted by Y
690 nb
= m_num_cells
>> cell_block_shift
;
693 cell_ptr
= *block_ptr
++;
697 sorted_y
& curr_y
= m_sorted_y
[cell_ptr
->y
- m_min_y
];
698 m_sorted_cells
[curr_y
.start
+ curr_y
.num
] = cell_ptr
;
704 cell_ptr
= *block_ptr
++;
705 i
= m_num_cells
& cell_block_mask
;
708 sorted_y
& curr_y
= m_sorted_y
[cell_ptr
->y
- m_min_y
];
709 m_sorted_cells
[curr_y
.start
+ curr_y
.num
] = cell_ptr
;
714 // Finally arrange the X-arrays
715 for(i
= 0; i
< m_sorted_y
.size(); i
++)
717 const sorted_y
& curr_y
= m_sorted_y
[i
];
720 qsort_cells(m_sorted_cells
.data() + curr_y
.start
, curr_y
.num
);
728 //------------------------------------------------------scanline_hit_test
729 class scanline_hit_test
732 scanline_hit_test(int x
) : m_x(x
), m_hit(false) {}
734 void reset_spans() {}
735 void finalize(int) {}
736 void add_cell(int x
, int)
738 if(m_x
== x
) m_hit
= true;
740 void add_span(int x
, int len
, int)
742 if(m_x
>= x
&& m_x
< x
+len
) m_hit
= true;
744 unsigned num_spans() const { return 1; }
745 bool hit() const { return m_hit
; }