xref: /haiku/headers/libs/agg/agg_rasterizer_outline_aa.h (revision e39da397f5ff79f2db9f9a3ddf1852b6710578af)
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 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 #ifndef AGG_RASTERIZER_OUTLINE_AA_INCLUDED
16 #define AGG_RASTERIZER_OUTLINE_AA_INCLUDED
17 
18 #include "agg_basics.h"
19 #include "agg_line_aa_basics.h"
20 #include "agg_vertex_sequence.h"
21 
22 namespace agg
23 {
24 
25     //-------------------------------------------------------------------------
cmp_dist_start(int d)26     inline bool cmp_dist_start(int d) { return d > 0;  }
cmp_dist_end(int d)27     inline bool cmp_dist_end(int d)   { return d <= 0; }
28 
29 
30 
31     //-----------------------------------------------------------line_aa_vertex
32     // Vertex (x, y) with the distance to the next one. The last vertex has
33     // the distance between the last and the first points
34     struct line_aa_vertex
35     {
36         int x;
37         int y;
38         int len;
39 
line_aa_vertexline_aa_vertex40         line_aa_vertex() {}
line_aa_vertexline_aa_vertex41         line_aa_vertex(int x_, int y_) :
42             x(x_),
43             y(y_),
44             len(0)
45         {
46         }
47 
operatorline_aa_vertex48         bool operator () (const line_aa_vertex& val)
49         {
50             double dx = val.x - x;
51             double dy = val.y - y;
52             return (len = uround(sqrt(dx * dx + dy * dy))) >
53                    (line_subpixel_scale + line_subpixel_scale / 2);
54         }
55     };
56 
57 
58     //----------------------------------------------------------outline_aa_join_e
59     enum outline_aa_join_e
60     {
61         outline_no_join,             //-----outline_no_join
62         outline_miter_join,          //-----outline_miter_join
63         outline_round_join,          //-----outline_round_join
64         outline_miter_accurate_join  //-----outline_accurate_join
65     };
66 
67     //=======================================================rasterizer_outline_aa
68     template<class Renderer, class Coord=line_coord> class rasterizer_outline_aa
69     {
70     private:
71         //------------------------------------------------------------------------
72         struct draw_vars
73         {
74             unsigned idx;
75             int x1, y1, x2, y2;
76             line_parameters curr, next;
77             int lcurr, lnext;
78             int xb1, yb1, xb2, yb2;
79             unsigned flags;
80         };
81 
82         void draw(draw_vars& dv, unsigned start, unsigned end);
83 
84     public:
85         typedef line_aa_vertex                  vertex_type;
86         typedef vertex_sequence<vertex_type, 6> vertex_storage_type;
87 
rasterizer_outline_aa(Renderer & ren)88         rasterizer_outline_aa(Renderer& ren) :
89             m_ren(&ren),
90             m_line_join(ren.accurate_join_only() ?
91                             outline_miter_accurate_join :
92                             outline_round_join),
93             m_round_cap(false),
94             m_start_x(0),
95             m_start_y(0)
96         {}
attach(Renderer & ren)97         void attach(Renderer& ren) { m_ren = &ren; }
98 
99         //------------------------------------------------------------------------
line_join(outline_aa_join_e join)100         void line_join(outline_aa_join_e join)
101         {
102             m_line_join = m_ren->accurate_join_only() ?
103                 outline_miter_accurate_join :
104                 join;
105         }
line_join()106         bool line_join() const { return m_line_join; }
107 
108         //------------------------------------------------------------------------
round_cap(bool v)109         void round_cap(bool v) { m_round_cap = v; }
round_cap()110         bool round_cap() const { return m_round_cap; }
111 
112         //------------------------------------------------------------------------
move_to(int x,int y)113         void move_to(int x, int y)
114         {
115             m_src_vertices.modify_last(vertex_type(m_start_x = x, m_start_y = y));
116         }
117 
118         //------------------------------------------------------------------------
line_to(int x,int y)119         void line_to(int x, int y)
120         {
121             m_src_vertices.add(vertex_type(x, y));
122         }
123 
124         //------------------------------------------------------------------------
move_to_d(double x,double y)125         void move_to_d(double x, double y)
126         {
127             move_to(Coord::conv(x), Coord::conv(y));
128         }
129 
130         //------------------------------------------------------------------------
line_to_d(double x,double y)131         void line_to_d(double x, double y)
132         {
133             line_to(Coord::conv(x), Coord::conv(y));
134         }
135 
136         //------------------------------------------------------------------------
137         void render(bool close_polygon);
138 
139         //------------------------------------------------------------------------
add_vertex(double x,double y,unsigned cmd)140         void add_vertex(double x, double y, unsigned cmd)
141         {
142             if(is_move_to(cmd))
143             {
144                 render(false);
145                 move_to_d(x, y);
146             }
147             else
148             {
149                 if(is_end_poly(cmd))
150                 {
151                     render(is_closed(cmd));
152                     if(is_closed(cmd))
153                     {
154                         move_to(m_start_x, m_start_y);
155                     }
156                 }
157                 else
158                 {
159                     line_to_d(x, y);
160                 }
161             }
162         }
163 
164         //------------------------------------------------------------------------
165         template<class VertexSource>
166         void add_path(VertexSource& vs, unsigned path_id=0)
167         {
168             double x;
169             double y;
170 
171             unsigned cmd;
172             vs.rewind(path_id);
173             while(!is_stop(cmd = vs.vertex(&x, &y)))
174             {
175                 add_vertex(x, y, cmd);
176             }
177             render(false);
178         }
179 
180 
181         //------------------------------------------------------------------------
182         template<class VertexSource, class ColorStorage, class PathId>
render_all_paths(VertexSource & vs,const ColorStorage & colors,const PathId & path_id,unsigned num_paths)183         void render_all_paths(VertexSource& vs,
184                               const ColorStorage& colors,
185                               const PathId& path_id,
186                               unsigned num_paths)
187         {
188             for(unsigned i = 0; i < num_paths; i++)
189             {
190                 m_ren->color(colors[i]);
191                 add_path(vs, path_id[i]);
192             }
193         }
194 
195 
196         //------------------------------------------------------------------------
render_ctrl(Ctrl & c)197         template<class Ctrl> void render_ctrl(Ctrl& c)
198         {
199             unsigned i;
200             for(i = 0; i < c.num_paths(); i++)
201             {
202                 m_ren->color(c.color(i));
203                 add_path(c, i);
204             }
205         }
206 
207     private:
208         rasterizer_outline_aa(const rasterizer_outline_aa<Renderer, Coord>&);
209         const rasterizer_outline_aa<Renderer, Coord>& operator =
210             (const rasterizer_outline_aa<Renderer, Coord>&);
211 
212         Renderer*           m_ren;
213         vertex_storage_type m_src_vertices;
214         outline_aa_join_e   m_line_join;
215         bool                m_round_cap;
216         int                 m_start_x;
217         int                 m_start_y;
218     };
219 
220 
221 
222 
223 
224 
225 
226 
227     //----------------------------------------------------------------------------
228     template<class Renderer, class Coord>
draw(draw_vars & dv,unsigned start,unsigned end)229     void rasterizer_outline_aa<Renderer, Coord>::draw(draw_vars& dv,
230                                                       unsigned start,
231                                                       unsigned end)
232     {
233         unsigned i;
234         const vertex_storage_type::value_type* v;
235 
236         for(i = start; i < end; i++)
237         {
238             if(m_line_join == outline_round_join)
239             {
240                 dv.xb1 = dv.curr.x1 + (dv.curr.y2 - dv.curr.y1);
241                 dv.yb1 = dv.curr.y1 - (dv.curr.x2 - dv.curr.x1);
242                 dv.xb2 = dv.curr.x2 + (dv.curr.y2 - dv.curr.y1);
243                 dv.yb2 = dv.curr.y2 - (dv.curr.x2 - dv.curr.x1);
244             }
245 
246             switch(dv.flags)
247             {
248             case 0: m_ren->line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break;
249             case 1: m_ren->line2(dv.curr, dv.xb2, dv.yb2); break;
250             case 2: m_ren->line1(dv.curr, dv.xb1, dv.yb1); break;
251             case 3: m_ren->line0(dv.curr); break;
252             }
253 
254             if(m_line_join == outline_round_join && (dv.flags & 2) == 0)
255             {
256                 m_ren->pie(dv.curr.x2, dv.curr.y2,
257                            dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
258                            dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
259                            dv.curr.x2 + (dv.next.y2 - dv.next.y1),
260                            dv.curr.y2 - (dv.next.x2 - dv.next.x1));
261             }
262 
263             dv.x1 = dv.x2;
264             dv.y1 = dv.y2;
265             dv.lcurr = dv.lnext;
266             dv.lnext = m_src_vertices[dv.idx].len;
267 
268             ++dv.idx;
269             if(dv.idx >= m_src_vertices.size()) dv.idx = 0;
270 
271             v = &m_src_vertices[dv.idx];
272             dv.x2 = v->x;
273             dv.y2 = v->y;
274 
275             dv.curr = dv.next;
276             dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
277             dv.xb1 = dv.xb2;
278             dv.yb1 = dv.yb2;
279 
280             switch(m_line_join)
281             {
282             case outline_no_join:
283                 dv.flags = 3;
284                 break;
285 
286             case outline_miter_join:
287                 dv.flags >>= 1;
288                 dv.flags |= ((dv.curr.diagonal_quadrant() ==
289                               dv.next.diagonal_quadrant()) << 1);
290                 if((dv.flags & 2) == 0)
291                 {
292                     bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
293                 }
294                 break;
295 
296             case outline_round_join:
297                 dv.flags >>= 1;
298                 dv.flags |= ((dv.curr.diagonal_quadrant() ==
299                               dv.next.diagonal_quadrant()) << 1);
300                 break;
301 
302             case outline_miter_accurate_join:
303                 dv.flags = 0;
304                 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
305                 break;
306             }
307         }
308     }
309 
310 
311 
312 
313     //----------------------------------------------------------------------------
314     template<class Renderer, class Coord>
render(bool close_polygon)315     void rasterizer_outline_aa<Renderer, Coord>::render(bool close_polygon)
316     {
317         m_src_vertices.close(close_polygon);
318         draw_vars dv;
319         const vertex_storage_type::value_type* v;
320         int x1;
321         int y1;
322         int x2;
323         int y2;
324         int lprev;
325 
326         if(close_polygon)
327         {
328             if(m_src_vertices.size() >= 3)
329             {
330                 dv.idx = 2;
331 
332                 v     = &m_src_vertices[m_src_vertices.size() - 1];
333                 x1    = v->x;
334                 y1    = v->y;
335                 lprev = v->len;
336 
337                 v  = &m_src_vertices[0];
338                 x2 = v->x;
339                 y2 = v->y;
340                 dv.lcurr = v->len;
341                 line_parameters prev(x1, y1, x2, y2, lprev);
342 
343                 v = &m_src_vertices[1];
344                 dv.x1    = v->x;
345                 dv.y1    = v->y;
346                 dv.lnext = v->len;
347                 dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
348 
349                 v = &m_src_vertices[dv.idx];
350                 dv.x2 = v->x;
351                 dv.y2 = v->y;
352                 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
353 
354                 dv.xb1 = 0;
355                 dv.yb1 = 0;
356                 dv.xb2 = 0;
357                 dv.yb2 = 0;
358 
359                 switch(m_line_join)
360                 {
361                 case outline_no_join:
362                     dv.flags = 3;
363                     break;
364 
365                 case outline_miter_join:
366                 case outline_round_join:
367                     dv.flags =
368                             (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
369                         ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
370                     break;
371 
372                 case outline_miter_accurate_join:
373                     dv.flags = 0;
374                     break;
375                 }
376 
377                 if((dv.flags & 1) == 0 && m_line_join != outline_round_join)
378                 {
379                     bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
380                 }
381 
382                 if((dv.flags & 2) == 0 && m_line_join != outline_round_join)
383                 {
384                     bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
385                 }
386                 draw(dv, 0, m_src_vertices.size());
387             }
388         }
389         else
390         {
391             switch(m_src_vertices.size())
392             {
393                 case 0:
394                 case 1:
395                     break;
396 
397                 case 2:
398                 {
399                     v     = &m_src_vertices[0];
400                     x1    = v->x;
401                     y1    = v->y;
402                     lprev = v->len;
403                     v     = &m_src_vertices[1];
404                     x2    = v->x;
405                     y2    = v->y;
406                     line_parameters lp(x1, y1, x2, y2, lprev);
407                     if(m_round_cap)
408                     {
409                         m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
410                     }
411                     m_ren->line3(lp,
412                                  x1 + (y2 - y1),
413                                  y1 - (x2 - x1),
414                                  x2 + (y2 - y1),
415                                  y2 - (x2 - x1));
416                     if(m_round_cap)
417                     {
418                         m_ren->semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1));
419                     }
420                 }
421                 break;
422 
423                 case 3:
424                 {
425                     int x3, y3;
426                     int lnext;
427                     v     = &m_src_vertices[0];
428                     x1    = v->x;
429                     y1    = v->y;
430                     lprev = v->len;
431                     v     = &m_src_vertices[1];
432                     x2    = v->x;
433                     y2    = v->y;
434                     lnext = v->len;
435                     v     = &m_src_vertices[2];
436                     x3    = v->x;
437                     y3    = v->y;
438                     line_parameters lp1(x1, y1, x2, y2, lprev);
439                     line_parameters lp2(x2, y2, x3, y3, lnext);
440 
441                     if(m_round_cap)
442                     {
443                         m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
444                     }
445 
446                     if(m_line_join == outline_round_join)
447                     {
448                         m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1),
449                                           x2 + (y2 - y1), y2 - (x2 - x1));
450 
451                         m_ren->pie(x2, y2, x2 + (y2 - y1), y2 - (x2 - x1),
452                                            x2 + (y3 - y2), y2 - (x3 - x2));
453 
454                         m_ren->line3(lp2, x2 + (y3 - y2), y2 - (x3 - x2),
455                                           x3 + (y3 - y2), y3 - (x3 - x2));
456                     }
457                     else
458                     {
459                         bisectrix(lp1, lp2, &dv.xb1, &dv.yb1);
460                         m_ren->line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1),
461                                           dv.xb1,         dv.yb1);
462 
463                         m_ren->line3(lp2, dv.xb1,         dv.yb1,
464                                           x3 + (y3 - y2), y3 - (x3 - x2));
465                     }
466                     if(m_round_cap)
467                     {
468                         m_ren->semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2));
469                     }
470                 }
471                 break;
472 
473                 default:
474                 {
475                     dv.idx = 3;
476 
477                     v     = &m_src_vertices[0];
478                     x1    = v->x;
479                     y1    = v->y;
480                     lprev = v->len;
481 
482                     v  = &m_src_vertices[1];
483                     x2 = v->x;
484                     y2 = v->y;
485                     dv.lcurr = v->len;
486                     line_parameters prev(x1, y1, x2, y2, lprev);
487 
488                     v = &m_src_vertices[2];
489                     dv.x1    = v->x;
490                     dv.y1    = v->y;
491                     dv.lnext = v->len;
492                     dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
493 
494                     v = &m_src_vertices[dv.idx];
495                     dv.x2 = v->x;
496                     dv.y2 = v->y;
497                     dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
498 
499                     dv.xb1 = 0;
500                     dv.yb1 = 0;
501                     dv.xb2 = 0;
502                     dv.yb2 = 0;
503 
504                     switch(m_line_join)
505                     {
506                     case outline_no_join:
507                         dv.flags = 3;
508                         break;
509 
510                     case outline_miter_join:
511                     case outline_round_join:
512                         dv.flags =
513                                 (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
514                             ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
515                         break;
516 
517                     case outline_miter_accurate_join:
518                         dv.flags = 0;
519                         break;
520                     }
521 
522                     if(m_round_cap)
523                     {
524                         m_ren->semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
525                     }
526                     if((dv.flags & 1) == 0)
527                     {
528                         if(m_line_join == outline_round_join)
529                         {
530                             m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1),
531                                                x2 + (y2 - y1), y2 - (x2 - x1));
532                             m_ren->pie(prev.x2, prev.y2,
533                                        x2 + (y2 - y1), y2 - (x2 - x1),
534                                        dv.curr.x1 + (dv.curr.y2 - dv.curr.y1),
535                                        dv.curr.y1 - (dv.curr.x2 - dv.curr.x1));
536                         }
537                         else
538                         {
539                             bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
540                             m_ren->line3(prev, x1 + (y2 - y1), y1 - (x2 - x1),
541                                                dv.xb1,         dv.yb1);
542                         }
543                     }
544                     else
545                     {
546                         m_ren->line1(prev,
547                                      x1 + (y2 - y1),
548                                      y1 - (x2 - x1));
549                     }
550                     if((dv.flags & 2) == 0 && m_line_join != outline_round_join)
551                     {
552                         bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
553                     }
554 
555                     draw(dv, 1, m_src_vertices.size() - 2);
556 
557                     if((dv.flags & 1) == 0)
558                     {
559                         if(m_line_join == outline_round_join)
560                         {
561                             m_ren->line3(dv.curr,
562                                          dv.curr.x1 + (dv.curr.y2 - dv.curr.y1),
563                                          dv.curr.y1 - (dv.curr.x2 - dv.curr.x1),
564                                          dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
565                                          dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
566                         }
567                         else
568                         {
569                             m_ren->line3(dv.curr, dv.xb1, dv.yb1,
570                                          dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
571                                          dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
572                         }
573                     }
574                     else
575                     {
576                         m_ren->line2(dv.curr,
577                                      dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
578                                      dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
579                     }
580                     if(m_round_cap)
581                     {
582                         m_ren->semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2,
583                                        dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
584                                        dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
585                     }
586 
587                 }
588                 break;
589             }
590         }
591         m_src_vertices.remove_all();
592     }
593 
594 
595 }
596 
597 
598 #endif
599 
600