/*
 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
 * All rights reserved. Distributed under the terms of the MIT License.
 *
 * Copyright 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
 *
 *
 */
 
#ifndef AGG_RASTERIZER_SCANLINE_AA_SUBPIX_INCLUDED
#define AGG_RASTERIZER_SCANLINE_AA_SUBPIX_INCLUDED
 
#include "agg_rasterizer_cells_aa.h"
#include "agg_rasterizer_sl_clip.h"
#include "agg_gamma_functions.h"
 
 
namespace agg
{
	template<class Clip=rasterizer_sl_clip_int> class rasterizer_scanline_aa_subpix
	{
		enum status
		{
			status_initial,
			status_move_to,
			status_line_to,
			status_closed
		};
 
	public:
		typedef Clip					  clip_type;
		typedef typename Clip::conv_type  conv_type;
		typedef typename Clip::coord_type coord_type;
 
		enum aa_scale_e
		{
			aa_shift  = 8,
			aa_scale  = 1 << aa_shift,
			aa_mask	  = aa_scale - 1,
			aa_scale2 = aa_scale * 2,
			aa_mask2  = aa_scale2 - 1
		};
 
		//--------------------------------------------------------------------
		rasterizer_scanline_aa_subpix() : 
			m_outline(),
			m_clipper(),
			m_filling_rule(fill_non_zero),
			m_auto_close(true),
			m_start_x(0),
			m_start_y(0),
			m_status(status_initial)
		{
			int i;
			for(i = 0; i < aa_scale; i++) m_gamma[i] = i;
		}
 
		//--------------------------------------------------------------------
		template<class GammaF> 
		rasterizer_scanline_aa_subpix(const GammaF& gamma_function) : 
			m_outline(),
			m_clipper(m_outline),
			m_filling_rule(fill_non_zero),
			m_auto_close(true),
			m_start_x(0),
			m_start_y(0),
			m_status(status_initial)
		{
			gamma(gamma_function);
		}
 
		//--------------------------------------------------------------------
		void reset(); 
		void reset_clipping();
		void clip_box(double x1, double y1, double x2, double y2);
		void filling_rule(filling_rule_e filling_rule);
		void auto_close(bool flag) { m_auto_close = flag; }
 
		//--------------------------------------------------------------------
		template<class GammaF> void gamma(const GammaF& gamma_function)
		{ 
			int i;
			for(i = 0; i < aa_scale; i++)
			{
				m_gamma[i] = uround(gamma_function(double(i) / aa_mask) * aa_mask);
			}
		}
 
		//--------------------------------------------------------------------
		unsigned apply_gamma(unsigned cover) const 
		{ 
			return m_gamma[cover]; 
		}
 
		//--------------------------------------------------------------------
		void move_to(int x, int y);
		void line_to(int x, int y);
		void move_to_d(double x, double y);
		void line_to_d(double x, double y);
		void close_polygon();
		void add_vertex(double x, double y, unsigned cmd);
 
		void edge(int x1, int y1, int x2, int y2);
		void edge_d(double x1, double y1, double x2, double y2);
 
		//-------------------------------------------------------------------
		template<class VertexSource>
		void add_path(VertexSource& vs, unsigned path_id=0)
		{
			double x = 0;
			double y = 0;
 
			unsigned cmd;
			vs.rewind(path_id);
			if(m_outline.sorted()) reset();
			while(!is_stop(cmd = vs.vertex(&x, &y)))
			{
				if (is_vertex(cmd)) {
					x *= 3;
				}
				add_vertex(x, y, cmd);
			}
		}
		
		//--------------------------------------------------------------------
		int min_x() const { return m_outline.min_x() / 3; }
		int min_y() const { return m_outline.min_y(); }
		int max_x() const { return m_outline.max_x() / 3; }
		int max_y() const { return m_outline.max_y(); }
 
		//--------------------------------------------------------------------
		void sort();
		bool rewind_scanlines();
		bool navigate_scanline(int y);
 
		//--------------------------------------------------------------------
		AGG_INLINE unsigned calculate_alpha(int area) const
		{
			int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift);
 
			if(cover < 0) cover = -cover;
			if(m_filling_rule == fill_even_odd)
			{
				cover &= aa_mask2;
				if(cover > aa_scale)
				{
					cover = aa_scale2 - cover;
				}
			}
			if(cover > aa_mask) cover = aa_mask;
			return m_gamma[cover];
		}
 
		//--------------------------------------------------------------------
		template<class Scanline> bool sweep_scanline(Scanline& sl)
		{
			for(;;)
			{
				if(m_scan_y > m_outline.max_y()) return false;
				sl.reset_spans();
				unsigned num_cells = m_outline.scanline_num_cells(m_scan_y);
				const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y);
				int cover = 0;
				int cover2 = 0;
				int cover3 = 0;
 
				while(num_cells)
				{
					const cell_aa* cur_cell = *cells;
					int x	 = cur_cell->x;
					int area1 = cur_cell->area;
					int area2;
					int area3;
					unsigned alpha1;
					unsigned alpha2;
					unsigned alpha3;
 
					int last_cover = cover3;
					cover = cover3;
					cover += cur_cell->cover;
 
					while(--num_cells)
					{
						cur_cell = *++cells;
						if(cur_cell->x != x) break;
						area1  += cur_cell->area;
						cover += cur_cell->cover;
					}
					
					if (x % 3 == 0)
					{
						if (cur_cell->x == x + 1)
						{
							area2 = cur_cell->area;
							cover2 = cover + cur_cell->cover;
							
							while (--num_cells)
							{
								cur_cell = *++cells;
								if (cur_cell->x != x+1) break;
								area2 += cur_cell->area;
								cover2 += cur_cell->cover;
							}
						}
						else
						{
							area2 = 0;
							cover2 = cover;
						}
						
						if (cur_cell->x == x + 2)
						{
							area3 = cur_cell->area;
							cover3 = cover2 + cur_cell->cover;
							
							while (--num_cells)
							{
								cur_cell = *++cells;
								if (cur_cell->x != x+2) break;
								area3 += cur_cell->area;
								cover3 += cur_cell->cover;
							}
						}
						else
						{
							area3 = 0;
							cover3 = cover2;
						}
					}
					else if (x % 3 == 1)
					{
						area2 = area1;
						area1 = 0;
						cover2 = cover;
						cover = last_cover;
						if (cur_cell->x == x+1)
						{
							area3 = cur_cell->area;
							cover3 = cover2 + cur_cell->cover;
							
							while (--num_cells)
							{
								cur_cell = *++cells;
								if (cur_cell->x != x+1) break;
								area3 += cur_cell->area;
								cover3 += cur_cell->cover;
							}
						}
						else
						{
							area3 = 0;
							cover3 = cover2;
						}
					}
					else // if (x % 3 == 2)
					{
						area3 = area1;
						area2 = 0;
						area1 = 0;
						cover3 = cover;
						cover = last_cover;
						cover2 = last_cover;
					}
					
					alpha1 = area1 ? calculate_alpha((cover 
						<< (poly_subpixel_shift + 1)) - area1) : 0;
					alpha2 = area2 ? calculate_alpha((cover2 
						<< (poly_subpixel_shift + 1)) - area2) : 0;
					alpha3 = area3 ? calculate_alpha((cover3 
						<< (poly_subpixel_shift + 1)) - area3) : 0;
					if(alpha1 || alpha2 || alpha3)
					{
						x += 3 - (x % 3);
						if (area1 && !area2 && area3)
						{
							alpha2 = calculate_alpha(cover
								<< (poly_subpixel_shift + 1));
						}
						else if (num_cells && cur_cell->x >= x)
						{
							if (area1 && !area2)
							{
								alpha2 = calculate_alpha(cover
									<< (poly_subpixel_shift + 1));
								alpha3 = alpha2;
							}
							if (area2 && !area3)
							{
								alpha3 = calculate_alpha(cover2
									<< (poly_subpixel_shift + 1));
							}
						}
						if (!area1)
						{
							if (area2)
							{
								alpha1 = calculate_alpha(cover
									<< (poly_subpixel_shift + 1));
							}
							else if (area3)
							{
								alpha2 = calculate_alpha(cover
									<< (poly_subpixel_shift + 1));
								alpha1 = alpha2;
							}
						}
						sl.add_cell(x / 3 - 1, alpha1, alpha2, alpha3);
					}
					
					if (num_cells && cur_cell->x - x >= 3)
					{
						alpha1 = calculate_alpha(cover3
							<< (poly_subpixel_shift + 1));
						sl.add_span(x / 3, cur_cell->x / 3 - x / 3, alpha1);
					}
				}
		
				if(sl.num_spans()) break;
				++m_scan_y;
			}
 
			sl.finalize(m_scan_y);
			++m_scan_y;
			return true;
		}
 
		//--------------------------------------------------------------------
		bool hit_test(int tx, int ty);
 
 
	private:
		//--------------------------------------------------------------------
		// Disable copying
		rasterizer_scanline_aa_subpix(const rasterizer_scanline_aa_subpix<Clip>&);
		const rasterizer_scanline_aa_subpix<Clip>& 
		operator = (const rasterizer_scanline_aa_subpix<Clip>&);
 
	private:
		rasterizer_cells_aa<cell_aa> m_outline;
		clip_type	   m_clipper;
		int			   m_gamma[aa_scale];
		filling_rule_e m_filling_rule;
		bool		   m_auto_close;
		coord_type	   m_start_x;
		coord_type	   m_start_y;
		unsigned	   m_status;
		int			   m_scan_y;
	};
 
 
 
 
 
 
 
 
 
 
 
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::reset() 
	{ 
		m_outline.reset(); 
		m_status = status_initial;
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::filling_rule(filling_rule_e filling_rule) 
	{ 
		m_filling_rule = filling_rule; 
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::clip_box(double x1, double y1, 
												double x2, double y2)
	{
		reset();
		m_clipper.clip_box(3 * conv_type::downscale(x1), conv_type::upscale(y1), 
						   conv_type::upscale(3 * x2), conv_type::upscale(y2));
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::reset_clipping()
	{
		reset();
		m_clipper.reset_clipping();
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::close_polygon()
	{
		if(m_status == status_line_to)
		{
			m_clipper.line_to(m_outline, m_start_x, m_start_y);
			m_status = status_closed;
		}
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::move_to(int x, int y)
	{
		if(m_outline.sorted()) reset();
		if(m_auto_close) close_polygon();
		m_clipper.move_to(m_start_x = conv_type::downscale(x), 
						  m_start_y = conv_type::downscale(y));
		m_status = status_move_to;
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::line_to(int x, int y)
	{
		m_clipper.line_to(m_outline, 
						  conv_type::downscale(x), 
						  conv_type::downscale(y));
		m_status = status_line_to;
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::move_to_d(double x, double y) 
	{ 
		if(m_outline.sorted()) reset();
		if(m_auto_close) close_polygon();
		m_clipper.move_to(m_start_x = conv_type::upscale(x), 
						  m_start_y = conv_type::upscale(y)); 
		m_status = status_move_to;
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::line_to_d(double x, double y) 
	{ 
		m_clipper.line_to(m_outline, 
						  conv_type::upscale(x), 
						  conv_type::upscale(y)); 
		m_status = status_line_to;
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::add_vertex(double x, double y, unsigned cmd)
	{
		if(is_move_to(cmd)) 
		{
			move_to_d(x, y);
		}
		else 
		if(is_vertex(cmd))
		{
			line_to_d(x, y);
		}
		else
		if(is_close(cmd))
		{
			close_polygon();
		}
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::edge(int x1, int y1, int x2, int y2)
	{
		if(m_outline.sorted()) reset();
		m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1));
		m_clipper.line_to(m_outline, 
						  conv_type::downscale(x2), 
						  conv_type::downscale(y2));
		m_status = status_move_to;
	}
	
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::edge_d(double x1, double y1, 
											  double x2, double y2)
	{
		if(m_outline.sorted()) reset();
		m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); 
		m_clipper.line_to(m_outline, 
						  conv_type::upscale(x2), 
						  conv_type::upscale(y2)); 
		m_status = status_move_to;
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	void rasterizer_scanline_aa_subpix<Clip>::sort()
	{
		m_outline.sort_cells();
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	AGG_INLINE bool rasterizer_scanline_aa_subpix<Clip>::rewind_scanlines()
	{
		if(m_auto_close) close_polygon();
		m_outline.sort_cells();
		if(m_outline.total_cells() == 0) 
		{
			return false;
		}
		m_scan_y = m_outline.min_y();
		return true;
	}
 
 
	//------------------------------------------------------------------------
	template<class Clip> 
	AGG_INLINE bool rasterizer_scanline_aa_subpix<Clip>::navigate_scanline(int y)
	{
		if(m_auto_close) close_polygon();
		m_outline.sort_cells();
		if(m_outline.total_cells() == 0 || 
		   y < m_outline.min_y() || 
		   y > m_outline.max_y()) 
		{
			return false;
		}
		m_scan_y = y;
		return true;
	}
 
	//------------------------------------------------------------------------
	template<class Clip> 
	bool rasterizer_scanline_aa_subpix<Clip>::hit_test(int tx, int ty)
	{
		if(!navigate_scanline(ty)) return false;
		scanline_hit_test sl(tx);
		sweep_scanline(sl);
		return sl.hit();
	}
 
 
 
}
 
 
 
#endif
 

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: m_scan_y.