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 // Adaptation for 32-bit screen coordinates (scanline32_u) has been sponsored by
17 // Liberty Technology Systems, Inc., visit http://lib-sys.com
18 //
19 // Liberty Technology Systems, Inc. is the provider of
20 // PostScript and PDF technology for software developers.
21 //
22 //----------------------------------------------------------------------------
23 
24 #ifndef AGG_SCANLINE_U_INCLUDED
25 #define AGG_SCANLINE_U_INCLUDED
26 
27 #include <cstring>
28 #include "agg_array.h"
29 
30 namespace agg
31 {
32     //=============================================================scanline_u8
33     //
34     // Unpacked scanline container class
35     //
36     // This class is used to transfer data from a scanline rasterizer
37     // to the rendering buffer. It's organized very simple. The class stores
38     // information of horizontal spans to render it into a pixel-map buffer.
39     // Each span has staring X, length, and an array of bytes that determine the
40     // cover-values for each pixel.
41     // Before using this class you should know the minimal and maximal pixel
42     // coordinates of your scanline. The protocol of using is:
43     // 1. reset(min_x, max_x)
44     // 2. add_cell() / add_span() - accumulate scanline.
45     //    When forming one scanline the next X coordinate must be always greater
46     //    than the last stored one, i.e. it works only with ordered coordinates.
47     // 3. Call finalize(y) and render the scanline.
48     // 3. Call reset_spans() to prepare for the new scanline.
49     //
50     // 4. Rendering:
51     //
52     // Scanline provides an iterator class that allows you to extract
53     // the spans and the cover values for each pixel. Be aware that clipping
54     // has not been done yet, so you should perform it yourself.
55     // Use scanline_u8::iterator to render spans:
56     //-------------------------------------------------------------------------
57     //
58     // int y = sl.y();                    // Y-coordinate of the scanline
59     //
60     // ************************************
61     // ...Perform vertical clipping here...
62     // ************************************
63     //
64     // scanline_u8::const_iterator span = sl.begin();
65     //
66     // unsigned char* row = m_rbuf->row(y); // The address of the beginning
67     //                                      // of the current row
68     //
69     // unsigned num_spans = sl.num_spans(); // Number of spans. It's guaranteed that
70     //                                      // num_spans is always greater than 0.
71     //
72     // do
73     // {
74     //     const scanline_u8::cover_type* covers =
75     //         span->covers;                     // The array of the cover values
76     //
77     //     int num_pix = span->len;              // Number of pixels of the span.
78     //                                           // Always greater than 0, still it's
79     //                                           // better to use "int" instead of
80     //                                           // "unsigned" because it's more
81     //                                           // convenient for clipping
82     //     int x = span->x;
83     //
84     //     **************************************
85     //     ...Perform horizontal clipping here...
86     //     ...you have x, covers, and pix_count..
87     //     **************************************
88     //
89     //     unsigned char* dst = row + x;  // Calculate the start address of the row.
90     //                                    // In this case we assume a simple
91     //                                    // grayscale image 1-byte per pixel.
92     //     do
93     //     {
94     //         *dst++ = *covers++;        // Hypotetical rendering.
95     //     }
96     //     while(--num_pix);
97     //
98     //     ++span;
99     // }
100     // while(--num_spans);  // num_spans cannot be 0, so this loop is quite safe
101     //------------------------------------------------------------------------
102     //
103     // The question is: why should we accumulate the whole scanline when we
104     // could render just separate spans when they're ready?
105     // That's because using the scanline is generally faster. When is consists
106     // of more than one span the conditions for the processor cash system
107     // are better, because switching between two different areas of memory
108     // (that can be very large) occurs less frequently.
109     //------------------------------------------------------------------------
110     class scanline_u8
111     {
112     public:
113         typedef scanline_u8 self_type;
114         typedef int8u       cover_type;
115         typedef int16       coord_type;
116 
117         //--------------------------------------------------------------------
118         struct span
119         {
120             coord_type  x;
121             coord_type  len;
122             cover_type* covers;
123         };
124 
125         typedef span* iterator;
126         typedef const span* const_iterator;
127 
128         //--------------------------------------------------------------------
scanline_u8()129         scanline_u8() :
130             m_min_x(0),
131             m_last_x(0x7FFFFFF0),
132             m_cur_span(0)
133         {}
134 
135         //--------------------------------------------------------------------
reset(int min_x,int max_x)136         void reset(int min_x, int max_x)
137         {
138             unsigned max_len = max_x - min_x + 2;
139             if(max_len > m_spans.size())
140             {
141                 m_spans.resize(max_len);
142                 m_covers.resize(max_len);
143             }
144             m_last_x   = 0x7FFFFFF0;
145             m_min_x    = min_x;
146             m_cur_span = &m_spans[0];
147         }
148 
149         //--------------------------------------------------------------------
add_cell(int x,unsigned cover)150         void add_cell(int x, unsigned cover)
151         {
152             x -= m_min_x;
153             m_covers[x] = (cover_type)cover;
154             if(x == m_last_x+1)
155             {
156                 m_cur_span->len++;
157             }
158             else
159             {
160                 m_cur_span++;
161                 m_cur_span->x      = (coord_type)(x + m_min_x);
162                 m_cur_span->len    = 1;
163                 m_cur_span->covers = &m_covers[x];
164             }
165             m_last_x = x;
166         }
167 
168         //--------------------------------------------------------------------
add_cells(int x,unsigned len,const cover_type * covers)169         void add_cells(int x, unsigned len, const cover_type* covers)
170         {
171             x -= m_min_x;
172             std::memcpy(&m_covers[x], covers, len * sizeof(cover_type));
173             if(x == m_last_x+1)
174             {
175                 m_cur_span->len += (coord_type)len;
176             }
177             else
178             {
179                 m_cur_span++;
180                 m_cur_span->x      = (coord_type)(x + m_min_x);
181                 m_cur_span->len    = (coord_type)len;
182                 m_cur_span->covers = &m_covers[x];
183             }
184             m_last_x = x + len - 1;
185         }
186 
187         //--------------------------------------------------------------------
add_span(int x,unsigned len,unsigned cover)188         void add_span(int x, unsigned len, unsigned cover)
189         {
190             x -= m_min_x;
191             std::memset(&m_covers[x], cover, len);
192             if(x == m_last_x+1)
193             {
194                 m_cur_span->len += (coord_type)len;
195             }
196             else
197             {
198                 m_cur_span++;
199                 m_cur_span->x      = (coord_type)(x + m_min_x);
200                 m_cur_span->len    = (coord_type)len;
201                 m_cur_span->covers = &m_covers[x];
202             }
203             m_last_x = x + len - 1;
204         }
205 
206         //--------------------------------------------------------------------
finalize(int y)207         void finalize(int y)
208         {
209             m_y = y;
210         }
211 
212         //--------------------------------------------------------------------
reset_spans()213         void reset_spans()
214         {
215             m_last_x    = 0x7FFFFFF0;
216             m_cur_span  = &m_spans[0];
217         }
218 
219         //--------------------------------------------------------------------
y()220         int      y()           const { return m_y; }
num_spans()221         unsigned num_spans()   const { return unsigned(m_cur_span - &m_spans[0]); }
begin()222         const_iterator begin() const { return &m_spans[1]; }
begin()223         iterator       begin()       { return &m_spans[1]; }
224 
225     private:
226         scanline_u8(const self_type&);
227         const self_type& operator = (const self_type&);
228 
229     private:
230         int                   m_min_x;
231         int                   m_last_x;
232         int                   m_y;
233         pod_array<cover_type> m_covers;
234         pod_array<span>       m_spans;
235         span*                 m_cur_span;
236     };
237 
238 
239 
240 
241     //==========================================================scanline_u8_am
242     //
243     // The scanline container with alpha-masking
244     //
245     //------------------------------------------------------------------------
246     template<class AlphaMask>
247     class scanline_u8_am : public scanline_u8
248     {
249     public:
250         typedef scanline_u8           base_type;
251         typedef AlphaMask             alpha_mask_type;
252         typedef base_type::cover_type cover_type;
253         typedef base_type::coord_type coord_type;
254 
scanline_u8_am()255         scanline_u8_am() : base_type(), m_alpha_mask(0) {}
scanline_u8_am(AlphaMask & am)256         scanline_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {}
257 
258         //--------------------------------------------------------------------
finalize(int span_y)259         void finalize(int span_y)
260         {
261             base_type::finalize(span_y);
262             if(m_alpha_mask)
263             {
264                 typename base_type::iterator span = base_type::begin();
265                 unsigned count = base_type::num_spans();
266                 do
267                 {
268                     m_alpha_mask->combine_hspan(span->x,
269                                                 base_type::y(),
270                                                 span->covers,
271                                                 span->len);
272                     ++span;
273                 }
274                 while(--count);
275             }
276         }
277 
278     private:
279         AlphaMask* m_alpha_mask;
280     };
281 
282 
283 
284 
285     //===========================================================scanline32_u8
286     class scanline32_u8
287     {
288     public:
289         typedef scanline32_u8 self_type;
290         typedef int8u         cover_type;
291         typedef int32         coord_type;
292 
293         //--------------------------------------------------------------------
294         struct span
295         {
spanspan296             span() {}
spanspan297             span(coord_type x_, coord_type len_, cover_type* covers_) :
298                 x(x_), len(len_), covers(covers_) {}
299 
300             coord_type  x;
301             coord_type  len;
302             cover_type* covers;
303         };
304 
305         typedef pod_bvector<span, 4> span_array_type;
306 
307         //--------------------------------------------------------------------
308         class const_iterator
309         {
310         public:
const_iterator(const span_array_type & spans)311             const_iterator(const span_array_type& spans) :
312                 m_spans(spans),
313                 m_span_idx(0)
314             {}
315 
316             const span& operator*()  const { return m_spans[m_span_idx];  }
317             const span* operator->() const { return &m_spans[m_span_idx]; }
318 
319             void operator ++ () { ++m_span_idx; }
320 
321         private:
322             const span_array_type& m_spans;
323             unsigned               m_span_idx;
324         };
325 
326         //--------------------------------------------------------------------
327         class iterator
328         {
329         public:
iterator(span_array_type & spans)330             iterator(span_array_type& spans) :
331                 m_spans(spans),
332                 m_span_idx(0)
333             {}
334 
335             span& operator*()  { return m_spans[m_span_idx];  }
336             span* operator->() { return &m_spans[m_span_idx]; }
337 
338             void operator ++ () { ++m_span_idx; }
339 
340         private:
341             span_array_type& m_spans;
342             unsigned         m_span_idx;
343         };
344 
345 
346 
347         //--------------------------------------------------------------------
scanline32_u8()348         scanline32_u8() :
349             m_min_x(0),
350             m_last_x(0x7FFFFFF0),
351             m_covers()
352         {}
353 
354         //--------------------------------------------------------------------
reset(int min_x,int max_x)355         void reset(int min_x, int max_x)
356         {
357             unsigned max_len = max_x - min_x + 2;
358             if(max_len > m_covers.size())
359             {
360                 m_covers.resize(max_len);
361             }
362             m_last_x = 0x7FFFFFF0;
363             m_min_x  = min_x;
364             m_spans.remove_all();
365         }
366 
367         //--------------------------------------------------------------------
add_cell(int x,unsigned cover)368         void add_cell(int x, unsigned cover)
369         {
370             x -= m_min_x;
371             m_covers[x] = cover_type(cover);
372             if(x == m_last_x+1)
373             {
374                 m_spans.last().len++;
375             }
376             else
377             {
378                 m_spans.add(span(coord_type(x + m_min_x), 1, &m_covers[x]));
379             }
380             m_last_x = x;
381         }
382 
383         //--------------------------------------------------------------------
add_cells(int x,unsigned len,const cover_type * covers)384         void add_cells(int x, unsigned len, const cover_type* covers)
385         {
386             x -= m_min_x;
387             std::memcpy(&m_covers[x], covers, len * sizeof(cover_type));
388             if(x == m_last_x+1)
389             {
390                 m_spans.last().len += coord_type(len);
391             }
392             else
393             {
394                 m_spans.add(span(coord_type(x + m_min_x),
395                                  coord_type(len),
396                                  &m_covers[x]));
397             }
398             m_last_x = x + len - 1;
399         }
400 
401         //--------------------------------------------------------------------
add_span(int x,unsigned len,unsigned cover)402         void add_span(int x, unsigned len, unsigned cover)
403         {
404             x -= m_min_x;
405             std::memset(&m_covers[x], cover, len);
406             if(x == m_last_x+1)
407             {
408                 m_spans.last().len += coord_type(len);
409             }
410             else
411             {
412                 m_spans.add(span(coord_type(x + m_min_x),
413                                  coord_type(len),
414                                  &m_covers[x]));
415             }
416             m_last_x = x + len - 1;
417         }
418 
419         //--------------------------------------------------------------------
finalize(int y)420         void finalize(int y)
421         {
422             m_y = y;
423         }
424 
425         //--------------------------------------------------------------------
reset_spans()426         void reset_spans()
427         {
428             m_last_x = 0x7FFFFFF0;
429             m_spans.remove_all();
430         }
431 
432         //--------------------------------------------------------------------
y()433         int      y()           const { return m_y; }
num_spans()434         unsigned num_spans()   const { return m_spans.size(); }
begin()435         const_iterator begin() const { return const_iterator(m_spans); }
begin()436         iterator       begin()       { return iterator(m_spans); }
437 
438     private:
439         scanline32_u8(const self_type&);
440         const self_type& operator = (const self_type&);
441 
442     private:
443         int                   m_min_x;
444         int                   m_last_x;
445         int                   m_y;
446         pod_array<cover_type> m_covers;
447         span_array_type       m_spans;
448     };
449 
450 
451 
452 
453     //========================================================scanline32_u8_am
454     //
455     // The scanline container with alpha-masking
456     //
457     //------------------------------------------------------------------------
458     template<class AlphaMask>
459     class scanline32_u8_am : public scanline32_u8
460     {
461     public:
462         typedef scanline32_u8         base_type;
463         typedef AlphaMask             alpha_mask_type;
464         typedef base_type::cover_type cover_type;
465         typedef base_type::coord_type coord_type;
466 
467 
scanline32_u8_am()468         scanline32_u8_am() : base_type(), m_alpha_mask(0) {}
scanline32_u8_am(AlphaMask & am)469         scanline32_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {}
470 
471         //--------------------------------------------------------------------
finalize(int span_y)472         void finalize(int span_y)
473         {
474             base_type::finalize(span_y);
475             if(m_alpha_mask)
476             {
477                 typename base_type::iterator span = base_type::begin();
478                 unsigned count = base_type::num_spans();
479                 do
480                 {
481                     m_alpha_mask->combine_hspan(span->x,
482                                                 base_type::y(),
483                                                 span->covers,
484                                                 span->len);
485                     ++span;
486                 }
487                 while(--count);
488             }
489         }
490 
491     private:
492         AlphaMask* m_alpha_mask;
493     };
494 
495 
496 
497 }
498 
499 #endif
500 
501