1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4 (Public License)
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
6 // Pascal Port By: Milan Marusinec alias Milano
7 //                 milan@marusinec.sk
8 //                 http://www.aggpas.org
9 // Copyright (c) 2005-2006
10 //
11 // Permission to copy, use, modify, sell and distribute this software
12 // is granted provided this copyright notice appears in all copies.
13 // This software is provided "as is" without express or implied
14 // warranty, and with no claim as to its suitability for any purpose.
15 //
16 //----------------------------------------------------------------------------
17 //
18 // The author gratefully acknowleges the support of David Turner,
19 // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
20 // libray - in producing this work. See http://www.freetype.org for details.
21 //
22 //----------------------------------------------------------------------------
23 // Contact: mcseem@antigrain.com
24 //          mcseemagg@yahoo.com
25 //          http://www.antigrain.com
26 //----------------------------------------------------------------------------
27 //
28 // Adaptation for 32-bit screen coordinates has been sponsored by
29 // Liberty Technology Systems, Inc., visit http://lib-sys.com
30 //
31 // Liberty Technology Systems, Inc. is the provider of
32 // PostScript and PDF technology for software developers.
33 //
34 // [Pascal Port History] -----------------------------------------------------
35 //
36 // 16.10.2007-Milano: Unit port establishment & Finished OK
37 //
38 { agg_rasterizer_cells_aa.pas }
39 unit
40  agg_rasterizer_cells_aa ;
41 
42 INTERFACE
43 
44 {$I agg_mode.inc }
45 
46 uses
47  agg_basics ,
48  agg_math ,
49  agg_array ,
50  agg_scanline ;
51 
52 { GLOBAL VARIABLES & CONSTANTS }
53 const
54  cell_block_shift = 12;
55  cell_block_size  = 1 shl cell_block_shift;
56  cell_block_mask  = cell_block_size - 1;
57  cell_block_pool  = 256;
58  cell_block_limit = 1024;
59 
60 { TYPES DEFINITION }
61 type
62 // A pixel cell. There're no constructors defined and it was done
63 // intentionally in order to avoid extra overhead when allocating an
64 // array of cells.
65  cell_style_aa_ptr_ptr_ptr = ^cell_style_aa_ptr_ptr;
66  cell_style_aa_ptr_ptr = ^cell_style_aa_ptr;
67  cell_style_aa_ptr = ^cell_style_aa;
68  cell_style_aa = object
69    x ,y ,cover ,area : int;
70 
71    left ,right : int16;
72 
73    procedure initial;
74    procedure style    (c : cell_style_aa_ptr );
75    function  not_equal(ex ,ey : int; c : cell_style_aa_ptr ) : int;
76 
77   end;
78 
79  cell_block_scale_e = int;
80 
81  sorted_y_ptr = ^sorted_y;
82  sorted_y = record
83    start ,
84    num   : unsigned;
85 
86   end;
87 
88 { cell_type_ptr_ptr_ptr = ^cell_type_ptr_ptr;
89  cell_type_ptr_ptr = ^cell_type_ptr;
90  cell_type_ptr = ^cell_type;
91  cell_type = cell_style_aa; }
92 
93 // An internal class that implements the main rasterization algorithm.
94 // Used in the rasterizer. Should not be used direcly.
95  rasterizer_cells_aa_ptr = ^rasterizer_cells_aa;
96  rasterizer_cells_aa = object
97   private
98    m_num_blocks ,
99    m_max_blocks ,
100    m_curr_block ,
101    m_num_cells  : unsigned;
102 
103    m_cells : cell_style_aa_ptr_ptr;
104 
105    m_curr_cell_ptr : cell_style_aa_ptr;
106    m_sorted_cells  ,
107    m_sorted_y      : pod_vector;
108    m_curr_cell     ,
109    m_style_cell    : cell_style_aa;
110 
111    m_min_x ,
112    m_min_y ,
113    m_max_x ,
114    m_max_y : int;
115 
116    m_sorted : boolean;
117 
118   public
119    constructor Construct;
120    destructor  Destruct;
121 
122    procedure reset;
123    procedure style(style_cell : cell_style_aa_ptr );
124    procedure line (x1 ,y1 ,x2 ,y2 : int );
125 
126    function  min_x : int;
127    function  min_y : int;
128    function  max_x : int;
129    function  max_y : int;
130 
131    procedure sort_cells;
132    function  total_cells : unsigned;
133 
134    function  scanline_num_cells(y : unsigned ) : unsigned;
135    function  scanline_cells    (y : unsigned ) : cell_style_aa_ptr_ptr;
136 
137    function  sorted : boolean;
138 
139   private
140    procedure set_curr_cell(x ,y : int );
141    procedure add_curr_cell;
142    procedure render_hline(ey ,x1 ,y1 ,x2 ,y2 : int );
143    procedure allocate_block;
144 
145   end;
146 
147 //------------------------------------------------------scanline_hit_test
148  scanline_hit_test = object(scanline )
149   private
150    m_x   : int;
151    m_hit : boolean;
152 
153   public
154    constructor Construct(x : int );
155 
156    procedure reset_spans; virtual;
157 
158    procedure finalize(y_ : int ); virtual;
159    procedure add_cell(x : int; cover : unsigned ); virtual;
160    procedure add_span(x : int; len ,cover : unsigned ); virtual;
161 
162    function  num_spans : unsigned; virtual;
163 
164    function  hit : boolean;
165 
166   end;
167 
168 { GLOBAL PROCEDURES }
169 
170 
171 IMPLEMENTATION
172 { LOCAL VARIABLES & CONSTANTS }
173 { UNIT IMPLEMENTATION }
174 { INITIAL }
175 procedure cell_style_aa.initial;
176 begin
177  x    :=$7FFFFFFF;
178  y    :=$7FFFFFFF;
179  cover:=0;
180  area :=0;
181  left :=-1;
182  right:=-1;
183 
184 end;
185 
186 { STYLE }
187 procedure cell_style_aa.style(c : cell_style_aa_ptr );
188 begin
189  left :=c.left;
190  right:=c.right;
191 
192 end;
193 
194 { NOT_EQUAL }
195 function cell_style_aa.not_equal(ex ,ey : int; c : cell_style_aa_ptr ) : int;
196 begin
197  result:=(ex - x ) or (ey - y ) or (left - c.left ) or (right - c.right );
198 
199 end;
200 
201 { CONSTRUCT }
202 constructor rasterizer_cells_aa.Construct;
203 begin
204  m_num_blocks:=0;
205  m_max_blocks:=0;
206  m_curr_block:=0;
207  m_num_cells :=0;
208 
209  m_cells        :=NIL;
210  m_curr_cell_ptr:=NIL;
211 
212  m_sorted_cells.Construct(sizeof(cell_style_aa_ptr ) );
213  m_sorted_y.Construct(sizeof(sorted_y ) );
214 
215  m_min_x :=$7FFFFFFF;
216  m_min_y :=$7FFFFFFF;
217  m_max_x :=-$7FFFFFFF;
218  m_max_y :=-$7FFFFFFF;
219  m_sorted:=false;
220 
221  m_style_cell.initial;
222  m_curr_cell.initial;
223 
224 end;
225 
226 { DESTRUCT }
227 destructor rasterizer_cells_aa.Destruct;
228 var
229  ptr : cell_style_aa_ptr_ptr;
230 
231 begin
232  m_sorted_cells.Destruct;
233  m_sorted_y.Destruct;
234 
235  if m_num_blocks <> 0 then
236   begin
237    ptr:=cell_style_aa_ptr_ptr(ptrcomp(m_cells ) + (m_num_blocks - 1 ) * sizeof(cell_style_aa_ptr ) );
238 
239    while m_num_blocks <> 0 do
240     begin
241      dec(m_num_blocks );
242 
243      agg_freemem(pointer(ptr^ ) ,cell_block_size * sizeof(cell_style_aa ) );
244 
245      dec(ptrcomp(ptr ) ,sizeof(cell_style_aa_ptr ) );
246 
247     end;
248 
249    agg_freemem(pointer(m_cells ) ,m_max_blocks * sizeof(cell_style_aa_ptr ) );
250 
251   end;
252 
253 end;
254 
255 { RESET }
256 procedure rasterizer_cells_aa.reset;
257 begin
258  m_num_cells :=0;
259  m_curr_block:=0;
260 
261  m_curr_cell.initial;
262  m_style_cell.initial;
263 
264  m_sorted:=false;
265  m_min_x :=$7FFFFFFF;
266  m_min_y :=$7FFFFFFF;
267  m_max_x :=-$7FFFFFFF;
268  m_max_y :=-$7FFFFFFF;
269 
270 end;
271 
272 { STYLE }
273 procedure rasterizer_cells_aa.style(style_cell : cell_style_aa_ptr );
274 begin
275  m_style_cell.style(style_cell );
276 
277 end;
278 
279 { LINE }
280 procedure rasterizer_cells_aa.line(x1 ,y1 ,x2 ,y2 : int );
281 const
282  dx_limit = 16384 shl poly_subpixel_shift;
283 
284 var
285  dx ,cx ,cy ,dy ,ex1 ,ex2 ,ey1 ,ey2 ,fy1 ,fy2 ,ex ,two_fx ,area ,
286 
287  x_from ,x_to ,p ,rem ,mod_ ,lift ,delta ,first ,incr : int;
288 
289 begin
290  dx:=x2 - x1;
291 
292  if (dx >= dx_limit ) or
293     (dx <= -dx_limit ) then
294   begin
295    cx:=shr_int32(x1 + x2 ,1 );
296    cy:=shr_int32(y1 + y2 ,1 );
297 
298    line(x1 ,y1 ,cx ,cy );
299    line(cx ,cy ,x2 ,y2 );
300 
301   end;
302 
303  dy := y2 - y1;
304  ex1:=shr_int32(x1 ,poly_subpixel_shift );
305  ex2:=shr_int32(x2 ,poly_subpixel_shift );
306  ey1:=shr_int32(y1 ,poly_subpixel_shift );
307  ey2:=shr_int32(y2 ,poly_subpixel_shift );
308  fy1:=y1 and poly_subpixel_mask;
309  fy2:=y2 and poly_subpixel_mask;
310 
311  if ex1 < m_min_x then
312   m_min_x:=ex1;
313 
314  if ex1 > m_max_x then
315   m_max_x:=ex1;
316 
317  if ey1 < m_min_y then
318   m_min_y:=ey1;
319 
320  if ey1 > m_max_y then
321   m_max_y:=ey1;
322 
323  if ex2 < m_min_x then
324   m_min_x:=ex2;
325 
326  if ex2 > m_max_x then
327   m_max_x:=ex2;
328 
329  if ey2 < m_min_y then
330   m_min_y:=ey2;
331 
332  if ey2 > m_max_y then
333   m_max_y:=ey2;
334 
335  set_curr_cell(ex1 ,ey1 );
336 
337 // everything is on a single hline
338  if ey1 = ey2 then
339   begin
340    render_hline(ey1 ,x1 ,fy1 ,x2 ,fy2 );
341    exit;
342 
343   end;
344 
345 // Vertical line - we have to calculate start and end cells,
346 // and then - the common values of the area and coverage for
347 // all cells of the line. We know exactly there's only one
348 // cell, so, we don't have to call render_hline().
349  incr:=1;
350 
351  if dx = 0 then
352   begin
353    ex    :=shr_int32(x1 ,poly_subpixel_shift );
354    two_fx:=(x1 - (ex shl poly_subpixel_shift ) ) shl 1;
355    first :=poly_subpixel_scale;
356 
357    if dy < 0 then
358     begin
359      first:=0;
360      incr :=-1;
361 
362     end;
363 
364    x_from:=x1;
365 
366   // render_hline(ey1 ,x_from ,fy1 ,x_from ,first );
367    delta:=first - fy1;
368 
369    inc(m_curr_cell.cover ,delta );
370    inc(m_curr_cell.area ,two_fx * delta );
371    inc(ey1 ,incr );
372 
373    set_curr_cell(ex ,ey1 );
374 
375    delta:=first + first - poly_subpixel_scale;
376    area :=two_fx * delta;
377 
378    while ey1 <> ey2 do
379     begin
380     // render_hline(ey1 ,x_from ,poly_subpixel_scale - first ,x_from ,first );
381      m_curr_cell.cover:=delta;
382      m_curr_cell.area :=area;
383 
384      inc(ey1 ,incr );
385 
386      set_curr_cell(ex ,ey1 );
387 
388     end;
389 
390   // render_hline(ey1 ,x_from ,poly_subpixel_scale - first ,x_from ,fy2 );
391    delta:=fy2 - poly_subpixel_scale + first;
392 
393    inc(m_curr_cell.cover ,delta );
394    inc(m_curr_cell.area ,two_fx * delta );
395 
396    exit;
397 
398   end;
399 
400 // ok, we have to render several hlines
401  p    :=(poly_subpixel_scale - fy1 ) * dx;
402  first:=poly_subpixel_scale;
403 
404  if dy < 0 then
405   begin
406    p    :=fy1 * dx;
407    first:=0;
408    incr :=-1;
409    dy   :=-dy;
410 
411   end;
412 
413  delta:=p div dy;
414  mod_ :=p mod dy;
415 
416  if mod_ < 0 then
417   begin
418    dec(delta );
419    inc(mod_,dy );
420 
421   end;
422 
423  x_from:=x1 + delta;
424 
425  render_hline(ey1 ,x1 ,fy1 ,x_from ,first );
426 
427  inc(ey1 ,incr );
428 
429  set_curr_cell(shr_int32(x_from ,poly_subpixel_shift ) ,ey1 );
430 
431  if ey1 <> ey2 then
432   begin
433    p   :=poly_subpixel_scale * dx;
434    lift:=p div dy;
435    rem :=p mod dy;
436 
437    if rem < 0 then
438     begin
439      dec(lift );
440      inc(rem ,dy );
441 
442     end;
443 
444    dec(mod_ ,dy );
445 
446    while ey1 <> ey2 do
447     begin
448      delta:=lift;
449 
450      inc(mod_ ,rem );
451 
452      if mod_ >= 0 then
453       begin
454        dec(mod_ ,dy );
455        inc(delta );
456 
457       end;
458 
459      x_to:=x_from + delta;
460 
461      render_hline(ey1 ,x_from ,poly_subpixel_scale - first ,x_to ,first );
462 
463      x_from:=x_to;
464 
465      inc(ey1 ,incr );
466 
467      set_curr_cell(shr_int32(x_from ,poly_subpixel_shift ) ,ey1 );
468 
469     end;
470 
471   end;
472 
473  render_hline(ey1 ,x_from ,poly_subpixel_scale - first ,x2 ,fy2 );
474 
475 end;
476 
477 { MIN_X }
478 function rasterizer_cells_aa.min_x : int;
479 begin
480  result:=m_min_x;
481 
482 end;
483 
484 { MIN_Y }
485 function rasterizer_cells_aa.min_y : int;
486 begin
487  result:=m_min_y;
488 
489 end;
490 
491 { MAX_X }
492 function rasterizer_cells_aa.max_x : int;
493 begin
494  result:=m_max_x;
495 
496 end;
497 
498 { MAX_Y }
499 function rasterizer_cells_aa.max_y : int;
500 begin
501  result:=m_max_y;
502 
503 end;
504 
505 { swap_cells }
506 procedure swap_cells(a ,b : pointer );
507 var
508  temp : pointer;
509 
510 begin
511  temp        :=pointer(a^ );
512  pointer(a^ ):=pointer(b^ );
513  pointer(b^ ):=temp;
514 
515 end;
516 
517 const
518  qsort_threshold = 9;
519 
520 { qsort_cells }
521 procedure qsort_cells(start : cell_style_aa_ptr_ptr; num : unsigned );
522 var
523  stack : array[0..79 ] of cell_style_aa_ptr_ptr;
524  top   : cell_style_aa_ptr_ptr_ptr;
525  limit ,
526  base  : cell_style_aa_ptr_ptr;
527 
528  len ,x : int;
529 
530  i ,j ,pivot : cell_style_aa_ptr_ptr;
531 
532 begin
533  limit:=cell_style_aa_ptr_ptr(ptrcomp(start ) + num * sizeof(cell_style_aa_ptr ) );
534  base :=start;
535  top  :=@stack[0 ];
536 
537  repeat
538   len:=(ptrcomp(limit ) - ptrcomp(base ) ) div sizeof(cell_style_aa_ptr );
539 
540   if len > qsort_threshold then
541    begin
542    // we use base + len/2 as the pivot
543     pivot:=cell_style_aa_ptr_ptr(ptrcomp(base ) + (len div 2 ) * sizeof(cell_style_aa_ptr ) );
544 
545     swap_cells(base ,pivot );
546 
547     i:=cell_style_aa_ptr_ptr(ptrcomp(base ) + sizeof(cell_style_aa_ptr ) );
548     j:=cell_style_aa_ptr_ptr(ptrcomp(limit ) - sizeof(cell_style_aa_ptr ) );
549 
550    // now ensure that *i <= *base <= *j
551     if j^^.x < i^^.x then
552      swap_cells(i ,j );
553 
554     if base^^.x < i^^.x then
555      swap_cells(base ,i );
556 
557     if j^^.x < base^^.x then
558      swap_cells(base ,j );
559 
560     repeat
561      x:=base^^.x;
562 
563      repeat
564       inc(ptrcomp(i ) ,sizeof(cell_style_aa_ptr ) );
565 
566      until i^^.x >= x;
567 
568      repeat
569       dec(ptrcomp(j ) ,sizeof(cell_style_aa_ptr ) );
570 
571      until x >= j^^.x;
572 
573      if ptrcomp(i ) > ptrcomp(j ) then
574       break;
575 
576      swap_cells(i ,j );
577 
578     until false;
579 
580     swap_cells(base ,j );
581 
582    // now, push the largest sub-array
583     if ptrcomp(j ) - ptrcomp(base ) > ptrcomp(limit ) - ptrcomp(i ) then
584      begin
585       top^:=base;
586 
587       cell_style_aa_ptr_ptr_ptr(ptrcomp(top ) + sizeof(cell_style_aa_ptr_ptr ) )^:=j;
588 
589       base:=i;
590 
591      end
592     else
593      begin
594       top^:=i;
595 
596       cell_style_aa_ptr_ptr_ptr(ptrcomp(top ) + sizeof(cell_style_aa_ptr_ptr ) )^:=limit;
597 
598       limit:=j;
599 
600      end;
601 
602     inc(ptrcomp(top ) ,2 * sizeof(cell_style_aa_ptr_ptr ) );
603 
604    end
605   else
606    begin
607    // the sub-array is small, perform insertion sort
608     j:=base;
609     i:=cell_style_aa_ptr_ptr(ptrcomp(j ) + sizeof(cell_style_aa_ptr ) );
610 
611     while ptrcomp(i ) < ptrcomp(limit ) do
612      begin
613       while cell_style_aa_ptr_ptr(ptrcomp(j ) + sizeof(cell_style_aa_ptr ) )^^.x < j^^.x do
614        begin
615         swap_cells(cell_style_aa_ptr_ptr(ptrcomp(j ) + sizeof(cell_style_aa_ptr ) ) ,j );
616 
617         if ptrcomp(j ) = ptrcomp(base ) then
618          break;
619 
620         dec(ptrcomp(j ) ,sizeof(cell_style_aa_ptr ) );
621 
622        end;
623 
624       j:=i;
625 
626       inc(ptrcomp(i ) ,sizeof(cell_style_aa_ptr ) );
627 
628      end;
629 
630     if ptrcomp(top ) > ptrcomp(@stack[0 ] ) then
631      begin
632       dec(ptrcomp(top ) ,2 * sizeof(cell_style_aa_ptr_ptr ) );
633 
634       base :=top^;
635       limit:=cell_style_aa_ptr_ptr_ptr(ptrcomp(top ) + sizeof(cell_style_aa_ptr_ptr ) )^;
636 
637      end
638     else
639      break;
640 
641    end;
642 
643  until false;
644 
645 end;
646 
647 { SORT_CELLS }
648 procedure rasterizer_cells_aa.sort_cells;
649 var
650  block_ptr : cell_style_aa_ptr_ptr;
651  cell_ptr  : cell_style_aa_ptr;
652 
653  nb ,i ,start ,v : unsigned;
654 
655  curr_y : sorted_y_ptr;
656 
657 begin
658 //Perform sort only the first time.
659  if m_sorted then
660   exit;
661 
662  add_curr_cell;
663 
664  m_curr_cell.x    :=$7FFFFFFF;
665  m_curr_cell.y    :=$7FFFFFFF;
666  m_curr_cell.cover:=0;
667  m_curr_cell.area :=0;
668 
669  if m_num_cells = 0 then
670   exit;
671 
672 // Allocate the array of cell pointers
673  m_sorted_cells.allocate(m_num_cells ,16 );
674 
675 // Allocate and zero the Y array
676  m_sorted_y.allocate(m_max_y - m_min_y + 1 ,16 );
677  m_sorted_y.zero;
678 
679 // Create the Y-histogram (count the numbers of cells for each Y)
680  block_ptr:=m_cells;
681 
682  nb:=m_num_cells shr cell_block_shift;
683 
684  while nb <> 0 do
685   begin
686    dec(nb );
687 
688    cell_ptr:=block_ptr^;
689 
690    inc(ptrcomp(block_ptr ) ,sizeof(cell_style_aa_ptr ) );
691 
692    i:=cell_block_size;
693 
694    while i <> 0 do
695     begin
696      dec(i );
697      inc(sorted_y_ptr(m_sorted_y.array_operator(cell_ptr.y - m_min_y ) ).start );
698      inc(ptrcomp(cell_ptr ) ,sizeof(cell_style_aa ) );
699 
700     end;
701 
702   end;
703 
704  cell_ptr:=block_ptr^;
705 
706  inc(ptrcomp(block_ptr ) ,sizeof(cell_style_aa_ptr ) );
707 
708  i:=m_num_cells and cell_block_mask;
709 
710  while i <> 0 do
711   begin
712    dec(i );
713    inc(sorted_y_ptr(m_sorted_y.array_operator(cell_ptr.y - m_min_y ) ).start );
714    inc(ptrcomp(cell_ptr ) ,sizeof(cell_style_aa ) );
715 
716   end;
717 
718 // Convert the Y-histogram into the array of starting indexes
719  start:=0;
720  i    :=0;
721 
722  while i < m_sorted_y.size do
723   begin
724    v:=sorted_y_ptr(m_sorted_y.array_operator(i ) ).start;
725 
726    sorted_y_ptr(m_sorted_y.array_operator(i ) ).start:=start;
727 
728    inc(start ,v );
729    inc(i );
730 
731   end;
732 
733 // Fill the cell pointer array sorted by Y
734  block_ptr:=m_cells;
735 
736  nb:=m_num_cells shr cell_block_shift;
737 
738  while nb <> 0 do
739   begin
740    dec(nb );
741 
742    cell_ptr:=block_ptr^;
743 
744    inc(ptrcomp(block_ptr ) ,sizeof(cell_style_aa_ptr ) );
745 
746    i:=cell_block_size;
747 
748    while i <> 0 do
749     begin
750      dec(i );
751 
752      curr_y:=sorted_y_ptr(m_sorted_y.array_operator(cell_ptr.y - m_min_y ) );
753 
754      cell_style_aa_ptr_ptr(m_sorted_cells.array_operator(curr_y.start + curr_y.num ) )^:=cell_ptr;
755 
756      inc(curr_y.num );
757      inc(ptrcomp(cell_ptr ) ,sizeof(cell_style_aa ) );
758 
759     end;
760 
761   end;
762 
763  cell_ptr:=block_ptr^;
764 
765  inc(ptrcomp(block_ptr ) ,sizeof(cell_style_aa_ptr ) );
766 
767  i:=m_num_cells and cell_block_mask;
768 
769  while i <> 0 do
770   begin
771    dec(i );
772 
773    curr_y:=sorted_y_ptr(m_sorted_y.array_operator(cell_ptr.y - m_min_y ) );
774 
775    cell_style_aa_ptr_ptr(m_sorted_cells.array_operator(curr_y.start + curr_y.num ) )^:=cell_ptr;
776 
777    inc(curr_y.num );
778    inc(ptrcomp(cell_ptr ) ,sizeof(cell_style_aa ) );
779 
780   end;
781 
782 // Finally arrange the X-arrays
783  i:=0;
784 
785  while i < m_sorted_y.size do
786   begin
787    curr_y:=sorted_y_ptr(m_sorted_y.array_operator(i ) );
788 
789    if curr_y.num <> 0 then
790     qsort_cells(
791      cell_style_aa_ptr_ptr(ptrcomp(m_sorted_cells.data ) + curr_y.start * sizeof(cell_style_aa_ptr ) ) ,
792      curr_y.num );
793 
794    inc(i );
795 
796   end;
797 
798  m_sorted:=true;
799 
800 end;
801 
802 { TOTAL_CELLS }
803 function rasterizer_cells_aa.total_cells : unsigned;
804 begin
805  result:=m_num_cells;
806 
807 end;
808 
809 { SCANLINE_NUM_CELLS }
810 function rasterizer_cells_aa.scanline_num_cells(y : unsigned ) : unsigned;
811 begin
812  result:=sorted_y_ptr(m_sorted_y.array_operator(y - m_min_y ) ).num;
813 
814 end;
815 
816 { SCANLINE_CELLS }
817 function rasterizer_cells_aa.scanline_cells(y : unsigned ) : cell_style_aa_ptr_ptr;
818 begin
819  result:=cell_style_aa_ptr_ptr(ptrcomp(m_sorted_cells.data ) + sorted_y_ptr(m_sorted_y.array_operator(y - m_min_y ) ).start * sizeof(cell_style_aa_ptr ) );
820 
821 end;
822 
823 { SORTED }
824 function rasterizer_cells_aa.sorted : boolean;
825 begin
826  result:=m_sorted;
827 
828 end;
829 
830 { SET_CURR_CELL }
831 procedure rasterizer_cells_aa.set_curr_cell(x ,y : int );
832 begin
833  if m_curr_cell.not_equal(x ,y ,@m_style_cell ) <> 0 then
834   begin
835    add_curr_cell;
836 
837    m_curr_cell.style(@m_style_cell );
838 
839    m_curr_cell.x    :=x;
840    m_curr_cell.y    :=y;
841    m_curr_cell.cover:=0;
842    m_curr_cell.area :=0;
843 
844   end;
845 
846 end;
847 
848 { ADD_CURR_CELL }
849 procedure rasterizer_cells_aa.add_curr_cell;
850 begin
851  if m_curr_cell.area or m_curr_cell.cover <> 0 then
852   begin
853    if m_num_cells and cell_block_mask = 0 then
854     begin
855      if m_num_blocks >= cell_block_limit then
856       exit;
857 
858      allocate_block;
859 
860     end;
861 
862    m_curr_cell_ptr^:=m_curr_cell;
863 
864    inc(ptrcomp(m_curr_cell_ptr ) ,sizeof(cell_style_aa ) );
865    inc(m_num_cells );
866 
867   end;
868 
869 end;
870 
871 { RENDER_HLINE }
872 procedure rasterizer_cells_aa.render_hline(ey ,x1 ,y1 ,x2 ,y2 : int );
873 var
874  ex1 ,ex2 ,fx1 ,fx2 ,delta ,p ,first ,dx ,incr ,lift ,mod_ ,rem : int;
875 
876 begin
877  ex1:=shr_int32(x1 ,poly_subpixel_shift );
878  ex2:=shr_int32(x2 ,poly_subpixel_shift );
879  fx1:=x1 and poly_subpixel_mask;
880  fx2:=x2 and poly_subpixel_mask;
881 
882 // trivial case. Happens often
883  if y1 = y2 then
884   begin
885    set_curr_cell(ex2 ,ey );
886    exit;
887 
888   end;
889 
890 // everything is located in a single cell.  That is easy!
891  if ex1 = ex2 then
892   begin
893    delta:=y2 - y1;
894 
895    inc(m_curr_cell.cover ,delta );
896    inc(m_curr_cell.area ,(fx1 + fx2 ) * delta );
897 
898    exit;
899 
900   end;
901 
902 // ok, we'll have to render a run of adjacent cells on the same
903 // hline...
904  p    :=(poly_subpixel_scale - fx1 ) * (y2 - y1 );
905  first:=poly_subpixel_scale;
906  incr :=1;
907 
908  dx:=x2 - x1;
909 
910  if dx < 0 then
911   begin
912    p    :=fx1 * (y2 - y1 );
913    first:=0;
914    incr :=-1;
915    dx   :=-dx;
916 
917   end;
918 
919  delta:=p div dx;
920  mod_ :=p mod dx;
921 
922  if mod_ < 0 then
923   begin
924    dec(delta );
925    inc(mod_ ,dx );
926 
927   end;
928 
929  inc(m_curr_cell.cover ,delta );
930  inc(m_curr_cell.area ,(fx1 + first ) * delta );
931  inc(ex1 ,incr );
932 
933  set_curr_cell(ex1 ,ey );
934 
935  inc(y1 ,delta );
936 
937  if ex1 <> ex2 then
938   begin
939    p   :=poly_subpixel_scale * (y2 - y1 + delta );
940    lift:=p div dx;
941    rem :=p mod dx;
942 
943    if rem < 0 then
944     begin
945      dec(lift );
946      inc(rem ,dx );
947 
948     end;
949 
950    dec(mod_ ,dx );
951 
952    while ex1 <> ex2 do
953     begin
954      delta:=lift;
955 
956      inc(mod_ ,rem );
957 
958      if mod_ >= 0 then
959       begin
960        dec(mod_ ,dx );
961        inc(delta );
962 
963       end;
964 
965      inc(m_curr_cell.cover ,delta );
966      inc(m_curr_cell.area ,poly_subpixel_scale * delta );
967 
968      inc(y1 ,delta );
969      inc(ex1 ,incr );
970 
971      set_curr_cell(ex1 ,ey );
972 
973     end;
974 
975   end;
976 
977  delta:=y2 - y1;
978 
979  inc(m_curr_cell.cover ,delta );
980  inc(m_curr_cell.area ,(fx2 + poly_subpixel_scale - first ) * delta );
981 
982 end;
983 
984 { ALLOCATE_BLOCK }
985 procedure rasterizer_cells_aa.allocate_block;
986 var
987  new_cells : cell_style_aa_ptr_ptr;
988 
989 begin
990  if m_curr_block >= m_num_blocks then
991   begin
992    if m_num_blocks >= m_max_blocks then
993     begin
994      agg_getmem(pointer(new_cells ) ,(m_max_blocks + cell_block_pool ) * sizeof(cell_style_aa_ptr ) );
995 
996      if m_cells <> NIL then
997       begin
998        move(m_cells^ ,new_cells^ ,m_max_blocks * sizeof(cell_style_aa_ptr ) );
999 
1000        agg_freemem(pointer(m_cells ) ,m_max_blocks * sizeof(cell_style_aa_ptr ) );
1001 
1002       end;
1003 
1004      m_cells:=new_cells;
1005 
1006      inc(m_max_blocks ,cell_block_pool );
1007 
1008     end;
1009 
1010    agg_getmem(
1011     pointer(cell_style_aa_ptr_ptr(ptrcomp(m_cells ) + m_num_blocks * sizeof(cell_style_aa_ptr ) )^ ) ,
1012     cell_block_size * sizeof(cell_style_aa ) );
1013 
1014    inc(m_num_blocks );
1015 
1016   end;
1017 
1018  m_curr_cell_ptr:=cell_style_aa_ptr_ptr(ptrcomp(m_cells ) + m_curr_block * sizeof(cell_style_aa_ptr ) )^;
1019 
1020  inc(m_curr_block );
1021 
1022 end;
1023 
1024 { CONSTRUCT }
1025 constructor scanline_hit_test.Construct;
1026 begin
1027  m_x  :=x;
1028  m_hit:=false;
1029 
1030 end;
1031 
1032 { RESET_SPANS }
1033 procedure scanline_hit_test.reset_spans;
1034 begin
1035 end;
1036 
1037 { FINALIZE }
1038 procedure scanline_hit_test.finalize;
1039 begin
1040 end;
1041 
1042 { ADD_CELL }
1043 procedure scanline_hit_test.add_cell;
1044 begin
1045  if m_x = x then
1046   m_hit:=true;
1047 
1048 end;
1049 
1050 { ADD_SPAN }
1051 procedure scanline_hit_test.add_span;
1052 begin
1053  if (m_x >= x ) and
1054     (m_x < x + len ) then
1055   m_hit:=true;
1056 
1057 end;
1058 
1059 { NUM_SPANS }
scanline_hit_test.num_spansnull1060 function scanline_hit_test.num_spans;
1061 begin
1062  result:=1;
1063 
1064 end;
1065 
1066 { HIT }
scanline_hit_test.hitnull1067 function scanline_hit_test.hit;
1068 begin
1069  result:=m_hit;
1070 
1071 end;
1072 
1073 END.
1074 
1075