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