You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1224 lines
37 KiB
1224 lines
37 KiB
//---------------------------------------------------------------------------- |
|
// Agg2D - Version 1.0 |
|
// Based on Anti-Grain Geometry |
|
// Copyright (C) 2005 Maxim Shemanarev (http://www.antigrain.com) |
|
// |
|
// 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 |
|
//---------------------------------------------------------------------------- |
|
//---------------------------------------------------------------------------- |
|
// |
|
// 2007-01-25 Jerry Evans (jerry@novadsp.com) |
|
// Ported to AGG 2.4 |
|
// |
|
// 2008-09-25 Jim Barry (jim@mvps.org) |
|
// Fixed errors in kerning |
|
// |
|
//---------------------------------------------------------------------------- |
|
|
|
#include "agg2d.h" |
|
|
|
static const double g_approxScale = 2.0; |
|
|
|
Agg2D::~Agg2D() |
|
{ |
|
} |
|
|
|
Agg2D::Agg2D() : |
|
m_rbuf(), |
|
m_pixFormat(m_rbuf), |
|
m_pixFormatComp(m_rbuf), |
|
m_pixFormatPre(m_rbuf), |
|
m_pixFormatCompPre(m_rbuf), |
|
m_renBase(m_pixFormat), |
|
m_renBaseComp(m_pixFormatComp), |
|
m_renBasePre(m_pixFormatPre), |
|
m_renBaseCompPre(m_pixFormatCompPre), |
|
m_renSolid(m_renBase), |
|
m_renSolidComp(m_renBaseComp), |
|
|
|
m_allocator(), |
|
m_clipBox(0,0,0,0), |
|
|
|
m_blendMode(BlendAlpha), |
|
|
|
m_scanline(), |
|
m_rasterizer(), |
|
|
|
m_masterAlpha(1.0), |
|
m_antiAliasGamma(1.0), |
|
|
|
m_fillColor(255, 255, 255), |
|
m_lineColor(0, 0, 0), |
|
m_fillGradient(), |
|
m_lineGradient(), |
|
|
|
m_lineCap(CapRound), |
|
m_lineJoin(JoinRound), |
|
|
|
m_fillGradientFlag(Solid), |
|
m_lineGradientFlag(Solid), |
|
m_fillGradientMatrix(), |
|
m_lineGradientMatrix(), |
|
m_fillGradientD1(0.0), |
|
m_lineGradientD1(0.0), |
|
m_fillGradientD2(100.0), |
|
m_lineGradientD2(100.0), |
|
|
|
m_fillGradientInterpolator(m_fillGradientMatrix), |
|
m_lineGradientInterpolator(m_lineGradientMatrix), |
|
|
|
m_linearGradientFunction(), |
|
m_radialGradientFunction(), |
|
|
|
m_lineWidth(1), |
|
m_evenOddFlag(false), |
|
|
|
m_path(), |
|
m_transform(), |
|
|
|
m_convCurve(m_path), |
|
m_convStroke(m_convCurve), |
|
|
|
m_pathTransform(m_convCurve, m_transform), |
|
m_strokeTransform(m_convStroke, m_transform) |
|
{ |
|
lineCap(m_lineCap); |
|
lineJoin(m_lineJoin); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::attach(unsigned char* buf, unsigned width, unsigned height, int stride) |
|
{ |
|
m_rbuf.attach(buf, width, height, stride); |
|
|
|
m_renBase.reset_clipping(true); |
|
m_renBaseComp.reset_clipping(true); |
|
m_renBasePre.reset_clipping(true); |
|
m_renBaseCompPre.reset_clipping(true); |
|
|
|
resetTransformations(); |
|
lineWidth(1.0), |
|
lineColor(0,0,0); |
|
fillColor(255,255,255); |
|
clipBox(0, 0, width, height); |
|
lineCap(CapRound); |
|
lineJoin(JoinRound); |
|
m_masterAlpha = 1.0; |
|
m_antiAliasGamma = 1.0; |
|
m_rasterizer.gamma(agg::gamma_none()); |
|
m_blendMode = BlendAlpha; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::clipBox(double x1, double y1, double x2, double y2) |
|
{ |
|
m_clipBox = RectD(x1, y1, x2, y2); |
|
int rx1 = int(x1); |
|
int ry1 = int(y1); |
|
int rx2 = int(x2); |
|
int ry2 = int(y2); |
|
|
|
m_renBase.clip_box(rx1, ry1, rx2, ry2); |
|
m_renBaseComp.clip_box(rx1, ry1, rx2, ry2); |
|
m_renBasePre.clip_box(rx1, ry1, rx2, ry2); |
|
m_renBaseCompPre.clip_box(rx1, ry1, rx2, ry2); |
|
|
|
m_rasterizer.clip_box(x1, y1, x2, y2); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::blendMode(BlendMode m) |
|
{ |
|
m_blendMode = m; |
|
m_pixFormatComp.comp_op(m); |
|
m_pixFormatCompPre.comp_op(m); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
Agg2D::BlendMode Agg2D::blendMode() const |
|
{ |
|
return m_blendMode; |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::masterAlpha(double a) |
|
{ |
|
m_masterAlpha = a; |
|
updateRasterizerGamma(); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
double Agg2D::masterAlpha() const |
|
{ |
|
return m_masterAlpha; |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::antiAliasGamma(double g) |
|
{ |
|
m_antiAliasGamma = g; |
|
updateRasterizerGamma(); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
double Agg2D::antiAliasGamma() const |
|
{ |
|
return m_antiAliasGamma; |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
Agg2D::RectD Agg2D::clipBox() const |
|
{ |
|
return m_clipBox; |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::clearAll(Color c) |
|
{ |
|
m_renBase.clear(c); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::clearAll(unsigned r, unsigned g, unsigned b, unsigned a) |
|
{ |
|
clearAll(Color(r, g, b, a)); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::clearClipBox(Color c) |
|
{ |
|
m_renBase.copy_bar(0, 0, m_renBase.width(), m_renBase.height(), c); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::clearClipBox(unsigned r, unsigned g, unsigned b, unsigned a) |
|
{ |
|
clearClipBox(Color(r, g, b, a)); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::worldToScreen(double& x, double& y) const |
|
{ |
|
m_transform.transform(&x, &y); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::screenToWorld(double& x, double& y) const |
|
{ |
|
m_transform.inverse_transform(&x, &y); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
double Agg2D::worldToScreen(double scalar) const |
|
{ |
|
double x1 = 0; |
|
double y1 = 0; |
|
double x2 = scalar; |
|
double y2 = scalar; |
|
worldToScreen(x1, y1); |
|
worldToScreen(x2, y2); |
|
return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * 0.7071068; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
double Agg2D::screenToWorld(double scalar) const |
|
{ |
|
double x1 = 0; |
|
double y1 = 0; |
|
double x2 = scalar; |
|
double y2 = scalar; |
|
screenToWorld(x1, y1); |
|
screenToWorld(x2, y2); |
|
return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * 0.7071068; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::alignPoint(double& x, double& y) const |
|
{ |
|
worldToScreen(x, y); |
|
x = floor(x) + 0.5; |
|
y = floor(y) + 0.5; |
|
screenToWorld(x, y); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
bool Agg2D::inBox(double worldX, double worldY) const |
|
{ |
|
worldToScreen(worldX, worldY); |
|
return m_renBase.inbox(int(worldX), int(worldY)); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
Agg2D::Transformations Agg2D::transformations() const |
|
{ |
|
Transformations tr; |
|
m_transform.store_to(tr.affineMatrix); |
|
return tr; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::transformations(const Transformations& tr) |
|
{ |
|
m_transform.load_from(tr.affineMatrix); |
|
m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::resetTransformations() |
|
{ |
|
m_transform.reset(); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::rotate(double angle) { m_transform *= agg::trans_affine_rotation(angle); } |
|
void Agg2D::skew(double sx, double sy) { m_transform *= agg::trans_affine_skewing(sx, sy); } |
|
void Agg2D::translate(double x, double y) { m_transform *= agg::trans_affine_translation(x, y); } |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::affine(const Affine& tr) |
|
{ |
|
m_transform *= tr; |
|
m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::affine(const Transformations& tr) |
|
{ |
|
affine(agg::trans_affine(tr.affineMatrix[0], tr.affineMatrix[1], tr.affineMatrix[2], |
|
tr.affineMatrix[3], tr.affineMatrix[4], tr.affineMatrix[5])); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::scale(double sx, double sy) |
|
{ |
|
m_transform *= agg::trans_affine_scaling(sx, sy); |
|
m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::parallelogram(double x1, double y1, double x2, double y2, const double* para) |
|
{ |
|
m_transform *= agg::trans_affine(x1, y1, x2, y2, para); |
|
m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::viewport(double worldX1, double worldY1, double worldX2, double worldY2, |
|
double screenX1, double screenY1, double screenX2, double screenY2, |
|
ViewportOption opt) |
|
{ |
|
agg::trans_viewport vp; |
|
switch(opt) |
|
{ |
|
case Anisotropic: vp.preserve_aspect_ratio(0.0, 0.0, agg::aspect_ratio_stretch); break; |
|
case XMinYMin: vp.preserve_aspect_ratio(0.0, 0.0, agg::aspect_ratio_meet); break; |
|
case XMidYMin: vp.preserve_aspect_ratio(0.5, 0.0, agg::aspect_ratio_meet); break; |
|
case XMaxYMin: vp.preserve_aspect_ratio(1.0, 0.0, agg::aspect_ratio_meet); break; |
|
case XMinYMid: vp.preserve_aspect_ratio(0.0, 0.5, agg::aspect_ratio_meet); break; |
|
case XMidYMid: vp.preserve_aspect_ratio(0.5, 0.5, agg::aspect_ratio_meet); break; |
|
case XMaxYMid: vp.preserve_aspect_ratio(1.0, 0.5, agg::aspect_ratio_meet); break; |
|
case XMinYMax: vp.preserve_aspect_ratio(0.0, 1.0, agg::aspect_ratio_meet); break; |
|
case XMidYMax: vp.preserve_aspect_ratio(0.5, 1.0, agg::aspect_ratio_meet); break; |
|
case XMaxYMax: vp.preserve_aspect_ratio(1.0, 1.0, agg::aspect_ratio_meet); break; |
|
} |
|
vp.world_viewport(worldX1, worldY1, worldX2, worldY2); |
|
vp.device_viewport(screenX1, screenY1, screenX2, screenY2); |
|
m_transform *= vp.to_affine(); |
|
m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::fillColor(Color c) |
|
{ |
|
m_fillColor = c; |
|
m_fillGradientFlag = Solid; |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::fillColor(unsigned r, unsigned g, unsigned b, unsigned a) |
|
{ |
|
fillColor(Color(r, g, b, a)); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::noFill() |
|
{ |
|
fillColor(Color(0, 0, 0, 0)); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineColor(Color c) |
|
{ |
|
m_lineColor = c; |
|
m_lineGradientFlag = Solid; |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineColor(unsigned r, unsigned g, unsigned b, unsigned a) |
|
{ |
|
lineColor(Color(r, g, b, a)); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::noLine() |
|
{ |
|
lineColor(Color(0, 0, 0, 0)); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
Agg2D::Color Agg2D::fillColor() const |
|
{ |
|
return m_fillColor; |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
Agg2D::Color Agg2D::lineColor() const |
|
{ |
|
return m_lineColor; |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::fillLinearGradient(double x1, double y1, double x2, double y2, Color c1, Color c2, double profile) |
|
{ |
|
int i; |
|
int startGradient = 128 - int(profile * 127.0); |
|
int endGradient = 128 + int(profile * 127.0); |
|
if (endGradient <= startGradient) endGradient = startGradient + 1; |
|
double k = 1.0 / double(endGradient - startGradient); |
|
for (i = 0; i < startGradient; i++) |
|
{ |
|
m_fillGradient[i] = c1; |
|
} |
|
for (; i < endGradient; i++) |
|
{ |
|
m_fillGradient[i] = c1.gradient(c2, double(i - startGradient) * k); |
|
} |
|
for (; i < 256; i++) |
|
{ |
|
m_fillGradient[i] = c2; |
|
} |
|
double angle = atan2(y2-y1, x2-x1); |
|
m_fillGradientMatrix.reset(); |
|
m_fillGradientMatrix *= agg::trans_affine_rotation(angle); |
|
m_fillGradientMatrix *= agg::trans_affine_translation(x1, y1); |
|
m_fillGradientMatrix *= m_transform; |
|
m_fillGradientMatrix.invert(); |
|
m_fillGradientD1 = 0.0; |
|
m_fillGradientD2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1)); |
|
m_fillGradientFlag = Linear; |
|
m_fillColor = Color(0,0,0); // Set some real color |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineLinearGradient(double x1, double y1, double x2, double y2, Color c1, Color c2, double profile) |
|
{ |
|
int i; |
|
int startGradient = 128 - int(profile * 128.0); |
|
int endGradient = 128 + int(profile * 128.0); |
|
if (endGradient <= startGradient) endGradient = startGradient + 1; |
|
double k = 1.0 / double(endGradient - startGradient); |
|
for (i = 0; i < startGradient; i++) |
|
{ |
|
m_lineGradient[i] = c1; |
|
} |
|
for (; i < endGradient; i++) |
|
{ |
|
m_lineGradient[i] = c1.gradient(c2, double(i - startGradient) * k); |
|
} |
|
for (; i < 256; i++) |
|
{ |
|
m_lineGradient[i] = c2; |
|
} |
|
double angle = atan2(y2-y1, x2-x1); |
|
m_lineGradientMatrix.reset(); |
|
m_lineGradientMatrix *= agg::trans_affine_rotation(angle); |
|
m_lineGradientMatrix *= agg::trans_affine_translation(x1, y1); |
|
m_fillGradientMatrix *= m_transform; |
|
m_lineGradientMatrix.invert(); |
|
m_lineGradientD1 = 0; |
|
m_lineGradientD2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1)); |
|
m_lineGradientFlag = Linear; |
|
m_lineColor = Color(0,0,0); // Set some real color |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::fillRadialGradient(double x, double y, double r, Color c1, Color c2, double profile) |
|
{ |
|
int i; |
|
int startGradient = 128 - int(profile * 127.0); |
|
int endGradient = 128 + int(profile * 127.0); |
|
if (endGradient <= startGradient) endGradient = startGradient + 1; |
|
double k = 1.0 / double(endGradient - startGradient); |
|
for (i = 0; i < startGradient; i++) |
|
{ |
|
m_fillGradient[i] = c1; |
|
} |
|
for (; i < endGradient; i++) |
|
{ |
|
m_fillGradient[i] = c1.gradient(c2, double(i - startGradient) * k); |
|
} |
|
for (; i < 256; i++) |
|
{ |
|
m_fillGradient[i] = c2; |
|
} |
|
m_fillGradientD2 = worldToScreen(r); |
|
worldToScreen(x, y); |
|
m_fillGradientMatrix.reset(); |
|
m_fillGradientMatrix *= agg::trans_affine_translation(x, y); |
|
m_fillGradientMatrix.invert(); |
|
m_fillGradientD1 = 0; |
|
m_fillGradientFlag = Radial; |
|
m_fillColor = Color(0,0,0); // Set some real color |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineRadialGradient(double x, double y, double r, Color c1, Color c2, double profile) |
|
{ |
|
int i; |
|
int startGradient = 128 - int(profile * 128.0); |
|
int endGradient = 128 + int(profile * 128.0); |
|
if (endGradient <= startGradient) endGradient = startGradient + 1; |
|
double k = 1.0 / double(endGradient - startGradient); |
|
for (i = 0; i < startGradient; i++) |
|
{ |
|
m_lineGradient[i] = c1; |
|
} |
|
for (; i < endGradient; i++) |
|
{ |
|
m_lineGradient[i] = c1.gradient(c2, double(i - startGradient) * k); |
|
} |
|
for (; i < 256; i++) |
|
{ |
|
m_lineGradient[i] = c2; |
|
} |
|
m_lineGradientD2 = worldToScreen(r); |
|
worldToScreen(x, y); |
|
m_lineGradientMatrix.reset(); |
|
m_lineGradientMatrix *= agg::trans_affine_translation(x, y); |
|
m_lineGradientMatrix.invert(); |
|
m_lineGradientD1 = 0; |
|
m_lineGradientFlag = Radial; |
|
m_lineColor = Color(0,0,0); // Set some real color |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::fillRadialGradient(double x, double y, double r, Color c1, Color c2, Color c3) |
|
{ |
|
int i; |
|
for (i = 0; i < 128; i++) |
|
{ |
|
m_fillGradient[i] = c1.gradient(c2, double(i) / 127.0); |
|
} |
|
for (; i < 256; i++) |
|
{ |
|
m_fillGradient[i] = c2.gradient(c3, double(i - 128) / 127.0); |
|
} |
|
m_fillGradientD2 = worldToScreen(r); |
|
worldToScreen(x, y); |
|
m_fillGradientMatrix.reset(); |
|
m_fillGradientMatrix *= agg::trans_affine_translation(x, y); |
|
m_fillGradientMatrix.invert(); |
|
m_fillGradientD1 = 0; |
|
m_fillGradientFlag = Radial; |
|
m_fillColor = Color(0,0,0); // Set some real color |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineRadialGradient(double x, double y, double r, Color c1, Color c2, Color c3) |
|
{ |
|
int i; |
|
for (i = 0; i < 128; i++) |
|
{ |
|
m_lineGradient[i] = c1.gradient(c2, double(i) / 127.0); |
|
} |
|
for (; i < 256; i++) |
|
{ |
|
m_lineGradient[i] = c2.gradient(c3, double(i - 128) / 127.0); |
|
} |
|
m_lineGradientD2 = worldToScreen(r); |
|
worldToScreen(x, y); |
|
m_lineGradientMatrix.reset(); |
|
m_lineGradientMatrix *= agg::trans_affine_translation(x, y); |
|
m_lineGradientMatrix.invert(); |
|
m_lineGradientD1 = 0; |
|
m_lineGradientFlag = Radial; |
|
m_lineColor = Color(0,0,0); // Set some real color |
|
} |
|
|
|
|
|
void Agg2D::fillRadialGradient(double x, double y, double r) |
|
{ |
|
m_fillGradientD2 = worldToScreen(r); |
|
worldToScreen(x, y); |
|
m_fillGradientMatrix.reset(); |
|
m_fillGradientMatrix *= agg::trans_affine_translation(x, y); |
|
m_fillGradientMatrix.invert(); |
|
m_fillGradientD1 = 0; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineRadialGradient(double x, double y, double r) |
|
{ |
|
m_lineGradientD2 = worldToScreen(r); |
|
worldToScreen(x, y); |
|
m_lineGradientMatrix.reset(); |
|
m_lineGradientMatrix *= agg::trans_affine_translation(x, y); |
|
m_lineGradientMatrix.invert(); |
|
m_lineGradientD1 = 0; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineWidth(double w) |
|
{ |
|
m_lineWidth = w; |
|
m_convStroke.width(w); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
double Agg2D::lineWidth(double w) const |
|
{ |
|
return m_lineWidth; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::fillEvenOdd(bool evenOddFlag) |
|
{ |
|
m_evenOddFlag = evenOddFlag; |
|
m_rasterizer.filling_rule(evenOddFlag ? agg::fill_even_odd : agg::fill_non_zero); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
bool Agg2D::fillEvenOdd() const |
|
{ |
|
return m_evenOddFlag; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineCap(LineCap cap) |
|
{ |
|
m_lineCap = cap; |
|
m_convStroke.line_cap((agg::line_cap_e)cap); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
Agg2D::LineCap Agg2D::lineCap() const |
|
{ |
|
return m_lineCap; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineJoin(LineJoin join) |
|
{ |
|
m_lineJoin = join; |
|
m_convStroke.line_join((agg::line_join_e)join); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
Agg2D::LineJoin Agg2D::lineJoin() const |
|
{ |
|
return m_lineJoin; |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::addLine(double x1, double y1, double x2, double y2) |
|
{ |
|
m_path.move_to(x1, y1); |
|
m_path.line_to(x2, y2); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::line(double x1, double y1, double x2, double y2) |
|
{ |
|
m_path.remove_all(); |
|
addLine(x1, y1, x2, y2); |
|
drawPath(StrokeOnly); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::triangle(double x1, double y1, double x2, double y2, double x3, double y3) |
|
{ |
|
m_path.remove_all(); |
|
m_path.move_to(x1, y1); |
|
m_path.line_to(x2, y2); |
|
m_path.line_to(x3, y3); |
|
m_path.close_polygon(); |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::rectangle(double x1, double y1, double x2, double y2) |
|
{ |
|
m_path.remove_all(); |
|
m_path.move_to(x1, y1); |
|
m_path.line_to(x2, y1); |
|
m_path.line_to(x2, y2); |
|
m_path.line_to(x1, y2); |
|
m_path.close_polygon(); |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::roundedRect(double x1, double y1, double x2, double y2, double r) |
|
{ |
|
m_path.remove_all(); |
|
agg::rounded_rect rc(x1, y1, x2, y2, r); |
|
rc.normalize_radius(); |
|
rc.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
// JME audit |
|
//m_path.add_path(rc, 0, false); |
|
m_path.concat_path(rc,0); |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::roundedRect(double x1, double y1, double x2, double y2, double rx, double ry) |
|
{ |
|
m_path.remove_all(); |
|
agg::rounded_rect rc; |
|
rc.rect(x1, y1, x2, y2); |
|
rc.radius(rx, ry); |
|
rc.normalize_radius(); |
|
//m_path.add_path(rc, 0, false); |
|
m_path.concat_path(rc,0); // JME |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::roundedRect(double x1, double y1, double x2, double y2, |
|
double rx_bottom, double ry_bottom, |
|
double rx_top, double ry_top) |
|
{ |
|
m_path.remove_all(); |
|
agg::rounded_rect rc; |
|
rc.rect(x1, y1, x2, y2); |
|
rc.radius(rx_bottom, ry_bottom, rx_top, ry_top); |
|
rc.normalize_radius(); |
|
rc.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
//m_path.add_path(rc, 0, false); |
|
m_path.concat_path(rc,0); // JME |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::roundedRect(double x1, double y1, double x2, double y2, |
|
double rtlx, double rtly, double rtrx, double rtry, |
|
double rbrx, double rbry, double rblx, double rbly) |
|
{ |
|
m_path.remove_all(); |
|
agg::rounded_rect rc; |
|
rc.rect(x1, y1, x2, y2); |
|
//rc.radius(10, 10, 20, 20, 30, 30, 40, 40); |
|
rc.radius(rtlx, rtly, rtrx, rtry, rblx, rbly, rbrx, rbry); |
|
rc.normalize_radius(); |
|
rc.approximation_scale(worldToScreen(1.0) * g_approxScale); |
|
//m_path.add_path(rc, 0, false); |
|
m_path.concat_path(rc,0); // JME |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::ellipse(double cx, double cy, double rx, double ry) |
|
{ |
|
m_path.remove_all(); |
|
agg::bezier_arc arc(cx, cy, rx, ry, 0, 2*pi()); |
|
//m_path.add_path(arc, 0, false); |
|
m_path.concat_path(arc,0); // JME |
|
m_path.close_polygon(); |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::arc(double cx, double cy, double rx, double ry, double start, double sweep) |
|
{ |
|
m_path.remove_all(); |
|
agg::bezier_arc arc(cx, cy, rx, ry, start, sweep); |
|
//m_path.add_path(arc, 0, false); |
|
m_path.concat_path(arc,0); // JME |
|
drawPath(StrokeOnly); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::star(double cx, double cy, double r1, double r2, double startAngle, int numRays) |
|
{ |
|
m_path.remove_all(); |
|
double da = agg::pi / double(numRays); |
|
double a = startAngle; |
|
int i; |
|
for (i = 0; i < numRays; i++) |
|
{ |
|
double x = cos(a) * r2 + cx; |
|
double y = sin(a) * r2 + cy; |
|
if (i) m_path.line_to(x, y); |
|
else m_path.move_to(x, y); |
|
a += da; |
|
m_path.line_to(cos(a) * r1 + cx, sin(a) * r1 + cy); |
|
a += da; |
|
} |
|
closePolygon(); |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::curve(double x1, double y1, double x2, double y2, double x3, double y3) |
|
{ |
|
m_path.remove_all(); |
|
m_path.move_to(x1, y1); |
|
m_path.curve3(x2, y2, x3, y3); |
|
drawPath(StrokeOnly); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::curve(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) |
|
{ |
|
m_path.remove_all(); |
|
m_path.move_to(x1, y1); |
|
m_path.curve4(x2, y2, x3, y3, x4, y4); |
|
drawPath(StrokeOnly); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::polygon(double* xy, int numPoints) |
|
{ |
|
m_path.remove_all(); |
|
//m_path.add_poly(xy, numPoints); |
|
m_path.concat_poly(xy,0,true); // JME |
|
closePolygon(); |
|
drawPath(FillAndStroke); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::polyline(double* xy, int numPoints) |
|
{ |
|
m_path.remove_all(); |
|
//m_path.add_poly(xy, numPoints); |
|
m_path.concat_poly(xy,0,true); // JME |
|
drawPath(StrokeOnly); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::resetPath() { m_path.remove_all(); } |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::moveTo(double x, double y) |
|
{ |
|
m_path.move_to(x, y); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::moveRel(double dx, double dy) |
|
{ |
|
m_path.move_rel(dx, dy); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineTo(double x, double y) |
|
{ |
|
m_path.line_to(x, y); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::lineRel(double dx, double dy) |
|
{ |
|
m_path.line_rel(dx, dy); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::horLineTo(double x) |
|
{ |
|
m_path.hline_to(x); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::horLineRel(double dx) |
|
{ |
|
m_path.hline_rel(dx); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::verLineTo(double y) |
|
{ |
|
m_path.vline_to(y); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::verLineRel(double dy) |
|
{ |
|
m_path.vline_rel(dy); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::arcTo(double rx, double ry, |
|
double angle, |
|
bool largeArcFlag, |
|
bool sweepFlag, |
|
double x, double y) |
|
{ |
|
m_path.arc_to(rx, ry, angle, largeArcFlag, sweepFlag, x, y); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::arcRel(double rx, double ry, |
|
double angle, |
|
bool largeArcFlag, |
|
bool sweepFlag, |
|
double dx, double dy) |
|
{ |
|
m_path.arc_rel(rx, ry, angle, largeArcFlag, sweepFlag, dx, dy); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::quadricCurveTo(double xCtrl, double yCtrl, |
|
double xTo, double yTo) |
|
{ |
|
m_path.curve3(xCtrl, yCtrl, xTo, yTo); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::quadricCurveRel(double dxCtrl, double dyCtrl, |
|
double dxTo, double dyTo) |
|
{ |
|
m_path.curve3_rel(dxCtrl, dyCtrl, dxTo, dyTo); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::quadricCurveTo(double xTo, double yTo) |
|
{ |
|
m_path.curve3(xTo, yTo); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::quadricCurveRel(double dxTo, double dyTo) |
|
{ |
|
m_path.curve3_rel(dxTo, dyTo); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::cubicCurveTo(double xCtrl1, double yCtrl1, |
|
double xCtrl2, double yCtrl2, |
|
double xTo, double yTo) |
|
{ |
|
m_path.curve4(xCtrl1, yCtrl1, xCtrl2, yCtrl2, xTo, yTo); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::cubicCurveRel(double dxCtrl1, double dyCtrl1, |
|
double dxCtrl2, double dyCtrl2, |
|
double dxTo, double dyTo) |
|
{ |
|
m_path.curve4_rel(dxCtrl1, dyCtrl1, dxCtrl2, dyCtrl2, dxTo, dyTo); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::cubicCurveTo(double xCtrl2, double yCtrl2, |
|
double xTo, double yTo) |
|
{ |
|
m_path.curve4(xCtrl2, yCtrl2, xTo, yTo); |
|
} |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::cubicCurveRel(double xCtrl2, double yCtrl2, |
|
double xTo, double yTo) |
|
{ |
|
m_path.curve4_rel(xCtrl2, yCtrl2, xTo, yTo); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::addEllipse(double cx, double cy, double rx, double ry, Direction dir) |
|
{ |
|
agg::bezier_arc arc(cx, cy, rx, ry, 0, (dir == CCW) ? 2*pi() : -2*pi()); |
|
//m_path.add_path(arc, 0, false); |
|
m_path.concat_path(arc,0); // JME |
|
m_path.close_polygon(); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::closePolygon() |
|
{ |
|
m_path.close_polygon(); |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::drawPath(DrawPathFlag flag) |
|
{ |
|
m_rasterizer.reset(); |
|
switch(flag) |
|
{ |
|
case FillOnly: |
|
if (m_fillColor.a) |
|
{ |
|
m_rasterizer.add_path(m_pathTransform); |
|
render(true); |
|
} |
|
break; |
|
|
|
case StrokeOnly: |
|
if (m_lineColor.a && m_lineWidth > 0.0) |
|
{ |
|
m_rasterizer.add_path(m_strokeTransform); |
|
render(false); |
|
} |
|
break; |
|
|
|
case FillAndStroke: |
|
if (m_fillColor.a) |
|
{ |
|
m_rasterizer.add_path(m_pathTransform); |
|
render(true); |
|
} |
|
|
|
if (m_lineColor.a && m_lineWidth > 0.0) |
|
{ |
|
m_rasterizer.add_path(m_strokeTransform); |
|
render(false); |
|
} |
|
break; |
|
|
|
case FillWithLineColor: |
|
if (m_lineColor.a) |
|
{ |
|
m_rasterizer.add_path(m_pathTransform); |
|
render(false); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
|
|
|
|
//------------------------------------------------------------------------ |
|
class Agg2DRenderer |
|
{ |
|
public: |
|
//-------------------------------------------------------------------- |
|
template<class BaseRenderer, class SolidRenderer> |
|
void static render(Agg2D& gr, BaseRenderer& renBase, SolidRenderer& renSolid, bool fillColor) |
|
{ |
|
// JME |
|
typedef agg::span_allocator<Agg2D::ColorType> span_allocator_type; |
|
//- typedef agg::renderer_scanline_aa<BaseRenderer, Agg2D::LinearGradientSpan> RendererLinearGradient; |
|
typedef agg::renderer_scanline_aa<BaseRenderer, |
|
span_allocator_type, |
|
Agg2D::LinearGradientSpan> RendererLinearGradient; |
|
//- typedef agg::renderer_scanline_aa<BaseRenderer, Agg2D::RadialGradientSpan> RendererRadialGradient; |
|
typedef agg::renderer_scanline_aa<BaseRenderer, |
|
span_allocator_type, |
|
Agg2D::RadialGradientSpan> RendererRadialGradient; |
|
|
|
if ((fillColor && gr.m_fillGradientFlag == Agg2D::Linear) || |
|
(!fillColor && gr.m_lineGradientFlag == Agg2D::Linear)) |
|
{ |
|
if (fillColor) |
|
{ |
|
Agg2D::LinearGradientSpan span(/*gr.m_allocator, */ |
|
gr.m_fillGradientInterpolator, |
|
gr.m_linearGradientFunction, |
|
gr.m_fillGradient, |
|
gr.m_fillGradientD1, |
|
gr.m_fillGradientD2); |
|
//-RendererLinearGradient ren(renBase,span); |
|
RendererLinearGradient ren(renBase,gr.m_allocator,span); |
|
agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren); |
|
} |
|
else |
|
{ |
|
Agg2D::LinearGradientSpan span(/*gr.m_allocator,*/ |
|
gr.m_lineGradientInterpolator, |
|
gr.m_linearGradientFunction, |
|
gr.m_lineGradient, |
|
gr.m_lineGradientD1, |
|
gr.m_lineGradientD2); |
|
//- RendererLinearGradient ren(renBase, span); |
|
RendererLinearGradient ren(renBase,gr.m_allocator,span); |
|
agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren); |
|
} |
|
} |
|
else |
|
{ |
|
if ((fillColor && gr.m_fillGradientFlag == Agg2D::Radial) || |
|
(!fillColor && gr.m_lineGradientFlag == Agg2D::Radial)) |
|
{ |
|
if (fillColor) |
|
{ |
|
Agg2D::RadialGradientSpan span(/*gr.m_allocator, */ |
|
gr.m_fillGradientInterpolator, |
|
gr.m_radialGradientFunction, |
|
gr.m_fillGradient, |
|
gr.m_fillGradientD1, |
|
gr.m_fillGradientD2); |
|
//-RendererRadialGradient ren(renBase, span); |
|
RendererRadialGradient ren(renBase,gr.m_allocator,span); |
|
agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren); |
|
} |
|
else |
|
{ |
|
Agg2D::RadialGradientSpan span(/*gr.m_allocator,*/ |
|
gr.m_lineGradientInterpolator, |
|
gr.m_radialGradientFunction, |
|
gr.m_lineGradient, |
|
gr.m_lineGradientD1, |
|
gr.m_lineGradientD2); |
|
//-RendererRadialGradient ren(renBase, span); |
|
RendererRadialGradient ren(renBase,gr.m_allocator,span); |
|
agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren); |
|
} |
|
} |
|
else |
|
{ |
|
renSolid.color(fillColor ? gr.m_fillColor : gr.m_lineColor); |
|
agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, renSolid); |
|
} |
|
} |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------- |
|
template<class BaseRenderer, class SolidRenderer, class Rasterizer, class Scanline> |
|
void static render(Agg2D& gr, BaseRenderer& renBase, SolidRenderer& renSolid, Rasterizer& ras, Scanline& sl) |
|
{ |
|
// JME |
|
typedef agg::span_allocator<Agg2D::ColorType> span_allocator_type; |
|
typedef agg::renderer_scanline_aa<BaseRenderer,span_allocator_type,Agg2D::LinearGradientSpan> RendererLinearGradient; |
|
typedef agg::renderer_scanline_aa<BaseRenderer,span_allocator_type,Agg2D::RadialGradientSpan> RendererRadialGradient; |
|
|
|
if(gr.m_fillGradientFlag == Agg2D::Linear) |
|
{ |
|
Agg2D::LinearGradientSpan span( |
|
gr.m_fillGradientInterpolator, |
|
gr.m_linearGradientFunction, |
|
gr.m_fillGradient, |
|
gr.m_fillGradientD1, |
|
gr.m_fillGradientD2); |
|
RendererLinearGradient ren(renBase,gr.m_allocator,span); |
|
agg::render_scanlines(ras, sl, ren); |
|
} |
|
else |
|
{ |
|
if(gr.m_fillGradientFlag == Agg2D::Radial) |
|
{ |
|
Agg2D::RadialGradientSpan span( |
|
gr.m_fillGradientInterpolator, |
|
gr.m_radialGradientFunction, |
|
gr.m_fillGradient, |
|
gr.m_fillGradientD1, |
|
gr.m_fillGradientD2); |
|
RendererRadialGradient ren(renBase,gr.m_allocator,span); |
|
agg::render_scanlines(ras, sl, ren); |
|
} |
|
else |
|
{ |
|
renSolid.color(gr.m_fillColor); |
|
agg::render_scanlines(ras, sl, renSolid); |
|
} |
|
} |
|
} |
|
}; |
|
|
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::render(bool fillColor) |
|
{ |
|
if(m_blendMode == BlendAlpha) |
|
{ |
|
Agg2DRenderer::render(*this, m_renBase, m_renSolid, fillColor); |
|
} |
|
else |
|
{ |
|
Agg2DRenderer::render(*this, m_renBaseComp, m_renSolidComp, fillColor); |
|
} |
|
} |
|
|
|
//------------------------------------------------------------------------ |
|
struct Agg2DRasterizerGamma |
|
{ |
|
|
|
Agg2DRasterizerGamma(double alpha, double gamma) : |
|
m_alpha(alpha), m_gamma(gamma) {} |
|
|
|
double operator() (double x) const |
|
{ |
|
return m_alpha(m_gamma(x)); |
|
} |
|
agg::gamma_multiply m_alpha; |
|
agg::gamma_power m_gamma; |
|
}; |
|
|
|
//------------------------------------------------------------------------ |
|
void Agg2D::updateRasterizerGamma() |
|
{ |
|
m_rasterizer.gamma(Agg2DRasterizerGamma(m_masterAlpha, m_antiAliasGamma)); |
|
}
|
|
|