xref: /haiku/headers/libs/agg/agg_renderer_base.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 //
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         void blend_vline(int x, int y1, int y2,
211                          const color_type& c, cover_type cover)
212         {
213             if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
214             if(x  > xmax()) return;
215             if(x  < xmin()) return;
216             if(y1 > ymax()) return;
217             if(y2 < ymin()) return;
218 
219             if(y1 < ymin()) y1 = ymin();
220             if(y2 > ymax()) y2 = ymax();
221 
222             m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover);
223         }
224 
225 
226         //--------------------------------------------------------------------
227         void copy_bar(int x1, int y1, int x2, int y2, const color_type& c)
228         {
229             rect_i rc(x1, y1, x2, y2);
230             rc.normalize();
231             if(rc.clip(clip_box()))
232             {
233                 int y;
234                 for(y = rc.y1; y <= rc.y2; y++)
235                 {
236                     m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c);
237                 }
238             }
239         }
240 
241         //--------------------------------------------------------------------
242         void blend_bar(int x1, int y1, int x2, int y2,
243                        const color_type& c, cover_type cover)
244         {
245             rect_i rc(x1, y1, x2, y2);
246             rc.normalize();
247             if(rc.clip(clip_box()))
248             {
249                 int y;
250                 for(y = rc.y1; y <= rc.y2; y++)
251                 {
252                     m_ren->blend_hline(rc.x1,
253                                        y,
254                                        unsigned(rc.x2 - rc.x1 + 1),
255                                        c,
256                                        cover);
257                 }
258             }
259         }
260 
261         //--------------------------------------------------------------------
262         void blend_solid_hspan(int x, int y, int len,
263                                const color_type& c,
264                                const cover_type* covers)
265         {
266             if(y > ymax()) return;
267             if(y < ymin()) return;
268 
269             if(x < xmin())
270             {
271                 len -= xmin() - x;
272                 if(len <= 0) return;
273                 covers += xmin() - x;
274                 x = xmin();
275             }
276             if(x + len > xmax())
277             {
278                 len = xmax() - x + 1;
279                 if(len <= 0) return;
280             }
281             m_ren->blend_solid_hspan(x, y, len, c, covers);
282         }
283 
284         //--------------------------------------------------------------------
285         void blend_solid_vspan(int x, int y, int len,
286                                const color_type& c,
287                                const cover_type* covers)
288         {
289             if(x > xmax()) return;
290             if(x < xmin()) return;
291 
292             if(y < ymin())
293             {
294                 len -= ymin() - y;
295                 if(len <= 0) return;
296                 covers += ymin() - y;
297                 y = ymin();
298             }
299             if(y + len > ymax())
300             {
301                 len = ymax() - y + 1;
302                 if(len <= 0) return;
303             }
304             m_ren->blend_solid_vspan(x, y, len, c, covers);
305         }
306 
307 
308         //--------------------------------------------------------------------
309         void copy_color_hspan(int x, int y, int len, const color_type* colors)
310         {
311             if(y > ymax()) return;
312             if(y < ymin()) return;
313 
314             if(x < xmin())
315             {
316                 int d = xmin() - x;
317                 len -= d;
318                 if(len <= 0) return;
319                 colors += d;
320                 x = xmin();
321             }
322             if(x + len > xmax())
323             {
324                 len = xmax() - x + 1;
325                 if(len <= 0) return;
326             }
327             m_ren->copy_color_hspan(x, y, len, colors);
328         }
329 
330 
331         //--------------------------------------------------------------------
332         void copy_color_vspan(int x, int y, int len, const color_type* colors)
333         {
334             if(x > xmax()) return;
335             if(x < xmin()) return;
336 
337             if(y < ymin())
338             {
339                 int d = ymin() - y;
340                 len -= d;
341                 if(len <= 0) return;
342                 colors += d;
343                 y = ymin();
344             }
345             if(y + len > ymax())
346             {
347                 len = ymax() - y + 1;
348                 if(len <= 0) return;
349             }
350             m_ren->copy_color_vspan(x, y, len, colors);
351         }
352 
353 
354         //--------------------------------------------------------------------
355         void blend_color_hspan(int x, int y, int len,
356                                const color_type* colors,
357                                const cover_type* covers,
358                                cover_type cover = agg::cover_full)
359         {
360             if(y > ymax()) return;
361             if(y < ymin()) return;
362 
363             if(x < xmin())
364             {
365                 int d = xmin() - x;
366                 len -= d;
367                 if(len <= 0) return;
368                 if(covers) covers += d;
369                 colors += d;
370                 x = xmin();
371             }
372             if(x + len > xmax())
373             {
374                 len = xmax() - x + 1;
375                 if(len <= 0) return;
376             }
377             m_ren->blend_color_hspan(x, y, len, colors, covers, cover);
378         }
379 
380         //--------------------------------------------------------------------
381         void blend_color_vspan(int x, int y, int len,
382                                const color_type* colors,
383                                const cover_type* covers,
384                                cover_type cover = agg::cover_full)
385         {
386             if(x > xmax()) return;
387             if(x < xmin()) return;
388 
389             if(y < ymin())
390             {
391                 int d = ymin() - y;
392                 len -= d;
393                 if(len <= 0) return;
394                 if(covers) covers += d;
395                 colors += d;
396                 y = ymin();
397             }
398             if(y + len > ymax())
399             {
400                 len = ymax() - y + 1;
401                 if(len <= 0) return;
402             }
403             m_ren->blend_color_vspan(x, y, len, colors, covers, cover);
404         }
405 
406         //--------------------------------------------------------------------
407         rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const
408         {
409             rect_i rc(0,0,0,0);
410             rect_i cb = clip_box();
411             ++cb.x2;
412             ++cb.y2;
413 
414             if(src.x1 < 0)
415             {
416                 dst.x1 -= src.x1;
417                 src.x1 = 0;
418             }
419             if(src.y1 < 0)
420             {
421                 dst.y1 -= src.y1;
422                 src.y1 = 0;
423             }
424 
425             if(src.x2 > wsrc) src.x2 = wsrc;
426             if(src.y2 > hsrc) src.y2 = hsrc;
427 
428             if(dst.x1 < cb.x1)
429             {
430                 src.x1 += cb.x1 - dst.x1;
431                 dst.x1 = cb.x1;
432             }
433             if(dst.y1 < cb.y1)
434             {
435                 src.y1 += cb.y1 - dst.y1;
436                 dst.y1 = cb.y1;
437             }
438 
439             if(dst.x2 > cb.x2) dst.x2 = cb.x2;
440             if(dst.y2 > cb.y2) dst.y2 = cb.y2;
441 
442             rc.x2 = dst.x2 - dst.x1;
443             rc.y2 = dst.y2 - dst.y1;
444 
445             if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1;
446             if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1;
447             return rc;
448         }
449 
450         //--------------------------------------------------------------------
451         template<class RenBuf>
452         void copy_from(const RenBuf& src,
453                        const rect_i* rect_src_ptr = 0,
454                        int dx = 0,
455                        int dy = 0)
456         {
457             rect_i rsrc(0, 0, src.width(), src.height());
458             if(rect_src_ptr)
459             {
460                 rsrc.x1 = rect_src_ptr->x1;
461                 rsrc.y1 = rect_src_ptr->y1;
462                 rsrc.x2 = rect_src_ptr->x2 + 1;
463                 rsrc.y2 = rect_src_ptr->y2 + 1;
464             }
465 
466             // Version with xdst, ydst (absolute positioning)
467             //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
468 
469             // Version with dx, dy (relative positioning)
470             rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
471 
472             rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
473 
474             if(rc.x2 > 0)
475             {
476                 int incy = 1;
477                 if(rdst.y1 > rsrc.y1)
478                 {
479                     rsrc.y1 += rc.y2 - 1;
480                     rdst.y1 += rc.y2 - 1;
481                     incy = -1;
482                 }
483                 while(rc.y2 > 0)
484                 {
485                     m_ren->copy_from(src,
486                                      rdst.x1, rdst.y1,
487                                      rsrc.x1, rsrc.y1,
488                                      rc.x2);
489                     rdst.y1 += incy;
490                     rsrc.y1 += incy;
491                     --rc.y2;
492                 }
493             }
494         }
495 
496         //--------------------------------------------------------------------
497         template<class SrcPixelFormatRenderer>
498         void blend_from(const SrcPixelFormatRenderer& src,
499                         const rect_i* rect_src_ptr = 0,
500                         int dx = 0,
501                         int dy = 0,
502                         cover_type cover = agg::cover_full)
503         {
504             rect_i rsrc(0, 0, src.width(), src.height());
505             if(rect_src_ptr)
506             {
507                 rsrc.x1 = rect_src_ptr->x1;
508                 rsrc.y1 = rect_src_ptr->y1;
509                 rsrc.x2 = rect_src_ptr->x2 + 1;
510                 rsrc.y2 = rect_src_ptr->y2 + 1;
511             }
512 
513             // Version with xdst, ydst (absolute positioning)
514             //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
515 
516             // Version with dx, dy (relative positioning)
517             rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
518             rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
519 
520             if(rc.x2 > 0)
521             {
522                 int incy = 1;
523                 if(rdst.y1 > rsrc.y1)
524                 {
525                     rsrc.y1 += rc.y2 - 1;
526                     rdst.y1 += rc.y2 - 1;
527                     incy = -1;
528                 }
529                 while(rc.y2 > 0)
530                 {
531                     typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
532                     if(rw.ptr)
533                     {
534                         int x1src = rsrc.x1;
535                         int x1dst = rdst.x1;
536                         int len   = rc.x2;
537                         if(rw.x1 > x1src)
538                         {
539                             x1dst += rw.x1 - x1src;
540                             len   -= rw.x1 - x1src;
541                             x1src  = rw.x1;
542                         }
543                         if(len > 0)
544                         {
545                             if(x1src + len-1 > rw.x2)
546                             {
547                                 len -= x1src + len - rw.x2 - 1;
548                             }
549                             if(len > 0)
550                             {
551                                 m_ren->blend_from(src,
552                                                   x1dst, rdst.y1,
553                                                   x1src, rsrc.y1,
554                                                   len,
555                                                   cover);
556                             }
557                         }
558                     }
559                     rdst.y1 += incy;
560                     rsrc.y1 += incy;
561                     --rc.y2;
562                 }
563             }
564         }
565 
566     private:
567         pixfmt_type* m_ren;
568         rect_i       m_clip_box;
569     };
570 
571 
572 }
573 
574 #endif
575