1/*
2 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
3 * Copyright 2008, Stephan A��mus <superstippi@gmx.de>.
4 * All rights reserved. Distributed under the terms of the MIT License.
5 *
6 * Copyright 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
7 *
8 *
9 * Class scanline_u8_subpix_avrg_filtering, a slightly modified version of
10 * scanline_u8 customized to store 3 covers per pixel and to implement
11 * average-based color filtering
12 *
13 */
14
15#ifndef AGG_SCANLINE_U_SUBPIX_AVRG_FILTERING_INCLUDED
16#define AGG_SCANLINE_U_SUBPIX_AVRG_FILTERING_INCLUDED
17
18#include "GlobalSubpixelSettings.h"
19
20namespace agg
21{
22	//=======================================scanline_u8_subpix_avrg_filtering
23	//------------------------------------------------------------------------
24	class scanline_u8_subpix_avrg_filtering
25	{
26	public:
27		typedef scanline_u8_subpix_avrg_filtering self_type;
28		typedef int8u		cover_type;
29		typedef int16		coord_type;
30
31		//--------------------------------------------------------------------
32		struct span
33		{
34			coord_type	x;
35			coord_type	len;
36			cover_type* covers;
37		};
38
39		typedef span* iterator;
40		typedef const span* const_iterator;
41
42		//--------------------------------------------------------------------
43		scanline_u8_subpix_avrg_filtering() :
44			m_min_x(0),
45			m_last_x(0x7FFFFFF0),
46			m_cur_span(0)
47		{}
48
49		//--------------------------------------------------------------------
50		void reset(int min_x, int max_x)
51		{
52			unsigned max_len = 3*(max_x - min_x + 2);
53			if(max_len > m_spans.size())
54			{
55				m_spans.resize(max_len);
56				m_covers.resize(max_len);
57			}
58			m_last_x   = 0x7FFFFFF0;
59			m_min_x	   = min_x;
60			m_cur_span = &m_spans[0];
61		}
62
63		//--------------------------------------------------------------------
64		void add_cell(int x, unsigned cover1, unsigned cover2, unsigned cover3)
65		{
66
67		// NOTE stippi: My basic idea is that filtering tries to minimize colored
68		// edges, but it does so by blurring the coverage values. This will also
69		// affect neighboring pixels and add blur where there were perfectly sharp
70		// edges. Andrej's method of filtering adds a special case for perfectly
71		// sharp edges, but the drawback here is that there will be a visible
72		// transition between blurred and non-blurred subpixels. I had the idea that
73		// when simply fading the subpixels towards the plain gray-scale-aa values,
74		// there must be a sweet spot for when colored edges become non-disturbing
75		// and there is still a benefit of sharpness compared to straight gray-scale-
76		// aa. The define above enables this method against the colored edges. My
77		// method still has a drawback, since jaggies in diagonal lines will be more
78		// visible again than with the filter method.
79
80			unsigned char averageWeight = gSubpixelAverageWeight;
81			unsigned char subpixelWeight = 255 - averageWeight;
82
83			unsigned int coverR;
84			unsigned int coverG;
85			unsigned int coverB;
86
87			unsigned int average = (cover1 + cover2 + cover3 + 2) / 3;
88
89			coverR = (cover1 * subpixelWeight + average * averageWeight) >> 8;
90			coverG = (cover2 * subpixelWeight + average * averageWeight) >> 8;
91			coverB = (cover3 * subpixelWeight + average * averageWeight) >> 8;
92
93			x -= m_min_x;
94			m_covers[3 * x] = (cover_type)coverR;
95			m_covers[3 * x + 1] = (cover_type)coverG;
96			m_covers[3 * x + 2] = (cover_type)coverB;
97			if(x == m_last_x + 1)
98			{
99				m_cur_span->len += 3;
100			}
101			else
102			{
103				m_cur_span++;
104				m_cur_span->x	   = (coord_type)(x + m_min_x);
105				m_cur_span->len	   = 3;
106				m_cur_span->covers = &m_covers[3 * x];
107			}
108			m_last_x = x;
109		}
110
111		//--------------------------------------------------------------------
112		void add_span(int x, unsigned len, unsigned cover)
113		{
114			x -= m_min_x;
115			memset(&m_covers[3 * x], cover, 3 * len);
116			if(x == m_last_x+1)
117			{
118				m_cur_span->len += 3 * (coord_type)len;
119			}
120			else
121			{
122				m_cur_span++;
123				m_cur_span->x	   = (coord_type)(x + m_min_x);
124				m_cur_span->len	   = 3 * (coord_type)len;
125				m_cur_span->covers = &m_covers[3 * x];
126			}
127			m_last_x = x + len - 1;
128		}
129
130		//--------------------------------------------------------------------
131		void finalize(int y)
132		{
133			m_y = y;
134		}
135
136		//--------------------------------------------------------------------
137		void reset_spans()
138		{
139			m_last_x	= 0x7FFFFFF0;
140			m_cur_span	= &m_spans[0];
141		}
142
143		//--------------------------------------------------------------------
144		int		 y()		   const { return m_y; }
145		unsigned num_spans()   const { return unsigned(m_cur_span - &m_spans[0]); }
146		const_iterator begin() const { return &m_spans[1]; }
147		iterator	   begin()		 { return &m_spans[1]; }
148
149	private:
150		scanline_u8_subpix_avrg_filtering(const self_type&);
151		const self_type& operator = (const self_type&);
152
153	private:
154		int					  m_min_x;
155		int					  m_last_x;
156		int					  m_y;
157		pod_array<cover_type> m_covers;
158		pod_array<span>		  m_spans;
159		span*				  m_cur_span;
160	};
161
162}
163
164#endif
165
166