merge the formfield patch from ooo-build
[ooovba.git] / agg / source / agg_rasterizer_scanline_aa.cpp
blobba2962bbeae435cf4ee167da9f07d4e8be4e9469
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
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.
9 //
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.
32 //
33 //----------------------------------------------------------------------------
35 #include <string.h>
36 #include "agg_rasterizer_scanline_aa.h"
39 namespace agg
42 //------------------------------------------------------------------------
43 AGG_INLINE void cell_aa::set_cover(int c, int a)
45 cover = c;
46 area = a;
49 //------------------------------------------------------------------------
50 AGG_INLINE void cell_aa::add_cover(int c, int a)
52 cover += c;
53 area += a;
56 //------------------------------------------------------------------------
57 AGG_INLINE void cell_aa::set_coord(int cx, int cy)
59 x = int16(cx);
60 y = int16(cy);
61 packed_coord = (cy << 16) + cx;
64 //------------------------------------------------------------------------
65 AGG_INLINE void cell_aa::set(int cx, int cy, int c, int a)
67 x = int16(cx);
68 y = int16(cy);
69 packed_coord = (cy << 16) + cx;
70 cover = c;
71 area = a;
74 //------------------------------------------------------------------------
75 outline_aa::~outline_aa()
77 delete [] m_sorted_cells;
78 if(m_num_blocks)
80 cell_aa** ptr = m_cells + m_num_blocks - 1;
81 while(m_num_blocks--)
83 delete [] *ptr;
84 ptr--;
86 delete [] m_cells;
91 //------------------------------------------------------------------------
92 outline_aa::outline_aa() :
93 m_num_blocks(0),
94 m_max_blocks(0),
95 m_cur_block(0),
96 m_num_cells(0),
97 m_cells(0),
98 m_cur_cell_ptr(0),
99 m_sorted_cells(0),
100 m_sorted_size(0),
101 m_cur_x(0),
102 m_cur_y(0),
103 m_min_x(0x7FFFFFFF),
104 m_min_y(0x7FFFFFFF),
105 m_max_x(-0x7FFFFFFF),
106 m_max_y(-0x7FFFFFFF),
107 m_sorted(false)
109 m_cur_cell.set(0x7FFF, 0x7FFF, 0, 0);
113 //------------------------------------------------------------------------
114 void outline_aa::reset()
116 m_num_cells = 0;
117 m_cur_block = 0;
118 m_cur_cell.set(0x7FFF, 0x7FFF, 0, 0);
119 m_sorted = false;
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];
136 if(m_cells)
138 memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_aa*));
139 delete [] m_cells;
141 m_cells = new_cells;
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;
158 allocate_block();
160 *m_cur_cell_ptr++ = m_cur_cell;
161 ++m_num_cells;
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)
174 add_cur_cell();
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
193 if(y1 == y2)
195 set_cur_cell(ex2, ey);
196 return;
199 //everything is located in a single cell. That is easy!
200 if(ex1 == ex2)
202 delta = y2 - y1;
203 m_cur_cell.add_cover(delta, (fx1 + fx2) * delta);
204 return;
207 //ok, we'll have to render a run of adjacent cells on the same
208 //hline...
209 p = (poly_base_size - fx1) * (y2 - y1);
210 first = poly_base_size;
211 incr = 1;
213 dx = x2 - x1;
215 if(dx < 0)
217 p = fx1 * (y2 - y1);
218 first = 0;
219 incr = -1;
220 dx = -dx;
223 delta = p / dx;
224 mod = p % dx;
226 if(mod < 0)
228 delta--;
229 mod += dx;
232 m_cur_cell.add_cover(delta, (fx1 + first) * delta);
234 ex1 += incr;
235 set_cur_cell(ex1, ey);
236 y1 += delta;
238 if(ex1 != ex2)
240 p = poly_base_size * (y2 - y1 + delta);
241 lift = p / dx;
242 rem = p % dx;
244 if (rem < 0)
246 lift--;
247 rem += dx;
250 mod -= dx;
252 while (ex1 != ex2)
254 delta = lift;
255 mod += rem;
256 if(mod >= 0)
258 mod -= dx;
259 delta++;
262 m_cur_cell.add_cover(delta, (poly_base_size) * delta);
263 y1 += delta;
264 ex1 += incr;
265 set_cur_cell(ex1, ey);
268 delta = y2 - y1;
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;
288 dx = x2 - x1;
289 dy = y2 - y1;
291 //everything is on a single hline
292 if(ey1 == ey2)
294 render_hline(ey1, x1, fy1, x2, fy2);
295 return;
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().
302 incr = 1;
303 if(dx == 0)
305 int ex = x1 >> poly_base_shift;
306 int two_fx = (x1 - (ex << poly_base_shift)) << 1;
307 int area;
309 first = poly_base_size;
310 if(dy < 0)
312 first = 0;
313 incr = -1;
316 x_from = x1;
318 //render_hline(ey1, x_from, fy1, x_from, first);
319 delta = first - fy1;
320 m_cur_cell.add_cover(delta, two_fx * delta);
322 ey1 += incr;
323 set_cur_cell(ex, ey1);
325 delta = first + first - poly_base_size;
326 area = two_fx * delta;
327 while(ey1 != ey2)
329 //render_hline(ey1, x_from, poly_base_size - first, x_from, first);
330 m_cur_cell.set_cover(delta, area);
331 ey1 += incr;
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);
337 return;
340 //ok, we have to render several hlines
341 p = (poly_base_size - fy1) * dx;
342 first = poly_base_size;
344 if(dy < 0)
346 p = fy1 * dx;
347 first = 0;
348 incr = -1;
349 dy = -dy;
352 delta = p / dy;
353 mod = p % dy;
355 if(mod < 0)
357 delta--;
358 mod += dy;
361 x_from = x1 + delta;
362 render_hline(ey1, x1, fy1, x_from, first);
364 ey1 += incr;
365 set_cur_cell(x_from >> poly_base_shift, ey1);
367 if(ey1 != ey2)
369 p = poly_base_size * dx;
370 lift = p / dy;
371 rem = p % dy;
373 if(rem < 0)
375 lift--;
376 rem += dy;
378 mod -= dy;
380 while(ey1 != ey2)
382 delta = lift;
383 mod += rem;
384 if (mod >= 0)
386 mod -= dy;
387 delta++;
390 x_to = x_from + delta;
391 render_hline(ey1, x_from, poly_base_size - first, x_to, first);
392 x_from = x_to;
394 ey1 += incr;
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);
407 m_cur_x = x;
408 m_cur_y = y;
413 //------------------------------------------------------------------------
414 void outline_aa::line_to(int x, int y)
416 render_line(m_cur_x, m_cur_y, x, y);
417 m_cur_x = x;
418 m_cur_y = y;
419 m_sorted = false;
423 //------------------------------------------------------------------------
424 enum
426 qsort_threshold = 9
430 //------------------------------------------------------------------------
431 template <class T> AGG_INLINE void swap_cells(T* a, T* b)
433 T temp = *a;
434 *a = *b;
435 *b = temp;
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)
449 cell_aa** stack[80];
450 cell_aa*** top;
451 cell_aa** limit;
452 cell_aa** base;
454 limit = start + num;
455 base = start;
456 top = stack;
458 for (;;)
460 int len = int(limit - base);
462 cell_aa** i;
463 cell_aa** j;
464 cell_aa** pivot;
466 if(len > qsort_threshold)
468 // we use base + len/2 as the pivot
469 pivot = base + len / 2;
470 swap_cells(base, pivot);
472 i = base + 1;
473 j = limit - 1;
475 // now ensure that *i <= *base <= *j
476 if(less_than(j, i))
478 swap_cells(i, j);
481 if(less_than(base, i))
483 swap_cells(base, i);
486 if(less_than(j, base))
488 swap_cells(base, j);
491 for(;;)
493 do i++; while( less_than(i, base) );
494 do j--; while( less_than(base, j) );
496 if ( i > j )
498 break;
501 swap_cells(i, j);
504 swap_cells(base, j);
506 // now, push the largest sub-array
507 if(j - base > limit - i)
509 top[0] = base;
510 top[1] = j;
511 base = i;
513 else
515 top[0] = i;
516 top[1] = limit;
517 limit = j;
519 top += 2;
521 else
523 // the sub-array is small, perform insertion sort
524 j = base;
525 i = j + 1;
527 for(; i < limit; j = i, i++)
529 for(; less_than(j + 1, j); j--)
531 swap_cells(j + 1, j);
532 if (j == base)
534 break;
538 if(top > stack)
540 top -= 2;
541 base = top[0];
542 limit = top[1];
544 else
546 break;
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;
569 cell_aa* cell_ptr;
571 unsigned nb = m_num_cells >> cell_block_shift;
572 unsigned i;
574 while(nb--)
576 cell_ptr = *block_ptr++;
577 i = cell_block_size;
578 while(i--)
580 *sorted_ptr++ = cell_ptr++;
584 cell_ptr = *block_ptr++;
585 i = m_num_cells & cell_block_mask;
586 while(i--)
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.
603 if(!m_sorted)
605 add_cur_cell();
606 sort_cells();
607 m_sorted = true;
609 return m_sorted_cells;