1
//----------------------------------------------------------------------------
2
// Anti-Grain Geometry (AGG) - Version 2.5
3
// A high quality rendering engine for C++
4
// Copyright (C) 2002-2006 Maxim Shemanarev
5
// Contact: mcseem@antigrain.com
7
// http://antigrain.com
9
// AGG is free software; you can redistribute it and/or
10
// modify it under the terms of the GNU General Public License
11
// as published by the Free Software Foundation; either version 2
12
// of the License, or (at your option) any later version.
14
// AGG is distributed in the hope that it will be useful,
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
// GNU General Public License for more details.
19
// You should have received a copy of the GNU General Public License
20
// along with AGG; if not, write to the Free Software
21
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22
// MA 02110-1301, USA.
23
//----------------------------------------------------------------------------
25
// The author gratefully acknowleges the support of David Turner,
26
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
27
// libray - in producing this work. See http://www.freetype.org for details.
29
//----------------------------------------------------------------------------
31
// Adaptation for 32-bit screen coordinates has been sponsored by
32
// Liberty Technology Systems, Inc., visit http://lib-sys.com
34
// Liberty Technology Systems, Inc. is the provider of
35
// PostScript and PDF technology for software developers.
37
//----------------------------------------------------------------------------
39
#ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED
40
#define AGG_RASTERIZER_CELLS_AA_INCLUDED
45
#include "agg_array.h"
51
//-----------------------------------------------------rasterizer_cells_aa
52
// An internal class that implements the main rasterization algorithm.
53
// Used in the rasterizer. Should not be used direcly.
54
template<class Cell> class rasterizer_cells_aa
56
enum cell_block_scale_e
58
cell_block_shift = 12,
59
cell_block_size = 1 << cell_block_shift,
60
cell_block_mask = cell_block_size - 1,
61
cell_block_pool = 256,
62
cell_block_limit = 1024
72
typedef Cell cell_type;
73
typedef rasterizer_cells_aa<Cell> self_type;
75
~rasterizer_cells_aa();
76
rasterizer_cells_aa();
79
void style(const cell_type& style_cell);
80
void line(int x1, int y1, int x2, int y2);
82
int min_x() const { return m_min_x; }
83
int min_y() const { return m_min_y; }
84
int max_x() const { return m_max_x; }
85
int max_y() const { return m_max_y; }
89
unsigned total_cells() const
94
unsigned scanline_num_cells(unsigned y) const
96
return m_sorted_y[y - m_min_y].num;
99
const cell_type* const* scanline_cells(unsigned y) const
101
return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start;
104
bool sorted() const { return m_sorted; }
107
rasterizer_cells_aa(const self_type&);
108
const self_type& operator = (const self_type&);
110
void set_curr_cell(int x, int y);
111
void add_curr_cell();
112
void render_hline(int ey, int x1, int y1, int x2, int y2);
113
void allocate_block();
116
unsigned m_num_blocks;
117
unsigned m_max_blocks;
118
unsigned m_curr_block;
119
unsigned m_num_cells;
121
cell_type* m_curr_cell_ptr;
122
pod_vector<cell_type*> m_sorted_cells;
123
pod_vector<sorted_y> m_sorted_y;
124
cell_type m_curr_cell;
125
cell_type m_style_cell;
136
//------------------------------------------------------------------------
138
rasterizer_cells_aa<Cell>::~rasterizer_cells_aa()
142
cell_type** ptr = m_cells + m_num_blocks - 1;
143
while(m_num_blocks--)
145
pod_allocator<cell_type>::deallocate(*ptr, cell_block_size);
148
pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
152
//------------------------------------------------------------------------
154
rasterizer_cells_aa<Cell>::rasterizer_cells_aa() :
165
m_max_x(-0x7FFFFFFF),
166
m_max_y(-0x7FFFFFFF),
169
m_style_cell.initial();
170
m_curr_cell.initial();
173
//------------------------------------------------------------------------
175
void rasterizer_cells_aa<Cell>::reset()
179
m_curr_cell.initial();
180
m_style_cell.initial();
182
m_min_x = 0x7FFFFFFF;
183
m_min_y = 0x7FFFFFFF;
184
m_max_x = -0x7FFFFFFF;
185
m_max_y = -0x7FFFFFFF;
188
//------------------------------------------------------------------------
190
AGG_INLINE void rasterizer_cells_aa<Cell>::add_curr_cell()
192
if(m_curr_cell.area | m_curr_cell.cover)
194
if((m_num_cells & cell_block_mask) == 0)
196
if(m_num_blocks >= cell_block_limit) return;
199
*m_curr_cell_ptr++ = m_curr_cell;
204
//------------------------------------------------------------------------
206
AGG_INLINE void rasterizer_cells_aa<Cell>::set_curr_cell(int x, int y)
208
if(m_curr_cell.not_equal(x, y, m_style_cell))
211
m_curr_cell.style(m_style_cell);
214
m_curr_cell.cover = 0;
215
m_curr_cell.area = 0;
219
//------------------------------------------------------------------------
221
AGG_INLINE void rasterizer_cells_aa<Cell>::render_hline(int ey,
225
int ex1 = x1 >> poly_subpixel_shift;
226
int ex2 = x2 >> poly_subpixel_shift;
227
int fx1 = x1 & poly_subpixel_mask;
228
int fx2 = x2 & poly_subpixel_mask;
230
int delta, p, first, dx;
231
int incr, lift, mod, rem;
233
//trivial case. Happens often
236
set_curr_cell(ex2, ey);
240
//everything is located in a single cell. That is easy!
244
m_curr_cell.cover += delta;
245
m_curr_cell.area += (fx1 + fx2) * delta;
249
//ok, we'll have to render a run of adjacent cells on the same
251
p = (poly_subpixel_scale - fx1) * (y2 - y1);
252
first = poly_subpixel_scale;
274
m_curr_cell.cover += delta;
275
m_curr_cell.area += (fx1 + first) * delta;
278
set_curr_cell(ex1, ey);
283
p = poly_subpixel_scale * (y2 - y1 + delta);
305
m_curr_cell.cover += delta;
306
m_curr_cell.area += poly_subpixel_scale * delta;
309
set_curr_cell(ex1, ey);
313
m_curr_cell.cover += delta;
314
m_curr_cell.area += (fx2 + poly_subpixel_scale - first) * delta;
317
//------------------------------------------------------------------------
319
AGG_INLINE void rasterizer_cells_aa<Cell>::style(const cell_type& style_cell)
321
m_style_cell.style(style_cell);
324
//------------------------------------------------------------------------
326
void rasterizer_cells_aa<Cell>::line(int x1, int y1, int x2, int y2)
328
enum dx_limit_e { dx_limit = 16384 << poly_subpixel_shift };
332
if(dx >= dx_limit || dx <= -dx_limit)
334
int cx = (x1 + x2) >> 1;
335
int cy = (y1 + y2) >> 1;
337
// Bail if values are so large they are likely to wrap
338
if ((std::abs(x1) >= std::numeric_limits<int>::max()/2) || (std::abs(y1) >= std::numeric_limits<int>::max()/2) ||
339
(std::abs(x2) >= std::numeric_limits<int>::max()/2) || (std::abs(y2) >= std::numeric_limits<int>::max()/2))
342
line(x1, y1, cx, cy);
343
line(cx, cy, x2, y2);
347
int ex1 = x1 >> poly_subpixel_shift;
348
int ex2 = x2 >> poly_subpixel_shift;
349
int ey1 = y1 >> poly_subpixel_shift;
350
int ey2 = y2 >> poly_subpixel_shift;
351
int fy1 = y1 & poly_subpixel_mask;
352
int fy2 = y2 & poly_subpixel_mask;
355
int p, rem, mod, lift, delta, first, incr;
357
if(ex1 < m_min_x) m_min_x = ex1;
358
if(ex1 > m_max_x) m_max_x = ex1;
359
if(ey1 < m_min_y) m_min_y = ey1;
360
if(ey1 > m_max_y) m_max_y = ey1;
361
if(ex2 < m_min_x) m_min_x = ex2;
362
if(ex2 > m_max_x) m_max_x = ex2;
363
if(ey2 < m_min_y) m_min_y = ey2;
364
if(ey2 > m_max_y) m_max_y = ey2;
366
set_curr_cell(ex1, ey1);
368
//everything is on a single hline
371
render_hline(ey1, x1, fy1, x2, fy2);
375
//Vertical line - we have to calculate start and end cells,
376
//and then - the common values of the area and coverage for
377
//all cells of the line. We know exactly there's only one
378
//cell, so, we don't have to call render_hline().
382
int ex = x1 >> poly_subpixel_shift;
383
int two_fx = (x1 - (ex << poly_subpixel_shift)) << 1;
386
first = poly_subpixel_scale;
395
//render_hline(ey1, x_from, fy1, x_from, first);
397
m_curr_cell.cover += delta;
398
m_curr_cell.area += two_fx * delta;
401
set_curr_cell(ex, ey1);
403
delta = first + first - poly_subpixel_scale;
404
area = two_fx * delta;
407
//render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, first);
408
m_curr_cell.cover = delta;
409
m_curr_cell.area = area;
411
set_curr_cell(ex, ey1);
413
//render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, fy2);
414
delta = fy2 - poly_subpixel_scale + first;
415
m_curr_cell.cover += delta;
416
m_curr_cell.area += two_fx * delta;
420
//ok, we have to render several hlines
421
p = (poly_subpixel_scale - fy1) * dx;
422
first = poly_subpixel_scale;
442
render_hline(ey1, x1, fy1, x_from, first);
445
set_curr_cell(x_from >> poly_subpixel_shift, ey1);
449
p = poly_subpixel_scale * dx;
470
x_to = x_from + delta;
471
render_hline(ey1, x_from, poly_subpixel_scale - first, x_to, first);
475
set_curr_cell(x_from >> poly_subpixel_shift, ey1);
478
render_hline(ey1, x_from, poly_subpixel_scale - first, x2, fy2);
481
//------------------------------------------------------------------------
483
void rasterizer_cells_aa<Cell>::allocate_block()
485
if(m_curr_block >= m_num_blocks)
487
if(m_num_blocks >= m_max_blocks)
489
cell_type** new_cells =
490
pod_allocator<cell_type*>::allocate(m_max_blocks +
495
memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_type*));
496
pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
499
m_max_blocks += cell_block_pool;
502
m_cells[m_num_blocks++] =
503
pod_allocator<cell_type>::allocate(cell_block_size);
506
m_curr_cell_ptr = m_cells[m_curr_block++];
511
//------------------------------------------------------------------------
512
template <class T> static AGG_INLINE void swap_cells(T* a, T* b)
520
//------------------------------------------------------------------------
527
//------------------------------------------------------------------------
529
void qsort_cells(Cell** start, unsigned num)
542
int len = int(limit - base);
548
if(len > qsort_threshold)
550
// we use base + len/2 as the pivot
551
pivot = base + len / 2;
552
swap_cells(base, pivot);
557
// now ensure that *i <= *base <= *j
558
if((*j)->x < (*i)->x)
563
if((*base)->x < (*i)->x)
568
if((*j)->x < (*base)->x)
576
do i++; while( (*i)->x < x );
577
do j--; while( x < (*j)->x );
589
// now, push the largest sub-array
590
if(j - base > limit - i)
606
// the sub-array is small, perform insertion sort
610
for(; i < limit; j = i, i++)
612
for(; j[1]->x < (*j)->x; j--)
614
swap_cells(j + 1, j);
637
//------------------------------------------------------------------------
639
void rasterizer_cells_aa<Cell>::sort_cells()
641
if(m_sorted) return; //Perform sort only the first time.
644
m_curr_cell.x = 0x7FFFFFFF;
645
m_curr_cell.y = 0x7FFFFFFF;
646
m_curr_cell.cover = 0;
647
m_curr_cell.area = 0;
649
if(m_num_cells == 0) return;
651
// DBG: Check to see if min/max works well.
652
//for(unsigned nc = 0; nc < m_num_cells; nc++)
654
// cell_type* cell = m_cells[nc >> cell_block_shift] + (nc & cell_block_mask);
655
// if(cell->x < m_min_x ||
656
// cell->y < m_min_y ||
657
// cell->x > m_max_x ||
658
// cell->y > m_max_y)
660
// cell = cell; // Breakpoint here
663
// Allocate the array of cell pointers
664
m_sorted_cells.allocate(m_num_cells, 16);
666
// Allocate and zero the Y array
667
m_sorted_y.allocate(m_max_y - m_min_y + 1, 16);
670
// Create the Y-histogram (count the numbers of cells for each Y)
671
cell_type** block_ptr = m_cells;
673
unsigned nb = m_num_cells >> cell_block_shift;
677
cell_ptr = *block_ptr++;
681
m_sorted_y[cell_ptr->y - m_min_y].start++;
686
cell_ptr = *block_ptr++;
687
i = m_num_cells & cell_block_mask;
690
m_sorted_y[cell_ptr->y - m_min_y].start++;
694
// Convert the Y-histogram into the array of starting indexes
696
for(i = 0; i < m_sorted_y.size(); i++)
698
unsigned v = m_sorted_y[i].start;
699
m_sorted_y[i].start = start;
703
// Fill the cell pointer array sorted by Y
705
nb = m_num_cells >> cell_block_shift;
708
cell_ptr = *block_ptr++;
712
sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y];
713
m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr;
719
cell_ptr = *block_ptr++;
720
i = m_num_cells & cell_block_mask;
723
sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y];
724
m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr;
729
// Finally arrange the X-arrays
730
for(i = 0; i < m_sorted_y.size(); i++)
732
const sorted_y& curr_y = m_sorted_y[i];
735
qsort_cells(m_sorted_cells.data() + curr_y.start, curr_y.num);
743
//------------------------------------------------------scanline_hit_test
744
class scanline_hit_test
747
scanline_hit_test(int x) : m_x(x), m_hit(false) {}
749
void reset_spans() {}
750
void finalize(int) {}
751
void add_cell(int x, int)
753
if(m_x == x) m_hit = true;
755
void add_span(int x, int len, int)
757
if(m_x >= x && m_x < x+len) m_hit = true;
759
unsigned num_spans() const { return 1; }
760
bool hit() const { return m_hit; }