agg/examples/svg_viewer/agg_svg_path_renderer.h

328 lines
11 KiB
C++

//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.3
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
// Copyright (c) 2008 Rene Rebe <rene@exactcode.de> [arc parser code]
// Copyright (c) 2017 John Horigan <john@glyphic.com> [align_subpath()]
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
//
// SVG path renderer.
//
//----------------------------------------------------------------------------
#ifndef AGG_SVG_PATH_RENDERER_INCLUDED
#define AGG_SVG_PATH_RENDERER_INCLUDED
#include "agg_path_storage.h"
#include "agg_conv_transform.h"
#include "agg_conv_stroke.h"
#include "agg_conv_contour.h"
#include "agg_conv_curve.h"
#include "agg_color_rgba.h"
#include "agg_renderer_scanline.h"
#include "agg_bounding_rect.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_svg_path_tokenizer.h"
namespace agg
{
namespace svg
{
template<class VertexSource> class conv_count
{
public:
conv_count(VertexSource& vs) : m_source(&vs), m_count(0) {}
void count(unsigned n) { m_count = n; }
unsigned count() const { return m_count; }
void rewind(unsigned path_id) { m_source->rewind(path_id); }
unsigned vertex(double* x, double* y)
{
++m_count;
return m_source->vertex(x, y);
}
private:
VertexSource* m_source;
unsigned m_count;
};
//============================================================================
// Basic path attributes
struct path_attributes
{
unsigned index;
rgba8 fill_color;
rgba8 stroke_color;
bool fill_flag;
bool stroke_flag;
bool even_odd_flag;
line_join_e line_join;
line_cap_e line_cap;
double miter_limit;
double stroke_width;
trans_affine transform;
// Empty constructor
path_attributes() :
index(0),
fill_color(rgba(0,0,0)),
stroke_color(rgba(0,0,0)),
fill_flag(true),
stroke_flag(false),
even_odd_flag(false),
line_join(miter_join),
line_cap(butt_cap),
miter_limit(4.0),
stroke_width(1.0),
transform()
{
}
// Copy constructor
path_attributes(const path_attributes& attr) :
index(attr.index),
fill_color(attr.fill_color),
stroke_color(attr.stroke_color),
fill_flag(attr.fill_flag),
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
line_join(attr.line_join),
line_cap(attr.line_cap),
miter_limit(attr.miter_limit),
stroke_width(attr.stroke_width),
transform(attr.transform)
{
}
// Copy constructor with new index value
path_attributes(const path_attributes& attr, unsigned idx) :
index(idx),
fill_color(attr.fill_color),
stroke_color(attr.stroke_color),
fill_flag(attr.fill_flag),
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
line_join(attr.line_join),
line_cap(attr.line_cap),
miter_limit(attr.miter_limit),
stroke_width(attr.stroke_width),
transform(attr.transform)
{
}
};
//============================================================================
// Path container and renderer.
class path_renderer
{
public:
typedef pod_bvector<path_attributes> attr_storage;
typedef conv_curve<path_storage> curved;
typedef conv_count<curved> curved_count;
typedef conv_stroke<curved_count> curved_stroked;
typedef conv_transform<curved_stroked> curved_stroked_trans;
typedef conv_transform<curved_count> curved_trans;
typedef conv_contour<curved_trans> curved_trans_contour;
path_renderer();
void remove_all();
// Use these functions as follows:
// begin_path() when the XML tag <path> comes ("start_element" handler)
// parse_path() on "d=" tag attribute
// end_path() when parsing of the entire tag is done.
void begin_path();
void parse_path(path_tokenizer& tok);
void end_path();
// The following functions are essentially a "reflection" of
// the respective SVG path commands.
void move_to(double x, double y, bool rel=false); // M, m
void line_to(double x, double y, bool rel=false); // L, l
void hline_to(double x, bool rel=false); // H, h
void vline_to(double y, bool rel=false); // V, v
void curve3(double x1, double y1, // Q, q
double x, double y, bool rel=false);
void curve3(double x, double y, bool rel=false); // T, t
void curve4(double x1, double y1, // C, c
double x2, double y2,
double x, double y, bool rel=false);
void curve4(double x2, double y2, // S, s
double x, double y, bool rel=false);
void arc(double rx, double ry, double angle, // A, a
bool large_arc_flag, bool sweep_flag, double x, double y,
bool rel=false);
void close_subpath(); // Z, z
void align_subpath(unsigned start_idx);
// template<class VertexSource>
// void add_path(VertexSource& vs,
// unsigned path_id = 0,
// bool solid_path = true)
// {
// m_storage.add_path(vs, path_id, solid_path);
// }
unsigned vertex_count() const { return m_curved_count.count(); }
// Call these functions on <g> tag (start_element, end_element respectively)
void push_attr();
void pop_attr();
// Attribute setting functions.
void fill(const rgba8& f);
void stroke(const rgba8& s);
void even_odd(bool flag);
void stroke_width(double w);
void fill_none();
void stroke_none();
void fill_opacity(double op);
void stroke_opacity(double op);
void line_join(line_join_e join);
void line_cap(line_cap_e cap);
void miter_limit(double ml);
trans_affine& transform();
// Make all polygons CCW-oriented
void arrange_orientations()
{
m_storage.arrange_orientations_all_paths(path_flags_ccw);
}
// Expand all polygons
void expand(double value)
{
m_curved_trans_contour.width(value);
}
unsigned operator [](unsigned idx)
{
m_transform = m_attr_storage[idx].transform;
return m_attr_storage[idx].index;
}
void bounding_rect(double* x1, double* y1, double* x2, double* y2)
{
agg::conv_transform<agg::path_storage> trans(m_storage, m_transform);
agg::bounding_rect(trans, *this, 0, m_attr_storage.size(), x1, y1, x2, y2);
}
// Rendering. One can specify two additional parameters:
// trans_affine and opacity. They can be used to transform the whole
// image and/or to make it translucent.
template<class Rasterizer, class Scanline, class Renderer>
void render(Rasterizer& ras,
Scanline& sl,
Renderer& ren,
const trans_affine& mtx,
const rect_i& cb,
double opacity=1.0)
{
unsigned i;
ras.clip_box(cb.x1, cb.y1, cb.x2, cb.y2);
m_curved_count.count(0);
for(i = 0; i < m_attr_storage.size(); i++)
{
const path_attributes& attr = m_attr_storage[i];
m_transform = attr.transform;
m_transform *= mtx;
double scl = m_transform.scale();
//m_curved.approximation_method(curve_inc);
m_curved.approximation_scale(scl);
m_curved.angle_tolerance(0.0);
rgba8 color;
if(attr.fill_flag)
{
ras.reset();
ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero);
if(fabs(m_curved_trans_contour.width()) < 0.0001)
{
ras.add_path(m_curved_trans, attr.index);
}
else
{
m_curved_trans_contour.miter_limit(attr.miter_limit);
ras.add_path(m_curved_trans_contour, attr.index);
}
color = attr.fill_color;
color.opacity(color.opacity() * opacity);
ren.color(color);
agg::render_scanlines(ras, sl, ren);
}
if(attr.stroke_flag)
{
m_curved_stroked.width(attr.stroke_width);
//m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join);
m_curved_stroked.line_join(attr.line_join);
m_curved_stroked.line_cap(attr.line_cap);
m_curved_stroked.miter_limit(attr.miter_limit);
m_curved_stroked.inner_join(inner_round);
m_curved_stroked.approximation_scale(scl);
// If the *visual* line width is considerable we
// turn on processing of curve cusps.
//---------------------
if(attr.stroke_width * scl > 1.0)
{
m_curved.angle_tolerance(0.2);
}
ras.reset();
ras.filling_rule(fill_non_zero);
ras.add_path(m_curved_stroked_trans, attr.index);
color = attr.stroke_color;
color.opacity(color.opacity() * opacity);
ren.color(color);
agg::render_scanlines(ras, sl, ren);
}
}
}
private:
path_attributes& cur_attr();
path_storage m_storage;
attr_storage m_attr_storage;
attr_storage m_attr_stack;
trans_affine m_transform;
curved m_curved;
curved_count m_curved_count;
curved_stroked m_curved_stroked;
curved_stroked_trans m_curved_stroked_trans;
curved_trans m_curved_trans;
curved_trans_contour m_curved_trans_contour;
};
}
}
#endif