btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / headers / libs / agg / agg_rasterizer_cells_aa.h
blob59ffd777390fb179d9b6ee628809c4faf69f8681
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
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 //----------------------------------------------------------------------------
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.
27 //
28 //----------------------------------------------------------------------------
29 #ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED
30 #define AGG_RASTERIZER_CELLS_AA_INCLUDED
32 #include <string.h>
33 #include <math.h>
34 #include "agg_math.h"
35 #include "agg_array.h"
38 namespace agg
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
55 struct sorted_y
57 unsigned start;
58 unsigned num;
61 public:
62 typedef Cell cell_type;
63 typedef rasterizer_cells_aa<Cell> self_type;
65 ~rasterizer_cells_aa();
66 rasterizer_cells_aa();
68 void reset();
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; }
77 void sort_cells();
79 unsigned total_cells() const
81 return m_num_cells;
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; }
96 private:
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();
105 private:
106 unsigned m_num_blocks;
107 unsigned m_max_blocks;
108 unsigned m_curr_block;
109 unsigned m_num_cells;
110 cell_type** m_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;
116 int m_min_x;
117 int m_min_y;
118 int m_max_x;
119 int m_max_y;
120 bool m_sorted;
126 //------------------------------------------------------------------------
127 template<class Cell>
128 rasterizer_cells_aa<Cell>::~rasterizer_cells_aa()
130 if(m_num_blocks)
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);
136 ptr--;
138 pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
142 //------------------------------------------------------------------------
143 template<class Cell>
144 rasterizer_cells_aa<Cell>::rasterizer_cells_aa() :
145 m_num_blocks(0),
146 m_max_blocks(0),
147 m_curr_block(0),
148 m_num_cells(0),
149 m_cells(0),
150 m_curr_cell_ptr(0),
151 m_sorted_cells(),
152 m_sorted_y(),
153 m_min_x(0x7FFFFFFF),
154 m_min_y(0x7FFFFFFF),
155 m_max_x(-0x7FFFFFFF),
156 m_max_y(-0x7FFFFFFF),
157 m_sorted(false)
159 m_style_cell.initial();
160 m_curr_cell.initial();
163 //------------------------------------------------------------------------
164 template<class Cell>
165 void rasterizer_cells_aa<Cell>::reset()
167 m_num_cells = 0;
168 m_curr_block = 0;
169 m_curr_cell.initial();
170 m_style_cell.initial();
171 m_sorted = false;
172 m_min_x = 0x7FFFFFFF;
173 m_min_y = 0x7FFFFFFF;
174 m_max_x = -0x7FFFFFFF;
175 m_max_y = -0x7FFFFFFF;
178 //------------------------------------------------------------------------
179 template<class Cell>
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;
187 allocate_block();
189 *m_curr_cell_ptr++ = m_curr_cell;
190 ++m_num_cells;
194 //------------------------------------------------------------------------
195 template<class Cell>
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))
200 add_curr_cell();
201 m_curr_cell.style(m_style_cell);
202 m_curr_cell.x = x;
203 m_curr_cell.y = y;
204 m_curr_cell.cover = 0;
205 m_curr_cell.area = 0;
209 //------------------------------------------------------------------------
210 template<class Cell>
211 AGG_INLINE void rasterizer_cells_aa<Cell>::render_hline(int ey,
212 int x1, int y1,
213 int x2, int y2)
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
224 if(y1 == y2)
226 set_curr_cell(ex2, ey);
227 return;
230 //everything is located in a single cell. That is easy!
231 if(ex1 == ex2)
233 delta = y2 - y1;
234 m_curr_cell.cover += delta;
235 m_curr_cell.area += (fx1 + fx2) * delta;
236 return;
239 //ok, we'll have to render a run of adjacent cells on the same
240 //hline...
241 p = (poly_subpixel_scale - fx1) * (y2 - y1);
242 first = poly_subpixel_scale;
243 incr = 1;
245 dx = x2 - x1;
247 if(dx < 0)
249 p = fx1 * (y2 - y1);
250 first = 0;
251 incr = -1;
252 dx = -dx;
255 delta = p / dx;
256 mod = p % dx;
258 if(mod < 0)
260 delta--;
261 mod += dx;
264 m_curr_cell.cover += delta;
265 m_curr_cell.area += (fx1 + first) * delta;
267 ex1 += incr;
268 set_curr_cell(ex1, ey);
269 y1 += delta;
271 if(ex1 != ex2)
273 p = poly_subpixel_scale * (y2 - y1 + delta);
274 lift = p / dx;
275 rem = p % dx;
277 if (rem < 0)
279 lift--;
280 rem += dx;
283 mod -= dx;
285 while (ex1 != ex2)
287 delta = lift;
288 mod += rem;
289 if(mod >= 0)
291 mod -= dx;
292 delta++;
295 m_curr_cell.cover += delta;
296 m_curr_cell.area += poly_subpixel_scale * delta;
297 y1 += delta;
298 ex1 += incr;
299 set_curr_cell(ex1, ey);
302 delta = y2 - y1;
303 m_curr_cell.cover += delta;
304 m_curr_cell.area += (fx2 + poly_subpixel_scale - first) * delta;
307 //------------------------------------------------------------------------
308 template<class Cell>
309 AGG_INLINE void rasterizer_cells_aa<Cell>::style(const cell_type& style_cell)
311 m_style_cell.style(style_cell);
314 //------------------------------------------------------------------------
315 template<class Cell>
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 };
320 int dx = x2 - x1;
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);
330 int dy = y2 - y1;
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;
338 int x_from, x_to;
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
353 if(ey1 == ey2)
355 render_hline(ey1, x1, fy1, x2, fy2);
356 return;
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().
363 incr = 1;
364 if(dx == 0)
366 int ex = x1 >> poly_subpixel_shift;
367 int two_fx = (x1 - (ex << poly_subpixel_shift)) << 1;
368 int area;
370 first = poly_subpixel_scale;
371 if(dy < 0)
373 first = 0;
374 incr = -1;
377 x_from = x1;
379 //render_hline(ey1, x_from, fy1, x_from, first);
380 delta = first - fy1;
381 m_curr_cell.cover += delta;
382 m_curr_cell.area += two_fx * delta;
384 ey1 += incr;
385 set_curr_cell(ex, ey1);
387 delta = first + first - poly_subpixel_scale;
388 area = two_fx * delta;
389 while(ey1 != ey2)
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;
394 ey1 += incr;
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;
401 return;
404 //ok, we have to render several hlines
405 p = (poly_subpixel_scale - fy1) * dx;
406 first = poly_subpixel_scale;
408 if(dy < 0)
410 p = fy1 * dx;
411 first = 0;
412 incr = -1;
413 dy = -dy;
416 delta = p / dy;
417 mod = p % dy;
419 if(mod < 0)
421 delta--;
422 mod += dy;
425 x_from = x1 + delta;
426 render_hline(ey1, x1, fy1, x_from, first);
428 ey1 += incr;
429 set_curr_cell(x_from >> poly_subpixel_shift, ey1);
431 if(ey1 != ey2)
433 p = poly_subpixel_scale * dx;
434 lift = p / dy;
435 rem = p % dy;
437 if(rem < 0)
439 lift--;
440 rem += dy;
442 mod -= dy;
444 while(ey1 != ey2)
446 delta = lift;
447 mod += rem;
448 if (mod >= 0)
450 mod -= dy;
451 delta++;
454 x_to = x_from + delta;
455 render_hline(ey1, x_from, poly_subpixel_scale - first, x_to, first);
456 x_from = x_to;
458 ey1 += incr;
459 set_curr_cell(x_from >> poly_subpixel_shift, ey1);
462 render_hline(ey1, x_from, poly_subpixel_scale - first, x2, fy2);
465 //------------------------------------------------------------------------
466 template<class Cell>
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 +
475 cell_block_pool);
477 if(m_cells)
479 memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_type*));
480 pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
482 m_cells = new_cells;
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)
498 T temp = *a;
499 *a = *b;
500 *b = temp;
504 //------------------------------------------------------------------------
505 enum
507 qsort_threshold = 9
511 //------------------------------------------------------------------------
512 template<class Cell>
513 void qsort_cells(Cell** start, unsigned num)
515 Cell** stack[80];
516 Cell*** top;
517 Cell** limit;
518 Cell** base;
520 limit = start + num;
521 base = start;
522 top = stack;
524 for (;;)
526 int len = int(limit - base);
528 Cell** i;
529 Cell** j;
530 Cell** pivot;
532 if(len > qsort_threshold)
534 // we use base + len/2 as the pivot
535 pivot = base + len / 2;
536 swap_cells(base, pivot);
538 i = base + 1;
539 j = limit - 1;
541 // now ensure that *i <= *base <= *j
542 if((*j)->x < (*i)->x)
544 swap_cells(i, j);
547 if((*base)->x < (*i)->x)
549 swap_cells(base, i);
552 if((*j)->x < (*base)->x)
554 swap_cells(base, j);
557 for(;;)
559 int x = (*base)->x;
560 do i++; while( (*i)->x < x );
561 do j--; while( x < (*j)->x );
563 if(i > j)
565 break;
568 swap_cells(i, j);
571 swap_cells(base, j);
573 // now, push the largest sub-array
574 if(j - base > limit - i)
576 top[0] = base;
577 top[1] = j;
578 base = i;
580 else
582 top[0] = i;
583 top[1] = limit;
584 limit = j;
586 top += 2;
588 else
590 // the sub-array is small, perform insertion sort
591 j = base;
592 i = j + 1;
594 for(; i < limit; j = i, i++)
596 for(; j[1]->x < (*j)->x; j--)
598 swap_cells(j + 1, j);
599 if (j == base)
601 break;
606 if(top > stack)
608 top -= 2;
609 base = top[0];
610 limit = top[1];
612 else
614 break;
621 //------------------------------------------------------------------------
622 template<class Cell>
623 void rasterizer_cells_aa<Cell>::sort_cells()
625 if(m_sorted) return; //Perform sort only the first time.
627 add_curr_cell();
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)
643 // {
644 // cell = cell; // Breakpoint here
645 // }
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);
653 m_sorted_y.zero();
655 // Create the Y-histogram (count the numbers of cells for each Y)
656 cell_type** block_ptr = m_cells;
657 cell_type* cell_ptr;
658 unsigned nb = m_num_cells >> cell_block_shift;
659 unsigned i;
660 while(nb--)
662 cell_ptr = *block_ptr++;
663 i = cell_block_size;
664 while(i--)
666 m_sorted_y[cell_ptr->y - m_min_y].start++;
667 ++cell_ptr;
671 cell_ptr = *block_ptr++;
672 i = m_num_cells & cell_block_mask;
673 while(i--)
675 m_sorted_y[cell_ptr->y - m_min_y].start++;
676 ++cell_ptr;
679 // Convert the Y-histogram into the array of starting indexes
680 unsigned start = 0;
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;
685 start += v;
688 // Fill the cell pointer array sorted by Y
689 block_ptr = m_cells;
690 nb = m_num_cells >> cell_block_shift;
691 while(nb--)
693 cell_ptr = *block_ptr++;
694 i = cell_block_size;
695 while(i--)
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;
699 ++curr_y.num;
700 ++cell_ptr;
704 cell_ptr = *block_ptr++;
705 i = m_num_cells & cell_block_mask;
706 while(i--)
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;
710 ++curr_y.num;
711 ++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];
718 if(curr_y.num)
720 qsort_cells(m_sorted_cells.data() + curr_y.start, curr_y.num);
723 m_sorted = true;
728 //------------------------------------------------------scanline_hit_test
729 class scanline_hit_test
731 public:
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; }
747 private:
748 int m_x;
749 bool m_hit;
755 #endif