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