/*
* 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.