xref: /haiku/headers/libs/agg/agg_renderer_base.h (revision 3c69a2e24d54c655eae99499c7ff5aed36def422)
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 //
16 // class renderer_base
17 //
18 //----------------------------------------------------------------------------
19 
20 #ifndef AGG_RENDERER_BASE_INCLUDED
21 #define AGG_RENDERER_BASE_INCLUDED
22 
23 #include "agg_basics.h"
24 #include "agg_rendering_buffer.h"
25 
26 namespace agg
27 {
28 
29     //-----------------------------------------------------------renderer_base
30     template<class PixelFormat> class renderer_base
31     {
32     public:
33         typedef PixelFormat pixfmt_type;
34         typedef typename pixfmt_type::color_type color_type;
35         typedef typename pixfmt_type::row_data row_data;
36 
37         //--------------------------------------------------------------------
renderer_base()38         renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {}
renderer_base(pixfmt_type & ren)39         renderer_base(pixfmt_type& ren) :
40             m_ren(&ren),
41             m_clip_box(0, 0, ren.width() - 1, ren.height() - 1)
42         {}
attach(pixfmt_type & ren)43         void attach(pixfmt_type& ren)
44         {
45             m_ren = &ren;
46             m_clip_box = rect_i(0, 0, ren.width() - 1, ren.height() - 1);
47         }
48 
49         //--------------------------------------------------------------------
ren()50         const pixfmt_type& ren() const { return *m_ren;  }
ren()51         pixfmt_type& ren() { return *m_ren;  }
52 
53         //--------------------------------------------------------------------
width()54         unsigned width()  const { return m_ren->width();  }
height()55         unsigned height() const { return m_ren->height(); }
56 
57         //--------------------------------------------------------------------
clip_box(int x1,int y1,int x2,int y2)58         bool clip_box(int x1, int y1, int x2, int y2)
59         {
60             rect_i cb(x1, y1, x2, y2);
61             cb.normalize();
62             if(cb.clip(rect_i(0, 0, width() - 1, height() - 1)))
63             {
64                 m_clip_box = cb;
65                 return true;
66             }
67             m_clip_box.x1 = 1;
68             m_clip_box.y1 = 1;
69             m_clip_box.x2 = 0;
70             m_clip_box.y2 = 0;
71             return false;
72         }
73 
74         //--------------------------------------------------------------------
reset_clipping(bool visibility)75         void reset_clipping(bool visibility)
76         {
77             if(visibility)
78             {
79                 m_clip_box.x1 = 0;
80                 m_clip_box.y1 = 0;
81                 m_clip_box.x2 = width() - 1;
82                 m_clip_box.y2 = height() - 1;
83             }
84             else
85             {
86                 m_clip_box.x1 = 1;
87                 m_clip_box.y1 = 1;
88                 m_clip_box.x2 = 0;
89                 m_clip_box.y2 = 0;
90             }
91         }
92 
93         //--------------------------------------------------------------------
clip_box_naked(int x1,int y1,int x2,int y2)94         void clip_box_naked(int x1, int y1, int x2, int y2)
95         {
96             m_clip_box.x1 = x1;
97             m_clip_box.y1 = y1;
98             m_clip_box.x2 = x2;
99             m_clip_box.y2 = y2;
100         }
101 
102         //--------------------------------------------------------------------
inbox(int x,int y)103         bool inbox(int x, int y) const
104         {
105             return x >= m_clip_box.x1 && y >= m_clip_box.y1 &&
106                    x <= m_clip_box.x2 && y <= m_clip_box.y2;
107         }
108 
109         //--------------------------------------------------------------------
clip_box()110         const rect_i& clip_box() const { return m_clip_box;    }
xmin()111         int           xmin()     const { return m_clip_box.x1; }
ymin()112         int           ymin()     const { return m_clip_box.y1; }
xmax()113         int           xmax()     const { return m_clip_box.x2; }
ymax()114         int           ymax()     const { return m_clip_box.y2; }
115 
116         //--------------------------------------------------------------------
bounding_clip_box()117         const rect_i& bounding_clip_box() const { return m_clip_box;    }
bounding_xmin()118         int           bounding_xmin()     const { return m_clip_box.x1; }
bounding_ymin()119         int           bounding_ymin()     const { return m_clip_box.y1; }
bounding_xmax()120         int           bounding_xmax()     const { return m_clip_box.x2; }
bounding_ymax()121         int           bounding_ymax()     const { return m_clip_box.y2; }
122 
123         //--------------------------------------------------------------------
clear(const color_type & c)124         void clear(const color_type& c)
125         {
126             unsigned y;
127             if(width())
128             {
129                 for(y = 0; y < height(); y++)
130                 {
131                     m_ren->copy_hline(0, y, width(), c);
132                 }
133             }
134         }
135 
136         //--------------------------------------------------------------------
fill(const color_type & c)137         void fill(const color_type& c)
138         {
139             unsigned y;
140             if(width())
141             {
142                 for(y = 0; y < height(); y++)
143                 {
144                     m_ren->blend_hline(0, y, width(), c, cover_mask);
145                 }
146             }
147         }
148 
149         //--------------------------------------------------------------------
copy_pixel(int x,int y,const color_type & c)150         void copy_pixel(int x, int y, const color_type& c)
151         {
152             if(inbox(x, y))
153             {
154                 m_ren->copy_pixel(x, y, c);
155             }
156         }
157 
158         //--------------------------------------------------------------------
blend_pixel(int x,int y,const color_type & c,cover_type cover)159         void blend_pixel(int x, int y, const color_type& c, cover_type cover)
160         {
161             if(inbox(x, y))
162             {
163                 m_ren->blend_pixel(x, y, c, cover);
164             }
165         }
166 
167         //--------------------------------------------------------------------
pixel(int x,int y)168         color_type pixel(int x, int y) const
169         {
170             return inbox(x, y) ?
171                    m_ren->pixel(x, y) :
172                    color_type::no_color();
173         }
174 
175         //--------------------------------------------------------------------
copy_hline(int x1,int y,int x2,const color_type & c)176         void copy_hline(int x1, int y, int x2, const color_type& c)
177         {
178             if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
179             if(y  > ymax()) return;
180             if(y  < ymin()) return;
181             if(x1 > xmax()) return;
182             if(x2 < xmin()) return;
183 
184             if(x1 < xmin()) x1 = xmin();
185             if(x2 > xmax()) x2 = xmax();
186 
187             m_ren->copy_hline(x1, y, x2 - x1 + 1, c);
188         }
189 
190         //--------------------------------------------------------------------
copy_vline(int x,int y1,int y2,const color_type & c)191         void copy_vline(int x, int y1, int y2, const color_type& c)
192         {
193             if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
194             if(x  > xmax()) return;
195             if(x  < xmin()) return;
196             if(y1 > ymax()) return;
197             if(y2 < ymin()) return;
198 
199             if(y1 < ymin()) y1 = ymin();
200             if(y2 > ymax()) y2 = ymax();
201 
202             m_ren->copy_vline(x, y1, y2 - y1 + 1, c);
203         }
204 
205         //--------------------------------------------------------------------
blend_hline(int x1,int y,int x2,const color_type & c,cover_type cover)206         void blend_hline(int x1, int y, int x2,
207                          const color_type& c, cover_type cover)
208         {
209             if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
210             if(y  > ymax()) return;
211             if(y  < ymin()) return;
212             if(x1 > xmax()) return;
213             if(x2 < xmin()) return;
214 
215             if(x1 < xmin()) x1 = xmin();
216             if(x2 > xmax()) x2 = xmax();
217 
218             m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover);
219         }
220 
221 
222         //--------------------------------------------------------------------
blend_vline(int x,int y1,int y2,const color_type & c,cover_type cover)223         void blend_vline(int x, int y1, int y2,
224                          const color_type& c, cover_type cover)
225         {
226             if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
227             if(x  > xmax()) return;
228             if(x  < xmin()) return;
229             if(y1 > ymax()) return;
230             if(y2 < ymin()) return;
231 
232             if(y1 < ymin()) y1 = ymin();
233             if(y2 > ymax()) y2 = ymax();
234 
235             m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover);
236         }
237 
238 
239         //--------------------------------------------------------------------
copy_bar(int x1,int y1,int x2,int y2,const color_type & c)240         void copy_bar(int x1, int y1, int x2, int y2, const color_type& c)
241         {
242             rect_i rc(x1, y1, x2, y2);
243             rc.normalize();
244             if(rc.clip(clip_box()))
245             {
246                 int y;
247                 for(y = rc.y1; y <= rc.y2; y++)
248                 {
249                     m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c);
250                 }
251             }
252         }
253 
254         //--------------------------------------------------------------------
blend_bar(int x1,int y1,int x2,int y2,const color_type & c,cover_type cover)255         void blend_bar(int x1, int y1, int x2, int y2,
256                        const color_type& c, cover_type cover)
257         {
258             rect_i rc(x1, y1, x2, y2);
259             rc.normalize();
260             if(rc.clip(clip_box()))
261             {
262                 int y;
263                 for(y = rc.y1; y <= rc.y2; y++)
264                 {
265                     m_ren->blend_hline(rc.x1,
266                                        y,
267                                        unsigned(rc.x2 - rc.x1 + 1),
268                                        c,
269                                        cover);
270                 }
271             }
272         }
273 
274         //--------------------------------------------------------------------
blend_solid_hspan(int x,int y,int len,const color_type & c,const cover_type * covers)275         void blend_solid_hspan(int x, int y, int len,
276                                const color_type& c,
277                                const cover_type* covers)
278         {
279             if(y > ymax()) return;
280             if(y < ymin()) return;
281 
282             if(x < xmin())
283             {
284                 len -= xmin() - x;
285                 if(len <= 0) return;
286                 covers += xmin() - x;
287                 x = xmin();
288             }
289             if(x + len > xmax())
290             {
291                 len = xmax() - x + 1;
292                 if(len <= 0) return;
293             }
294             m_ren->blend_solid_hspan(x, y, len, c, covers);
295         }
296 
297 		//--------------------------------------------------------------------
blend_solid_hspan_subpix(int x,int y,int len,const color_type & c,const cover_type * covers)298         void blend_solid_hspan_subpix(int x, int y, int len,
299                                       const color_type& c,
300                                       const cover_type* covers)
301         {
302             if(y > ymax()) return;
303             if(y < ymin()) return;
304 
305             if(x < xmin())
306             {
307                 len -= 3 * (xmin() - x);
308                 if(len <= 0) return;
309                 covers += 3 * (xmin() - x);
310                 x = xmin();
311             }
312             if(x + len / 3 > xmax())
313             {
314                 len = 3 * (xmax() - x + 1);
315                 if(len <= 0) return;
316             }
317             m_ren->blend_solid_hspan_subpix(x, y, len, c, covers);
318         }
319 
320         //--------------------------------------------------------------------
blend_solid_vspan(int x,int y,int len,const color_type & c,const cover_type * covers)321         void blend_solid_vspan(int x, int y, int len,
322                                const color_type& c,
323                                const cover_type* covers)
324         {
325             if(x > xmax()) return;
326             if(x < xmin()) return;
327 
328             if(y < ymin())
329             {
330                 len -= ymin() - y;
331                 if(len <= 0) return;
332                 covers += ymin() - y;
333                 y = ymin();
334             }
335             if(y + len > ymax())
336             {
337                 len = ymax() - y + 1;
338                 if(len <= 0) return;
339             }
340             m_ren->blend_solid_vspan(x, y, len, c, covers);
341         }
342 
343 
344         //--------------------------------------------------------------------
copy_color_hspan(int x,int y,int len,const color_type * colors)345         void copy_color_hspan(int x, int y, int len, const color_type* colors)
346         {
347             if(y > ymax()) return;
348             if(y < ymin()) return;
349 
350             if(x < xmin())
351             {
352                 int d = xmin() - x;
353                 len -= d;
354                 if(len <= 0) return;
355                 colors += d;
356                 x = xmin();
357             }
358             if(x + len > xmax())
359             {
360                 len = xmax() - x + 1;
361                 if(len <= 0) return;
362             }
363             m_ren->copy_color_hspan(x, y, len, colors);
364         }
365 
366 
367         //--------------------------------------------------------------------
copy_color_vspan(int x,int y,int len,const color_type * colors)368         void copy_color_vspan(int x, int y, int len, const color_type* colors)
369         {
370             if(x > xmax()) return;
371             if(x < xmin()) return;
372 
373             if(y < ymin())
374             {
375                 int d = ymin() - y;
376                 len -= d;
377                 if(len <= 0) return;
378                 colors += d;
379                 y = ymin();
380             }
381             if(y + len > ymax())
382             {
383                 len = ymax() - y + 1;
384                 if(len <= 0) return;
385             }
386             m_ren->copy_color_vspan(x, y, len, colors);
387         }
388 
389 
390         //--------------------------------------------------------------------
391         void blend_color_hspan(int x, int y, int len,
392                                const color_type* colors,
393                                const cover_type* covers,
394                                cover_type cover = agg::cover_full)
395         {
396             if(y > ymax()) return;
397             if(y < ymin()) return;
398 
399             if(x < xmin())
400             {
401                 int d = xmin() - x;
402                 len -= d;
403                 if(len <= 0) return;
404                 if(covers) covers += d;
405                 colors += d;
406                 x = xmin();
407             }
408             if(x + len > xmax())
409             {
410                 len = xmax() - x + 1;
411                 if(len <= 0) return;
412             }
413             m_ren->blend_color_hspan(x, y, len, colors, covers, cover);
414         }
415 
416         //--------------------------------------------------------------------
417         void blend_color_vspan(int x, int y, int len,
418                                const color_type* colors,
419                                const cover_type* covers,
420                                cover_type cover = agg::cover_full)
421         {
422             if(x > xmax()) return;
423             if(x < xmin()) return;
424 
425             if(y < ymin())
426             {
427                 int d = ymin() - y;
428                 len -= d;
429                 if(len <= 0) return;
430                 if(covers) covers += d;
431                 colors += d;
432                 y = ymin();
433             }
434             if(y + len > ymax())
435             {
436                 len = ymax() - y + 1;
437                 if(len <= 0) return;
438             }
439             m_ren->blend_color_vspan(x, y, len, colors, covers, cover);
440         }
441 
442         //--------------------------------------------------------------------
clip_rect_area(rect_i & dst,rect_i & src,int wsrc,int hsrc)443         rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const
444         {
445             rect_i rc(0,0,0,0);
446             rect_i cb = clip_box();
447             ++cb.x2;
448             ++cb.y2;
449 
450             if(src.x1 < 0)
451             {
452                 dst.x1 -= src.x1;
453                 src.x1 = 0;
454             }
455             if(src.y1 < 0)
456             {
457                 dst.y1 -= src.y1;
458                 src.y1 = 0;
459             }
460 
461             if(src.x2 > wsrc) src.x2 = wsrc;
462             if(src.y2 > hsrc) src.y2 = hsrc;
463 
464             if(dst.x1 < cb.x1)
465             {
466                 src.x1 += cb.x1 - dst.x1;
467                 dst.x1 = cb.x1;
468             }
469             if(dst.y1 < cb.y1)
470             {
471                 src.y1 += cb.y1 - dst.y1;
472                 dst.y1 = cb.y1;
473             }
474 
475             if(dst.x2 > cb.x2) dst.x2 = cb.x2;
476             if(dst.y2 > cb.y2) dst.y2 = cb.y2;
477 
478             rc.x2 = dst.x2 - dst.x1;
479             rc.y2 = dst.y2 - dst.y1;
480 
481             if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1;
482             if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1;
483             return rc;
484         }
485 
486         //--------------------------------------------------------------------
487         template<class RenBuf>
488         void copy_from(const RenBuf& src,
489                        const rect_i* rect_src_ptr = 0,
490                        int dx = 0,
491                        int dy = 0)
492         {
493             rect_i rsrc(0, 0, src.width(), src.height());
494             if(rect_src_ptr)
495             {
496                 rsrc.x1 = rect_src_ptr->x1;
497                 rsrc.y1 = rect_src_ptr->y1;
498                 rsrc.x2 = rect_src_ptr->x2 + 1;
499                 rsrc.y2 = rect_src_ptr->y2 + 1;
500             }
501 
502             // Version with xdst, ydst (absolute positioning)
503             //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
504 
505             // Version with dx, dy (relative positioning)
506             rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
507 
508             rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
509 
510             if(rc.x2 > 0)
511             {
512                 int incy = 1;
513                 if(rdst.y1 > rsrc.y1)
514                 {
515                     rsrc.y1 += rc.y2 - 1;
516                     rdst.y1 += rc.y2 - 1;
517                     incy = -1;
518                 }
519                 while(rc.y2 > 0)
520                 {
521                     m_ren->copy_from(src,
522                                      rdst.x1, rdst.y1,
523                                      rsrc.x1, rsrc.y1,
524                                      rc.x2);
525                     rdst.y1 += incy;
526                     rsrc.y1 += incy;
527                     --rc.y2;
528                 }
529             }
530         }
531 
532         //--------------------------------------------------------------------
533         template<class SrcPixelFormatRenderer>
534         void blend_from(const SrcPixelFormatRenderer& src,
535                         const rect_i* rect_src_ptr = 0,
536                         int dx = 0,
537                         int dy = 0,
538                         cover_type cover = agg::cover_full)
539         {
540             rect_i rsrc(0, 0, src.width(), src.height());
541             if(rect_src_ptr)
542             {
543                 rsrc.x1 = rect_src_ptr->x1;
544                 rsrc.y1 = rect_src_ptr->y1;
545                 rsrc.x2 = rect_src_ptr->x2 + 1;
546                 rsrc.y2 = rect_src_ptr->y2 + 1;
547             }
548 
549             // Version with xdst, ydst (absolute positioning)
550             //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
551 
552             // Version with dx, dy (relative positioning)
553             rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
554             rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
555 
556             if(rc.x2 > 0)
557             {
558                 int incy = 1;
559                 if(rdst.y1 > rsrc.y1)
560                 {
561                     rsrc.y1 += rc.y2 - 1;
562                     rdst.y1 += rc.y2 - 1;
563                     incy = -1;
564                 }
565                 while(rc.y2 > 0)
566                 {
567                     typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
568                     if(rw.ptr)
569                     {
570                         int x1src = rsrc.x1;
571                         int x1dst = rdst.x1;
572                         int len   = rc.x2;
573                         if(rw.x1 > x1src)
574                         {
575                             x1dst += rw.x1 - x1src;
576                             len   -= rw.x1 - x1src;
577                             x1src  = rw.x1;
578                         }
579                         if(len > 0)
580                         {
581                             if(x1src + len-1 > rw.x2)
582                             {
583                                 len -= x1src + len - rw.x2 - 1;
584                             }
585                             if(len > 0)
586                             {
587                                 m_ren->blend_from(src,
588                                                   x1dst, rdst.y1,
589                                                   x1src, rsrc.y1,
590                                                   len,
591                                                   cover);
592                             }
593                         }
594                     }
595                     rdst.y1 += incy;
596                     rsrc.y1 += incy;
597                     --rc.y2;
598                 }
599             }
600         }
601 
602     private:
603         pixfmt_type* m_ren;
604         rect_i       m_clip_box;
605     };
606 
607 
608 }
609 
610 #endif
611