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