xref: /haiku/headers/libs/agg/agg_rasterizer_outline_aa.h (revision 95bac3fda53a4cb21880712d7b43f8c21db32a2e)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.2
3 // Copyright (C) 2002-2004 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     //-------------------------------------------------------------------------
26     inline bool cmp_dist_start(int d) { return d > 0;  }
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 
40         line_aa_vertex() {}
41         line_aa_vertex(int x_, int y_) :
42             x(x_),
43             y(y_),
44             len(0)
45         {
46         }
47 
48         bool operator () (const line_aa_vertex& val)
49         {
50             double dx = val.x - x;
51             double dy = val.y - y;
52             return (len = int(sqrt(dx * dx + dy * dy))) >
53                    (line_subpixel_size + line_subpixel_size / 2);
54         }
55     };
56 
57 
58 
59 
60     //=======================================================rasterizer_outline_aa
61     template<class Renderer> class rasterizer_outline_aa
62     {
63     private:
64         //------------------------------------------------------------------------
65         struct draw_vars
66         {
67             unsigned idx;
68             int x1, y1, x2, y2;
69             line_parameters curr, next;
70             int lcurr, lnext;
71             int xb1, yb1, xb2, yb2;
72             unsigned flags;
73         };
74 
75         void draw(draw_vars& dv, unsigned start, unsigned end);
76 
77     public:
78         typedef line_aa_vertex                  vertex_type;
79         typedef vertex_sequence<vertex_type, 6> vertex_storage_type;
80 
81         rasterizer_outline_aa(Renderer& ren) :
82             m_ren(ren),
83             m_accurate_join(m_ren.accurate_join_only()),
84             m_round_cap(false),
85             m_start_x(0),
86             m_start_y(0)
87         {
88         }
89 
90         //------------------------------------------------------------------------
91         void accurate_join(bool v)
92         {
93             m_accurate_join = m_ren.accurate_join_only() ? true : v;
94         }
95         bool accurate_join() const { return m_accurate_join; }
96 
97         //------------------------------------------------------------------------
98         void round_cap(bool v) { m_round_cap = v; }
99         bool round_cap() const { return m_round_cap; }
100 
101         //------------------------------------------------------------------------
102         void move_to(int x, int y)
103         {
104             m_src_vertices.modify_last(vertex_type(m_start_x = x, m_start_y = y));
105         }
106 
107         //------------------------------------------------------------------------
108         void line_to(int x, int y)
109         {
110             m_src_vertices.add(vertex_type(x, y));
111         }
112 
113         //------------------------------------------------------------------------
114         void move_to_d(double x, double y)
115         {
116             move_to(line_coord(x), line_coord(y));
117         }
118 
119         //------------------------------------------------------------------------
120         void line_to_d(double x, double y)
121         {
122             line_to(line_coord(x), line_coord(y));
123         }
124 
125         //------------------------------------------------------------------------
126         void render(bool close_polygon);
127 
128         //------------------------------------------------------------------------
129         void add_vertex(double x, double y, unsigned cmd)
130         {
131             if(is_move_to(cmd))
132             {
133                 render(false);
134                 move_to_d(x, y);
135             }
136             else
137             {
138                 if(is_end_poly(cmd))
139                 {
140                     render(is_closed(cmd));
141                     if(is_closed(cmd)) move_to(m_start_x, m_start_y);
142                 }
143                 else
144                 {
145                     line_to_d(x, y);
146                 }
147             }
148         }
149 
150         //------------------------------------------------------------------------
151         template<class VertexSource>
152         void add_path(VertexSource& vs, unsigned id=0)
153         {
154             double x;
155             double y;
156 
157             unsigned cmd;
158             vs.rewind(id);
159             while(!is_stop(cmd = vs.vertex(&x, &y)))
160             {
161                 add_vertex(x, y, cmd);
162             }
163             render(false);
164         }
165 
166 
167         //------------------------------------------------------------------------
168         template<class VertexSource, class ColorStorage, class PathId>
169         void render_all_paths(VertexSource& vs,
170                               const ColorStorage& colors,
171                               const PathId& id,
172                               unsigned num_paths)
173         {
174             for(unsigned i = 0; i < num_paths; i++)
175             {
176                 m_ren.color(colors[i]);
177                 add_path(vs, id[i]);
178             }
179         }
180 
181 
182         //------------------------------------------------------------------------
183         template<class Ctrl> void render_ctrl(Ctrl& c)
184         {
185             unsigned i;
186             for(i = 0; i < c.num_paths(); i++)
187             {
188                 m_ren.color(c.color(i));
189                 add_path(c, i);
190             }
191         }
192 
193     private:
194         rasterizer_outline_aa(const rasterizer_outline_aa<Renderer>&);
195         const rasterizer_outline_aa<Renderer>& operator =
196             (const rasterizer_outline_aa<Renderer>&);
197 
198         Renderer& m_ren;
199         vertex_storage_type m_src_vertices;
200         bool m_accurate_join;
201         bool m_round_cap;
202         int  m_start_x;
203         int  m_start_y;
204     };
205 
206 
207 
208 
209 
210 
211 
212 
213     //----------------------------------------------------------------------------
214     template<class Renderer>
215     void rasterizer_outline_aa<Renderer>::draw(draw_vars& dv, unsigned start, unsigned end)
216     {
217         unsigned i;
218         const vertex_storage_type::value_type* v;
219 
220         for(i = start; i < end; i++)
221         {
222             switch(dv.flags)
223             {
224             case 0: m_ren.line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break;
225             case 1: m_ren.line2(dv.curr, dv.xb2, dv.yb2); break;
226             case 2: m_ren.line1(dv.curr, dv.xb1, dv.yb1); break;
227             case 3: m_ren.line0(dv.curr); break;
228             }
229 
230             dv.x1 = dv.x2;
231             dv.y1 = dv.y2;
232             dv.lcurr = dv.lnext;
233             dv.lnext = m_src_vertices[dv.idx].len;
234 
235             ++dv.idx;
236             if(dv.idx >= m_src_vertices.size()) dv.idx = 0;
237 
238             v = &m_src_vertices[dv.idx];
239             dv.x2 = v->x;
240             dv.y2 = v->y;
241 
242             dv.curr = dv.next;
243             dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
244             dv.xb1 = dv.xb2;
245             dv.yb1 = dv.yb2;
246 
247             if(m_accurate_join)
248             {
249                 dv.flags = 0;
250             }
251             else
252             {
253                 dv.flags >>= 1;
254                 dv.flags |= ((dv.curr.diagonal_quadrant() ==
255                               dv.next.diagonal_quadrant()) << 1);
256             }
257 
258             if((dv.flags & 2) == 0)
259             {
260                 bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
261             }
262         }
263     }
264 
265 
266 
267 
268     //----------------------------------------------------------------------------
269     template<class Renderer>
270     void rasterizer_outline_aa<Renderer>::render(bool close_polygon)
271     {
272         m_src_vertices.close(close_polygon);
273         draw_vars dv;
274         const vertex_storage_type::value_type* v;
275         int x1;
276         int y1;
277         int x2;
278         int y2;
279         int lprev;
280 
281         if(close_polygon)
282         {
283             if(m_src_vertices.size() >= 3)
284             {
285                 dv.idx = 2;
286 
287                 v     = &m_src_vertices[m_src_vertices.size() - 1];
288                 x1    = v->x;
289                 y1    = v->y;
290                 lprev = v->len;
291 
292                 v  = &m_src_vertices[0];
293                 x2 = v->x;
294                 y2 = v->y;
295                 dv.lcurr = v->len;
296                 line_parameters prev(x1, y1, x2, y2, lprev);
297 
298                 v = &m_src_vertices[1];
299                 dv.x1    = v->x;
300                 dv.y1    = v->y;
301                 dv.lnext = v->len;
302                 dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
303 
304                 v = &m_src_vertices[dv.idx];
305                 dv.x2 = v->x;
306                 dv.y2 = v->y;
307                 dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
308 
309                 dv.xb1 = 0;
310                 dv.yb1 = 0;
311                 dv.xb2 = 0;
312                 dv.yb2 = 0;
313 
314                 if(m_accurate_join)
315                 {
316                     dv.flags = 0;
317                 }
318                 else
319                 {
320                     dv.flags =
321                             (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
322                         ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
323                 }
324 
325                 if((dv.flags & 1) == 0)
326                 {
327                     bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
328                 }
329 
330                 if((dv.flags & 2) == 0)
331                 {
332                     bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
333                 }
334                 draw(dv, 0, m_src_vertices.size());
335             }
336         }
337         else
338         {
339             switch(m_src_vertices.size())
340             {
341                 case 0:
342                 case 1:
343                     break;
344 
345                 case 2:
346                 {
347                     v     = &m_src_vertices[0];
348                     x1    = v->x;
349                     y1    = v->y;
350                     lprev = v->len;
351                     v     = &m_src_vertices[1];
352                     x2    = v->x;
353                     y2    = v->y;
354                     line_parameters lp(x1, y1, x2, y2, lprev);
355                     if(m_round_cap)
356                     {
357                         m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
358                     }
359                     m_ren.line3(lp,
360                                 x1 + (y2 - y1),
361                                 y1 - (x2 - x1),
362                                 x2 + (y2 - y1),
363                                 y2 - (x2 - x1));
364                     if(m_round_cap)
365                     {
366                         m_ren.semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1));
367                     }
368                 }
369                 break;
370 
371                 case 3:
372                 {
373                     int x3, y3;
374                     int lnext;
375                     v     = &m_src_vertices[0];
376                     x1    = v->x;
377                     y1    = v->y;
378                     lprev = v->len;
379                     v     = &m_src_vertices[1];
380                     x2    = v->x;
381                     y2    = v->y;
382                     lnext = v->len;
383                     v     = &m_src_vertices[2];
384                     x3    = v->x;
385                     y3    = v->y;
386                     line_parameters lp1(x1, y1, x2, y2, lprev);
387                     line_parameters lp2(x2, y2, x3, y3, lnext);
388                     bisectrix(lp1, lp2, &dv.xb1, &dv.yb1);
389 
390                     if(m_round_cap)
391                     {
392                         m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
393                     }
394                     m_ren.line3(lp1,
395                                 x1 + (y2 - y1),
396                                 y1 - (x2 - x1),
397                                 dv.xb1,
398                                 dv.yb1);
399 
400                     m_ren.line3(lp2,
401                                 dv.xb1,
402                                 dv.yb1,
403                                 x3 + (y3 - y2),
404                                 y3 - (x3 - x2));
405                     if(m_round_cap)
406                     {
407                         m_ren.semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2));
408                     }
409                 }
410                 break;
411 
412                 default:
413                 {
414                     dv.idx = 3;
415 
416                     v     = &m_src_vertices[0];
417                     x1    = v->x;
418                     y1    = v->y;
419                     lprev = v->len;
420 
421                     v  = &m_src_vertices[1];
422                     x2 = v->x;
423                     y2 = v->y;
424                     dv.lcurr = v->len;
425                     line_parameters prev(x1, y1, x2, y2, lprev);
426 
427                     v = &m_src_vertices[2];
428                     dv.x1    = v->x;
429                     dv.y1    = v->y;
430                     dv.lnext = v->len;
431                     dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
432 
433                     v = &m_src_vertices[dv.idx];
434                     dv.x2 = v->x;
435                     dv.y2 = v->y;
436                     dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
437 
438                     dv.xb1 = 0;
439                     dv.yb1 = 0;
440                     dv.xb2 = 0;
441                     dv.yb2 = 0;
442 
443                     if(m_accurate_join)
444                     {
445                         dv.flags = 0;
446                     }
447                     else
448                     {
449                         dv.flags =
450                                 (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
451                             ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
452                     }
453 
454                     if((dv.flags & 1) == 0)
455                     {
456                         bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
457                         m_ren.line3(prev,
458                                     x1 + (y2 - y1),
459                                     y1 - (x2 - x1),
460                                     dv.xb1,
461                                     dv.yb1);
462                     }
463                     else
464                     {
465                         m_ren.line1(prev,
466                                     x1 + (y2 - y1),
467                                     y1 - (x2 - x1));
468                     }
469                     if(m_round_cap)
470                     {
471                         m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
472                     }
473                     if((dv.flags & 2) == 0)
474                     {
475                         bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
476                     }
477 
478                     draw(dv, 1, m_src_vertices.size() - 2);
479 
480                     if((dv.flags & 1) == 0)
481                     {
482                         m_ren.line3(dv.curr,
483                                     dv.xb1,
484                                     dv.yb1,
485                                     dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
486                                     dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
487                     }
488                     else
489                     {
490                         m_ren.line2(dv.curr,
491                                     dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
492                                     dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
493                     }
494                     if(m_round_cap)
495                     {
496                         m_ren.semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2,
497                                       dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
498                                       dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
499                     }
500 
501                 }
502                 break;
503             }
504         }
505         m_src_vertices.remove_all();
506     }
507 
508 
509 }
510 
511 
512 #endif
513 
514