mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-21 06:45:39 -06:00
Painter1.0 to archive
git-svn-id: svn://ultimatepp.org/upp/trunk@855 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
b017fc959b
commit
91e75c2404
62 changed files with 2 additions and 13 deletions
|
|
@ -1,111 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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 coM_PIes.
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e.,
|
||||
// 4, 7, 10, or 13 vertices.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Recycled for U++ by Miroslav Fidler 2008
|
||||
|
||||
void sSubArc(double cx, double cy, double rx, double ry,
|
||||
double start_angle, double sweep_angle,
|
||||
double *px, double *py)
|
||||
{
|
||||
double x0 = cos(sweep_angle / 2.0);
|
||||
double y0 = sin(sweep_angle / 2.0);
|
||||
double tx = (1.0 - x0) * 4.0 / 3.0;
|
||||
double ty = y0 - tx * x0 / y0;
|
||||
double x[4], y[4];
|
||||
x[0] = x0;
|
||||
y[0] = -y0;
|
||||
x[1] = x0 + tx;
|
||||
y[1] = -ty;
|
||||
x[2] = x0 + tx;
|
||||
y[2] = ty;
|
||||
x[3] = x0;
|
||||
y[3] = y0;
|
||||
|
||||
double sn = sin(start_angle + sweep_angle / 2.0);
|
||||
double cs = cos(start_angle + sweep_angle / 2.0);
|
||||
|
||||
unsigned i;
|
||||
for(i = 0; i < 4; i++) {
|
||||
px[i] = cx + rx * (x[i] * cs - y[i] * sn);
|
||||
py[i] = cy + ry * (x[i] * sn + y[i] * cs);
|
||||
}
|
||||
}
|
||||
|
||||
Painter& Painter::Arc(double x, double y, double rx, double ry,
|
||||
double start_angle, double sweep_angle, bool startline)
|
||||
{
|
||||
const double bezier_arc_angle_epsilon = 0.01;
|
||||
start_angle = fmod(start_angle, 2.0 * M_PI);
|
||||
if(sweep_angle >= 2.0 * M_PI) sweep_angle = 2.0 * M_PI;
|
||||
if(sweep_angle <= -2.0 * M_PI) sweep_angle = -2.0 * M_PI;
|
||||
if(fabs(sweep_angle) < 1e-10) {
|
||||
double px = x + rx * cos(start_angle);
|
||||
double py = y + ry * sin(start_angle);
|
||||
if(startline)
|
||||
Line(px, py);
|
||||
else
|
||||
Move(px, py);
|
||||
Line(x + rx * cos(start_angle + sweep_angle), y + ry * sin(start_angle + sweep_angle));
|
||||
return *this;
|
||||
}
|
||||
double total_sweep = 0.0;
|
||||
double local_sweep = 0.0;
|
||||
double prev_sweep;
|
||||
bool done = false;
|
||||
bool first = true;
|
||||
for(int i = 0; !done && i < 4; i++) {
|
||||
if(sweep_angle < 0.0) {
|
||||
prev_sweep = total_sweep;
|
||||
local_sweep = -M_PI * 0.5;
|
||||
total_sweep -= M_PI * 0.5;
|
||||
if(total_sweep <= sweep_angle + bezier_arc_angle_epsilon) {
|
||||
local_sweep = sweep_angle - prev_sweep;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
prev_sweep = total_sweep;
|
||||
local_sweep = M_PI * 0.5;
|
||||
total_sweep += M_PI * 0.5;
|
||||
if(total_sweep >= sweep_angle - bezier_arc_angle_epsilon) {
|
||||
local_sweep = sweep_angle - prev_sweep;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
double px[4];
|
||||
double py[4];
|
||||
sSubArc(x, y, rx, ry, start_angle, local_sweep, px, py);
|
||||
if(first)
|
||||
if(startline)
|
||||
Line(px[0], py[0]);
|
||||
else
|
||||
Move(px[0], py[0]);
|
||||
first = false;
|
||||
Cubic(px[1], py[1], px[2], py[2], px[3], py[3]);
|
||||
start_angle += local_sweep;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::ClearOp(const RGBA& color)
|
||||
{
|
||||
Upp::Fill(~buffer, color, buffer.GetLength());
|
||||
}
|
||||
|
||||
inline void BufferPainter::PathPoint0(double x, double y)
|
||||
{
|
||||
pathrect.left = min(pathrect.left, x);
|
||||
pathrect.top = min(pathrect.top, y);
|
||||
pathrect.right = max(pathrect.right, x);
|
||||
pathrect.bottom = max(pathrect.bottom, y);
|
||||
}
|
||||
|
||||
inline void BufferPainter::PathPoint(double& x, double& y, bool rel)
|
||||
{
|
||||
x = IsNull(x) ? current.x : rel ? x + current.x : x;
|
||||
y = IsNull(y) ? current.y : rel ? y + current.y : y;
|
||||
if(inpath)
|
||||
PathPoint0(x, y);
|
||||
else {
|
||||
path.remove_all();
|
||||
pathrect.left = pathrect.right = x;
|
||||
pathrect.top = pathrect.bottom = y;
|
||||
pathattr = attr;
|
||||
}
|
||||
inpath = true;
|
||||
}
|
||||
|
||||
inline void BufferPainter::EndPoint(double& x, double& y, bool rel)
|
||||
{
|
||||
PathPoint(x, y, rel);
|
||||
current = Pointf(x, y);
|
||||
}
|
||||
|
||||
void BufferPainter::MoveOp(double x, double y, bool rel)
|
||||
{
|
||||
EndPoint(x, y, rel);
|
||||
ccontrol = qcontrol = current;
|
||||
path.move_to(x, y);
|
||||
inpath = true;
|
||||
}
|
||||
|
||||
void BufferPainter::LineOp(double x, double y, bool rel)
|
||||
{
|
||||
EndPoint(x, y, rel);
|
||||
ccontrol = qcontrol = current;
|
||||
path.line_to(x, y);
|
||||
inpath = true;
|
||||
}
|
||||
|
||||
void BufferPainter::QuadraticOp(double x1, double y1, double x, double y, bool rel)
|
||||
{
|
||||
PathPoint(x1, y1, rel);
|
||||
qcontrol = Pointf(x1, y1);
|
||||
EndPoint(x, y, rel);
|
||||
ccontrol = current;
|
||||
path.curve3(x1, y1, x, y);
|
||||
}
|
||||
|
||||
void BufferPainter::QuadraticOp(double x, double y, bool rel)
|
||||
{
|
||||
qcontrol = current + current - qcontrol;
|
||||
PathPoint0(qcontrol.x, qcontrol.y);
|
||||
EndPoint(x, y, rel);
|
||||
ccontrol = current;
|
||||
path.curve3(qcontrol.x, qcontrol.y, x, y);
|
||||
}
|
||||
|
||||
void BufferPainter::CubicOp(double x1, double y1, double x2, double y2, double x, double y, bool rel)
|
||||
{
|
||||
PathPoint(x1, y1, rel);
|
||||
PathPoint(x2, y2, rel);
|
||||
ccontrol = Pointf(x2, y2);
|
||||
EndPoint(x, y, rel);
|
||||
qcontrol = current;
|
||||
path.curve4(x1, y1, x2, y2, x, y);
|
||||
}
|
||||
|
||||
void BufferPainter::CubicOp(double x2, double y2, double x, double y, bool rel)
|
||||
{
|
||||
Pointf c = current + current - ccontrol;
|
||||
PathPoint0(c.x, c.y);
|
||||
PathPoint(x2, y2, rel);
|
||||
ccontrol = Pointf(x2, y2);
|
||||
EndPoint(x, y, rel);
|
||||
qcontrol = current;
|
||||
path.curve4(c.x, c.y, x2, y2, x, y);
|
||||
}
|
||||
|
||||
void BufferPainter::CloseOp()
|
||||
{
|
||||
path.close_polygon();
|
||||
}
|
||||
|
||||
inline void BufferPainter::MinMax(Pointf& minv, Pointf& maxv, Pointf p) const
|
||||
{
|
||||
p = pathattr.mtx.Transformed(p);
|
||||
minv.x = min(minv.x, p.x);
|
||||
minv.y = min(minv.y, p.y);
|
||||
maxv.x = max(maxv.x, p.x);
|
||||
maxv.y = max(maxv.y, p.y);
|
||||
}
|
||||
|
||||
bool BufferPainter::PathVisible(double w) const
|
||||
{
|
||||
Pointf h = pathattr.mtx.Transformed(w, w);
|
||||
w = max(fabs(h.x), fabs(h.y));
|
||||
Pointf min;
|
||||
Pointf max;
|
||||
min = max = pathattr.mtx.Transformed(pathrect.TopLeft());
|
||||
MinMax(min, max, pathrect.TopRight());
|
||||
MinMax(min, max, pathrect.BottomLeft());
|
||||
MinMax(min, max, pathrect.BottomRight());
|
||||
return max.x + w >= 0 && max.y + w >= 0 && min.x - w <= sizef.cx && min.y - w <= sizef.cy;
|
||||
}
|
||||
|
||||
void BufferPainter::SetRbuf()
|
||||
{
|
||||
pixf.attach(buffer);
|
||||
renb.attach(pixf);
|
||||
renderer.attach(renb);
|
||||
}
|
||||
|
||||
BufferPainter::BufferPainter(ImageBuffer& ib)
|
||||
: buffer(ib),
|
||||
curved(path),
|
||||
curved_trans(curved, attr.mtx)
|
||||
{
|
||||
size = ib.GetSize();
|
||||
sizef = size;
|
||||
inpath = false;
|
||||
pathrect = Null;
|
||||
ccontrol = qcontrol = current = Point(0, 0);
|
||||
|
||||
attr.cap = LINECAP_BUTT;
|
||||
attr.join = LINEJOIN_MITER;
|
||||
attr.miter_limit = 4;
|
||||
attr.evenodd = false;
|
||||
attr.hasclip = false;
|
||||
attr.cliplevel = 0;
|
||||
attr.dash_start = 0.0;
|
||||
attr.opacity = 1.0;
|
||||
attr.mask = false;
|
||||
attr.noaa = false;
|
||||
pathattr = attr;
|
||||
|
||||
SetRbuf();
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,326 +0,0 @@
|
|||
// #define USE_MMX
|
||||
|
||||
inline RGBA Mul8(const RGBA& s, int mul)
|
||||
{
|
||||
RGBA t;
|
||||
t.r = (mul * s.r) >> 8;
|
||||
t.g = (mul * s.g) >> 8;
|
||||
t.b = (mul * s.b) >> 8;
|
||||
t.a = (mul * s.a) >> 8;
|
||||
return t;
|
||||
}
|
||||
|
||||
inline RGBA MulA(const RGBA& s, int alpha)
|
||||
{
|
||||
return Mul8(s, alpha + (alpha >> 7));
|
||||
}
|
||||
|
||||
#ifndef USE_MMX
|
||||
|
||||
inline void AlphaBlend(RGBA& t, const RGBA& c)
|
||||
{
|
||||
int alpha = 256 - (c.a + (c.a >> 7));
|
||||
t.r = c.r + (alpha * t.r >> 8);
|
||||
t.g = c.g + (alpha * t.g >> 8);
|
||||
t.b = c.b + (alpha * t.b >> 8);
|
||||
t.a = c.a + (alpha * t.a >> 8);
|
||||
}
|
||||
|
||||
inline void AlphaBlendCover(RGBA& t, const RGBA& c, byte cover)
|
||||
{
|
||||
AlphaBlend(t, MulA(c, cover));
|
||||
}
|
||||
|
||||
inline void FinishBlend() {}
|
||||
|
||||
#else
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
inline __m64 RGBAtoMMX(const RGBA& rgba)
|
||||
{
|
||||
return _mm_unpacklo_pi8(_mm_cvtsi32_si64(*(dword *)&rgba), _mm_setzero_si64());
|
||||
}
|
||||
|
||||
inline RGBA MMXtoRGBA(__m64 c)
|
||||
{
|
||||
int x = _mm_cvtsi64_si32(_mm_packs_pu16(c, _mm_setzero_si64()));
|
||||
return *(RGBA *)&x;
|
||||
}
|
||||
|
||||
inline void AlphaBlend(RGBA& t, const RGBA& c)
|
||||
{
|
||||
__m64 alpha = _mm_set1_pi16(256 - (c.a + (c.a >> 7)));
|
||||
__m64 tx = RGBAtoMMX(t);
|
||||
tx = _mm_mullo_pi16(alpha, tx);
|
||||
tx = _mm_srli_pi16(tx, 8);
|
||||
tx = _mm_add_pi16(tx, RGBAtoMMX(c));
|
||||
t = MMXtoRGBA(tx);
|
||||
}
|
||||
|
||||
inline void AlphaBlendCover(RGBA& t, const RGBA& c, byte cover)
|
||||
{
|
||||
__m64 cx = _mm_srli_pi16(_mm_mullo_pi16(RGBAtoMMX(c), _mm_set1_pi16(cover + (cover >> 7))), 8);
|
||||
__m64 tx = RGBAtoMMX(t);
|
||||
byte a = MMXtoRGBA(cx).a;
|
||||
__m64 alpha = _mm_set1_pi16(256 - (a + (a >> 7)));
|
||||
tx = _mm_mullo_pi16(alpha, tx);
|
||||
tx = _mm_srli_pi16(tx, 8);
|
||||
tx = _mm_add_pi16(tx, cx);
|
||||
t = MMXtoRGBA(tx);
|
||||
}
|
||||
|
||||
inline void AlphaBlendCover(dword *t, dword s, const byte *c, int len)
|
||||
{
|
||||
dword *e = t + len;
|
||||
__m64 zero = _mm_setzero_si64();
|
||||
__m64 src = _mm_unpacklo_pi8(_mm_cvtsi32_si64(s), zero);
|
||||
while(t < e) {
|
||||
byte cover = *c;
|
||||
__m64 cx = _mm_srli_pi16(_mm_mullo_pi16(src, _mm_set1_pi16(cover + (cover >> 7))), 8);
|
||||
__m64 tx = _mm_unpacklo_pi8(_mm_cvtsi32_si64(*t), zero);
|
||||
byte a = (dword)_mm_cvtsi64_si32(_mm_packs_pu16(cx, zero)) >> 24;
|
||||
__m64 alpha = _mm_set1_pi16(256 - (a + (a >> 7)));
|
||||
tx = _mm_mullo_pi16(alpha, tx);
|
||||
tx = _mm_srli_pi16(tx, 8);
|
||||
tx = _mm_add_pi16(tx, cx);
|
||||
*t = _mm_cvtsi64_si32(_mm_packs_pu16(tx, zero));
|
||||
t++;
|
||||
c++;
|
||||
}
|
||||
_mm_empty();
|
||||
}
|
||||
|
||||
inline void FinishBlend()
|
||||
{
|
||||
_mm_empty();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class BufferPainter : public Painter {
|
||||
protected:
|
||||
virtual void ClearOp(const RGBA& color);
|
||||
|
||||
virtual void MoveOp(double x, double y, bool rel);
|
||||
virtual void LineOp(double x, double y, bool rel);
|
||||
virtual void QuadraticOp(double x1, double y1, double x, double y, bool rel);
|
||||
virtual void QuadraticOp(double x, double y, bool rel);
|
||||
virtual void CubicOp(double x1, double y1, double x2, double y2, double x, double y, bool rel);
|
||||
virtual void CubicOp(double x2, double y2, double x, double y, bool rel);
|
||||
virtual void CloseOp();
|
||||
|
||||
virtual void FillOp(const RGBA& color);
|
||||
virtual void FillOp(const Image& image, const Matrix2D& transsrc,
|
||||
dword flags);
|
||||
virtual void FillOp(double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2,
|
||||
int style);
|
||||
virtual void FillOp(double fx, double fy, const RGBA& color1,
|
||||
double x1, double y1, double r, const RGBA& color2,
|
||||
int style);
|
||||
|
||||
virtual void StrokeOp(double width, const RGBA& rgba);
|
||||
virtual void StrokeOp(double width, const Image& image, const Matrix2D& transsrc,
|
||||
dword flags);
|
||||
virtual void StrokeOp(double width, double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2,
|
||||
int style);
|
||||
virtual void StrokeOp(double width, double fx, double fy, const RGBA& color1,
|
||||
double x, double y, double r, const RGBA& color2,
|
||||
int style);
|
||||
|
||||
virtual void ClipOp();
|
||||
|
||||
virtual void ColorStopOp(double pos, const RGBA& color);
|
||||
virtual void ClearStopsOp();
|
||||
|
||||
virtual void OpacityOp(double o);
|
||||
virtual void LineCapOp(int linecap);
|
||||
virtual void LineJoinOp(int linejoin);
|
||||
virtual void MiterLimitOp(double l);
|
||||
virtual void EvenOddOp(bool evenodd);
|
||||
virtual void DashOp(const Vector<double>& dash, double start);
|
||||
virtual void NoAAOp(bool noaa);
|
||||
|
||||
|
||||
virtual void TransformOp(const Matrix2D& m);
|
||||
|
||||
virtual void BeginOp();
|
||||
virtual void EndOp();
|
||||
|
||||
virtual void BeginMaskOp();
|
||||
|
||||
private:
|
||||
class vertex_upp_storage {
|
||||
Vector<Pointf> v;
|
||||
Vector<int> c;
|
||||
public:
|
||||
typedef double value_type;
|
||||
void remove_all() { v.Clear(); c.Clear(); }
|
||||
void free_all() { remove_all(); }
|
||||
void add_vertex(double x, double y, unsigned cmd) { v.Add(Pointf(x, y)); c.Add(cmd); }
|
||||
void modify_vertex(int i, double x, double y) { v[i].x = x; v[i].y = y; }
|
||||
void modify_vertex(int i, double x, double y, unsigned cmd) { modify_vertex(i, x, y); c[i] = cmd; }
|
||||
void modify_command(int i, unsigned cmd) { c[i] = cmd; }
|
||||
void swap_vertices(unsigned v1, unsigned v2) { v.Swap(v1, v2); c.Swap(v1, v2); }
|
||||
unsigned last_command() const { return c.GetCount() ? c.Top() : agg::path_cmd_stop; }
|
||||
unsigned last_vertex(double* x, double* y) const {
|
||||
if(c.GetCount() == 0) {
|
||||
*x = *y = 0.0;
|
||||
return agg::path_cmd_stop;
|
||||
}
|
||||
return vertex(v.GetCount() - 1, x, y);
|
||||
}
|
||||
unsigned prev_vertex(double* x, double* y) const {
|
||||
if(c.GetCount() < 2) {
|
||||
*x = *y = 0.0;
|
||||
return agg::path_cmd_stop;
|
||||
}
|
||||
return vertex(v.GetCount() - 2, x, y);
|
||||
}
|
||||
double last_x() const { return v.GetCount() ? v.Top().x : 0.0; }
|
||||
double last_y() const { return v.GetCount() ? v.Top().y : 0.0; }
|
||||
unsigned total_vertices() const { return v.GetCount(); }
|
||||
unsigned vertex(int i, double* x, double* y) const {
|
||||
*x = v[i].x;
|
||||
*y = v[i].y;
|
||||
return c[i];
|
||||
}
|
||||
unsigned command(int i) const { return (int)i < c.GetCount() ? c[i] : agg::path_cmd_stop; }
|
||||
};
|
||||
|
||||
class upp_pixfmt {
|
||||
Size sz;
|
||||
RGBA *buffer;
|
||||
|
||||
public:
|
||||
typedef RGBA pixel_type;
|
||||
typedef RGBA color_type;
|
||||
typedef byte value_type;
|
||||
typedef int calc_type;
|
||||
typedef agg::const_row_info<RGBA> row_data;
|
||||
|
||||
bool noaa;
|
||||
|
||||
void attach(ImageBuffer& ib) { buffer = ib; sz = ib.GetSize(); }
|
||||
|
||||
int width() const { return sz.cx; }
|
||||
int height() const { return sz.cy; }
|
||||
int stride() const { return sz.cx; }
|
||||
|
||||
RGBA* row_ptr(int y) { return buffer + sz.cx * y; }
|
||||
RGBA *ptr(int x, int y) { return buffer + sz.cx * y + x; }
|
||||
const RGBA* row_ptr(int y) const { return buffer + sz.cx * y; }
|
||||
|
||||
void blend_hline(int x, int y, int len, RGBA c, byte cover);
|
||||
void blend_solid_hspan(int x, int y, int len, const RGBA& c, const byte* covers);
|
||||
void blend_color_hspan(int x, int y, int len, const RGBA* colors,
|
||||
const byte* covers, byte cover);
|
||||
};
|
||||
|
||||
struct upp_pixfmt_clip {
|
||||
Size sz;
|
||||
byte *buffer;
|
||||
|
||||
typedef byte pixel_type;
|
||||
typedef byte color_type;
|
||||
typedef byte value_type;
|
||||
typedef int calc_type;
|
||||
typedef agg::const_row_info<RGBA> row_data;
|
||||
|
||||
int width() const { return sz.cx; }
|
||||
int height() const { return sz.cy; }
|
||||
int stride() const { return sz.cx; }
|
||||
|
||||
byte* row_ptr(int y) { return buffer + sz.cx * y; }
|
||||
byte *ptr(int x, int y) { return buffer + sz.cx * y + x; }
|
||||
const byte* row_ptr(int y) const { return buffer + sz.cx * y; }
|
||||
|
||||
void blend_hline(int x, int y, int len, byte, byte cover);
|
||||
void blend_solid_hspan(int x, int y, int len, byte, const byte* covers);
|
||||
void blend_color_hspan(int x, int y, int len, byte *,
|
||||
const byte* covers, byte cover);
|
||||
};
|
||||
|
||||
typedef agg::path_base<vertex_upp_storage> path_storage;
|
||||
|
||||
typedef upp_pixfmt pixfmt;
|
||||
typedef RGBA color_type;
|
||||
typedef agg::renderer_base<pixfmt> renderer_base;
|
||||
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
|
||||
typedef agg::span_interpolator_linear<> interpolator_type;
|
||||
typedef agg::span_allocator<color_type> span_alloc;
|
||||
typedef renderer_base::color_type x;
|
||||
|
||||
Size size;
|
||||
Sizef sizef;
|
||||
ImageBuffer& buffer;
|
||||
Array< Buffer<byte> > clip;
|
||||
Array< ImageBuffer > mask;
|
||||
|
||||
struct Attr : Moveable<Attr> {
|
||||
Matrix2D mtx;
|
||||
bool evenodd;
|
||||
byte join;
|
||||
byte cap;
|
||||
double miter_limit;
|
||||
WithDeepCopy< Vector<double> > dash;
|
||||
WithDeepCopy< Vector<double> > stop;
|
||||
WithDeepCopy< Vector<RGBA> > stop_color;
|
||||
double dash_start;
|
||||
double opacity;
|
||||
int cliplevel;
|
||||
bool hasclip;
|
||||
bool mask;
|
||||
bool noaa;
|
||||
};
|
||||
|
||||
Attr attr;
|
||||
Attr pathattr;
|
||||
Vector<Attr> attrstack;
|
||||
|
||||
path_storage path;
|
||||
bool inpath;
|
||||
|
||||
agg::rasterizer_scanline_aa<> rasterizer;
|
||||
agg::scanline_p8 scanline_p;
|
||||
renderer_base renb;
|
||||
renderer_solid renderer;
|
||||
pixfmt pixf;
|
||||
|
||||
typedef agg::conv_curve<path_storage> Curved;
|
||||
typedef agg::conv_transform<Curved> CurvedTrans;
|
||||
|
||||
Curved curved;
|
||||
CurvedTrans curved_trans;
|
||||
|
||||
Rectf pathrect;
|
||||
Pointf current, ccontrol, qcontrol;
|
||||
|
||||
struct StrokeInfo {
|
||||
bool evenodd;
|
||||
path_storage path;
|
||||
};
|
||||
|
||||
void PathPoint0(double x, double y);
|
||||
void PathPoint(double& x, double& y, bool rel);
|
||||
void EndPoint(double& x, double& y, bool rel);
|
||||
void MinMax(Pointf& min, Pointf& max, Pointf p) const;
|
||||
bool PathVisible(double d) const;
|
||||
Pointf Current() const { return current; }
|
||||
Rectf PathRect() const { return pathrect; }
|
||||
StrokeInfo BeginStroke(double width);
|
||||
void EndStroke(StrokeInfo& f);
|
||||
Pointf ReadPoint(CParser& p, bool rel);
|
||||
void RenderClip(byte *t);
|
||||
void MakeGradient(RGBA *t, RGBA color1, RGBA color2, int cx);
|
||||
void ColorStop0(Attr& a, double pos, const RGBA& color);
|
||||
void FinishMask();
|
||||
void SetRbuf();
|
||||
|
||||
friend class Painter;
|
||||
|
||||
public:
|
||||
BufferPainter(ImageBuffer& ib);
|
||||
};
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::upp_pixfmt_clip::blend_hline(int x, int y, int len, byte, byte cover)
|
||||
{
|
||||
memset(ptr(x, y), cover, len);
|
||||
}
|
||||
|
||||
void BufferPainter::upp_pixfmt_clip::blend_solid_hspan(int x, int y, int len, byte, const byte *covers)
|
||||
{
|
||||
memcpy(ptr(x, y), covers, len);
|
||||
}
|
||||
|
||||
void BufferPainter::RenderClip(byte *t)
|
||||
{
|
||||
upp_pixfmt_clip pixf;
|
||||
pixf.sz = size;
|
||||
pixf.buffer = t;
|
||||
typedef agg::renderer_base<upp_pixfmt_clip> ren_base;
|
||||
ren_base rb(pixf);
|
||||
agg::scanline_p8 sl;
|
||||
if(inpath)
|
||||
path.close_polygon();
|
||||
rasterizer.reset();
|
||||
rasterizer.filling_rule(pathattr.evenodd ? agg::fill_even_odd : agg::fill_non_zero);
|
||||
rasterizer.add_path(curved_trans);
|
||||
agg::renderer_scanline_aa_solid<ren_base> r(rb);
|
||||
r.color(255);
|
||||
agg::render_scanlines(rasterizer, sl, r);
|
||||
rasterizer.reset();
|
||||
inpath = false;
|
||||
}
|
||||
|
||||
void BufferPainter::ClipOp()
|
||||
{
|
||||
int l = size.cx * size.cy;
|
||||
Buffer<byte> cl(l);
|
||||
memset(~cl, 0, l);
|
||||
RenderClip(~cl);
|
||||
if(clip.GetCount()) {
|
||||
byte *s = ~clip.Top();
|
||||
for(int i = 0; i < l; i++)
|
||||
cl[i] = ((cl[i] + (cl[i] >> 7)) * s[i]) >> 8;
|
||||
}
|
||||
if(attr.hasclip)
|
||||
clip.Top() = cl;
|
||||
else {
|
||||
clip.Add() = cl;
|
||||
attr.hasclip = true;
|
||||
attr.cliplevel = clip.GetCount();
|
||||
}
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::BeginOp()
|
||||
{
|
||||
attrstack.Add(attr);
|
||||
attr.hasclip = false;
|
||||
}
|
||||
|
||||
void BufferPainter::EndOp()
|
||||
{
|
||||
if(attrstack.GetCount() == 0) {
|
||||
NEVER_("Painter::End: attribute stack is empty");
|
||||
return;
|
||||
}
|
||||
pathattr = attr = attrstack.Pop();
|
||||
clip.SetCount(attr.cliplevel);
|
||||
if(attr.mask)
|
||||
FinishMask();
|
||||
}
|
||||
|
||||
void BufferPainter::TransformOp(const Matrix2D& m)
|
||||
{
|
||||
ASSERT_(!inpath, "Cannot change transformation during path definition");
|
||||
attr.mtx = m * attr.mtx;
|
||||
pathattr.mtx = attr.mtx;
|
||||
}
|
||||
|
||||
void BufferPainter::OpacityOp(double o)
|
||||
{
|
||||
pathattr.opacity *= o;
|
||||
if(!inpath)
|
||||
attr.opacity *= o;
|
||||
}
|
||||
|
||||
void BufferPainter::LineCapOp(int linecap)
|
||||
{
|
||||
pathattr.cap = linecap;
|
||||
if(!inpath)
|
||||
attr.cap = linecap;
|
||||
}
|
||||
|
||||
void BufferPainter::LineJoinOp(int linejoin)
|
||||
{
|
||||
pathattr.join = linejoin;
|
||||
if(!inpath)
|
||||
attr.join = linejoin;
|
||||
}
|
||||
|
||||
void BufferPainter::MiterLimitOp(double l)
|
||||
{
|
||||
pathattr.miter_limit = l;
|
||||
if(!inpath)
|
||||
attr.miter_limit = l;
|
||||
}
|
||||
|
||||
void BufferPainter::EvenOddOp(bool evenodd)
|
||||
{
|
||||
pathattr.evenodd = evenodd;
|
||||
if(!inpath)
|
||||
attr.evenodd = evenodd;
|
||||
}
|
||||
|
||||
void BufferPainter::DashOp(const Vector<double>& dash, double start)
|
||||
{
|
||||
pathattr.dash <<= dash;
|
||||
pathattr.dash_start = start;
|
||||
if(!inpath) {
|
||||
attr.dash <<= dash;
|
||||
attr.dash_start = start;
|
||||
}
|
||||
}
|
||||
|
||||
void BufferPainter::NoAAOp(bool noaa)
|
||||
{
|
||||
pathattr.noaa = noaa;
|
||||
if(!inpath)
|
||||
attr.noaa = noaa;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
// int agg_line_counter; _DBG_
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::FillOp(const RGBA& c)
|
||||
{
|
||||
PAINTER_TIMING("FillOp");
|
||||
// agg_line_counter = 0;
|
||||
if(inpath)
|
||||
path.close_polygon();
|
||||
pixf.noaa = pathattr.noaa;
|
||||
RGBA color = c;
|
||||
if(PathVisible(0) && color.a) {
|
||||
if(pathattr.opacity != 1.0) {
|
||||
color.a = int(color.a * pathattr.opacity);
|
||||
color.r = int(color.r * pathattr.opacity);
|
||||
color.g = int(color.g * pathattr.opacity);
|
||||
color.b = int(color.b * pathattr.opacity);
|
||||
}
|
||||
if(color.a) {
|
||||
rasterizer.reset();
|
||||
rasterizer.filling_rule(pathattr.evenodd ? agg::fill_even_odd : agg::fill_non_zero);
|
||||
rasterizer.add_path(curved_trans);
|
||||
if(clip.GetCount()) {
|
||||
agg::rendering_buffer mask_rbuf;
|
||||
mask_rbuf.attach(~clip.Top(), size.cx, size.cy, size.cx);
|
||||
agg::alpha_mask_gray8 mask(mask_rbuf);
|
||||
agg::scanline_u8_am<agg::alpha_mask_gray8> sl(mask);
|
||||
renderer.color(color);
|
||||
agg::render_scanlines(rasterizer, sl, renderer);
|
||||
}
|
||||
else {
|
||||
renderer.color(*(color_type *)&color);
|
||||
agg::render_scanlines(rasterizer, scanline_p, renderer);
|
||||
}
|
||||
rasterizer.reset();
|
||||
}
|
||||
}
|
||||
inpath = false;
|
||||
// DDUMP(agg_line_counter);
|
||||
}
|
||||
|
||||
struct UppImageAggSpan {
|
||||
struct RGBAV {
|
||||
dword r, g, b, a;
|
||||
|
||||
void Set(dword v) { r = g = b = a = v; }
|
||||
void Put(dword weight, const RGBA& src) {
|
||||
r += weight * src.r;
|
||||
g += weight * src.g;
|
||||
b += weight * src.b;
|
||||
a += weight * src.a;
|
||||
}
|
||||
};
|
||||
|
||||
agg::span_interpolator_linear<> interpolator;
|
||||
int ax, ay, cx, cy, maxx, maxy;
|
||||
byte style;
|
||||
byte hstyle, vstyle;
|
||||
bool fast;
|
||||
bool fixed;
|
||||
const RGBA *image;
|
||||
int alpha;
|
||||
|
||||
void SetImage(const Image& img) {
|
||||
image = ~img;
|
||||
cx = img.GetWidth();
|
||||
cy = img.GetHeight();
|
||||
maxx = cx - 1;
|
||||
maxy = cy - 1;
|
||||
ax = 6000000 / cx * cx;
|
||||
ay = 6000000 / cy * cy;
|
||||
}
|
||||
|
||||
RGBA Pixel(int x, int y) { return image[cx * y + x]; }
|
||||
|
||||
RGBA GetPixel(int x, int y) {
|
||||
if(hstyle == FILL_HPAD)
|
||||
x = minmax(x, 0, maxx);
|
||||
else
|
||||
if(hstyle == FILL_HREFLECT)
|
||||
x = (x + ax) / cx & 1 ? (ax - x - 1) % cx : (x + ax) % cx;
|
||||
else
|
||||
if(hstyle == FILL_HREPEAT)
|
||||
x = (x + ax) % cx;
|
||||
if(vstyle == FILL_VPAD)
|
||||
y = minmax(y, 0, maxy);
|
||||
else
|
||||
if(vstyle == FILL_VREFLECT)
|
||||
y = (y + ay) / cy & 1 ? (ay - y - 1) % cy : (y + ay) % cy;
|
||||
else
|
||||
if(vstyle == FILL_VREPEAT)
|
||||
y = (y + ay) % cy;
|
||||
return fixed || (x >= 0 && x < cx && y >= 0 && y < cy) ? image[cx * y + x] : RGBAZero();
|
||||
}
|
||||
|
||||
void prepare() {}
|
||||
|
||||
void generate(RGBA *_span, int x, int y, unsigned len)
|
||||
{
|
||||
interpolator.begin(x + 0.5, y + 0.5, len);
|
||||
RGBA *span = (RGBA *)_span;
|
||||
fixed = hstyle && vstyle;
|
||||
while(len--) {
|
||||
int x_hr;
|
||||
int y_hr;
|
||||
interpolator.coordinates(&x_hr, &y_hr);
|
||||
x_hr -= 128;
|
||||
y_hr -= 128;
|
||||
int x_lr = x_hr >> 8;
|
||||
int y_lr = y_hr >> 8;
|
||||
if(hstyle == FILL_HREPEAT)
|
||||
x_lr = (x_lr + ax) % cx;
|
||||
if(vstyle == FILL_VREPEAT)
|
||||
y_lr = (y_lr + ay) % cy;
|
||||
if(fast) {
|
||||
RGBA v;
|
||||
if(x_lr > 0 && x_lr < maxx && y_lr > 0 && y_lr < maxy)
|
||||
v = Pixel(x_lr, y_lr);
|
||||
if(style == 0 && (x_lr < -1 || x_lr > cx || y_lr < -1 || y_lr > cy))
|
||||
v == RGBAZero();
|
||||
else
|
||||
v = GetPixel(x_lr, y_lr);
|
||||
if(alpha == 256)
|
||||
*span = v;
|
||||
else {
|
||||
span->r = byte((alpha * v.r) >> 8);
|
||||
span->g = byte((alpha * v.g) >> 8);
|
||||
span->b = byte((alpha * v.b) >> 8);
|
||||
span->a = byte((alpha * v.a) >> 8);
|
||||
}
|
||||
}
|
||||
else {
|
||||
RGBAV v;
|
||||
v.Set(256 * 256 / 2);
|
||||
x_hr &= 255;
|
||||
y_hr &= 255;
|
||||
if(x_lr > 0 && x_lr < maxx && y_lr > 0 && y_lr < maxy) {
|
||||
v.Put((256 - x_hr) * (256 - y_hr), Pixel(x_lr, y_lr));
|
||||
v.Put(x_hr * (256 - y_hr), Pixel(x_lr + 1, y_lr));
|
||||
v.Put((256 - x_hr) * y_hr, Pixel(x_lr, y_lr + 1));
|
||||
v.Put(x_hr * y_hr, Pixel(x_lr + 1, y_lr + 1));
|
||||
}
|
||||
else
|
||||
if(style == 0 && (x_lr < -1 || x_lr > cx || y_lr < -1 || y_lr > cy))
|
||||
v.Set(0);
|
||||
else {
|
||||
v.Put((256 - x_hr) * (256 - y_hr), GetPixel(x_lr, y_lr));
|
||||
v.Put(x_hr * (256 - y_hr), GetPixel(x_lr + 1, y_lr));
|
||||
v.Put((256 - x_hr) * y_hr, GetPixel(x_lr, y_lr + 1));
|
||||
v.Put(x_hr * y_hr, GetPixel(x_lr + 1, y_lr + 1));
|
||||
}
|
||||
v.r >>= 16;
|
||||
v.g >>= 16;
|
||||
v.b >>= 16;
|
||||
v.a >>= 16;
|
||||
if(alpha == 256) {
|
||||
span->r = (byte)v.r;
|
||||
span->g = (byte)v.g;
|
||||
span->b = (byte)v.b;
|
||||
span->a = (byte)v.a;
|
||||
}
|
||||
else {
|
||||
span->r = byte((alpha * v.r) >> 8);
|
||||
span->g = byte((alpha * v.g) >> 8);
|
||||
span->b = byte((alpha * v.b) >> 8);
|
||||
span->a = byte((alpha * v.a) >> 8);
|
||||
}
|
||||
}
|
||||
++span;
|
||||
++interpolator;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void BufferPainter::FillOp(const Image& image, const Matrix2D& transsrc, dword flags)
|
||||
{
|
||||
if(image.GetWidth() == 0 || image.GetHeight() == 0)
|
||||
return;
|
||||
if(inpath)
|
||||
path.close_polygon();
|
||||
span_alloc sa;
|
||||
|
||||
pixf.noaa = pathattr.noaa;
|
||||
Matrix2D m = transsrc * pathattr.mtx;
|
||||
m.invert();
|
||||
UppImageAggSpan sg;
|
||||
sg.interpolator.transformer(m);
|
||||
sg.alpha = int(pathattr.opacity * 256);
|
||||
sg.SetImage(image);
|
||||
sg.style = flags & 15;
|
||||
sg.hstyle = flags & 3;
|
||||
sg.vstyle = flags & 12;
|
||||
sg.fast = flags & FILL_FAST;
|
||||
|
||||
rasterizer.reset();
|
||||
rasterizer.filling_rule(pathattr.evenodd ? agg::fill_even_odd : agg::fill_non_zero);
|
||||
rasterizer.add_path(curved_trans);
|
||||
|
||||
if(clip.GetCount()) {
|
||||
agg::rendering_buffer mask_rbuf;
|
||||
mask_rbuf.attach(~clip.Top(), size.cx, size.cy, size.cx);
|
||||
agg::alpha_mask_gray8 mask(mask_rbuf);
|
||||
agg::scanline_u8_am<agg::alpha_mask_gray8> sl(mask);
|
||||
agg::render_scanlines_aa(rasterizer, sl, renb, sa, sg);
|
||||
}
|
||||
else
|
||||
agg::render_scanlines_aa(rasterizer, scanline_p, renb, sa, sg);
|
||||
rasterizer.reset();
|
||||
inpath = false;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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 coM_PIes.
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Recycled for U++ by Miroslav Fidler 2008
|
||||
|
||||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
|
||||
inline double fx_to_dbl(const FIXED& p) {
|
||||
return double(p.value) + double(p.fract) * (1.0 / 65536.0);
|
||||
}
|
||||
|
||||
void RenderCharPath(const char* gbuf, unsigned total_size, Painter& sw, double xx, double yy)
|
||||
{
|
||||
const char* cur_glyph = gbuf;
|
||||
const char* end_glyph = gbuf + total_size;
|
||||
|
||||
while(cur_glyph < end_glyph) {
|
||||
const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
|
||||
const char* end_poly = cur_glyph + th->cb;
|
||||
const char* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
|
||||
sw.Move(xx + fx_to_dbl(th->pfxStart.x), yy - fx_to_dbl(th->pfxStart.y));
|
||||
while(cur_poly < end_poly) {
|
||||
const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
|
||||
if (pc->wType == TT_PRIM_LINE)
|
||||
for(int i = 0; i < pc->cpfx; i++)
|
||||
sw.Line(xx + fx_to_dbl(pc->apfx[i].x), yy - fx_to_dbl(pc->apfx[i].y));
|
||||
if (pc->wType == TT_PRIM_QSPLINE) {
|
||||
int u;
|
||||
for (u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
|
||||
POINTFX pnt_b = pc->apfx[u]; // B is always the current point
|
||||
POINTFX pnt_c = pc->apfx[u+1];
|
||||
if (u < pc->cpfx - 2) { // If not on last spline, compute C
|
||||
*(int*)&pnt_c.x = (*(int*)&pnt_b.x + *(int*)&pnt_c.x) / 2;
|
||||
*(int*)&pnt_c.y = (*(int*)&pnt_b.y + *(int*)&pnt_c.y) / 2;
|
||||
}
|
||||
sw.Quadratic(xx + fx_to_dbl(pnt_b.x), yy - fx_to_dbl(pnt_b.y),
|
||||
xx + fx_to_dbl(pnt_c.x), yy - fx_to_dbl(pnt_c.y));
|
||||
}
|
||||
}
|
||||
cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
|
||||
}
|
||||
sw.Close();
|
||||
cur_glyph += th->cb;
|
||||
}
|
||||
}
|
||||
|
||||
struct FontChar {
|
||||
Font fnt;
|
||||
int chr;
|
||||
|
||||
bool operator==(const FontChar& b) const { return fnt == b.fnt && chr == b.chr; }
|
||||
unsigned GetHashValue() const { return CombineHash(fnt, chr); }
|
||||
};
|
||||
|
||||
struct sMakeCharOutline : LRUCache<String, FontChar>::Maker {
|
||||
FontChar fc;
|
||||
|
||||
FontChar Key() const { return fc; }
|
||||
int Make(String& s) const {
|
||||
static ScreenDraw w;
|
||||
w.SetFont(fc.fnt);
|
||||
GLYPHMETRICS gm;
|
||||
MAT2 m_matrix;
|
||||
memset(&m_matrix, 0, sizeof(m_matrix));
|
||||
m_matrix.eM11.value = 1;
|
||||
m_matrix.eM22.value = 1;
|
||||
s.Clear();
|
||||
int gsz = GetGlyphOutlineW(w.GetHandle(), fc.chr, GGO_NATIVE, &gm, 0, NULL, &m_matrix);
|
||||
if(gsz < 0)
|
||||
return 0;
|
||||
StringBuffer gb(gsz);
|
||||
gsz = GetGlyphOutlineW(w.GetHandle(), fc.chr, GGO_NATIVE, &gm, gsz, ~gb, &m_matrix);
|
||||
if(gsz < 0)
|
||||
return 0;
|
||||
s = gb;
|
||||
return gsz;
|
||||
}
|
||||
};
|
||||
|
||||
void Painter::CharacterOp(double x, double y, int ch, Font fnt)
|
||||
{
|
||||
PAINTER_TIMING("CharacterOp");
|
||||
String s;
|
||||
INTERLOCKED {
|
||||
static LRUCache<String, FontChar> cache;
|
||||
cache.Shrink(100000);
|
||||
sMakeCharOutline h;
|
||||
h.fc.fnt = fnt;
|
||||
h.fc.chr = ch;
|
||||
s = cache.Get(h);
|
||||
}
|
||||
RenderCharPath(s, s.GetLength(), *this, x, y + fnt.Info().GetAscent());
|
||||
EvenOdd(true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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 coM_PIes.
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Recycled for U++ by Miroslav Fidler 2008
|
||||
|
||||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#ifdef PLATFORM_X11
|
||||
|
||||
static inline double ft_dbl(int p)
|
||||
{
|
||||
return double(p) / 64.0;
|
||||
}
|
||||
|
||||
bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy)
|
||||
{
|
||||
FT_Vector v_last;
|
||||
FT_Vector v_control;
|
||||
FT_Vector v_start;
|
||||
double x1, y1, x2, y2, x3, y3;
|
||||
FT_Vector* point;
|
||||
FT_Vector* limit;
|
||||
char* tags;
|
||||
int n; // index of contour in outline
|
||||
char tag; // current point's state
|
||||
int first = 0; // index of first point in contour
|
||||
for(n = 0; n < outline.n_contours; n++) {
|
||||
int last = outline.contours[n];
|
||||
limit = outline.points + last;
|
||||
v_start = outline.points[first];
|
||||
v_last = outline.points[last];
|
||||
v_control = v_start;
|
||||
point = outline.points + first;
|
||||
tags = outline.tags + first;
|
||||
tag = FT_CURVE_TAG(tags[0]);
|
||||
if(tag == FT_CURVE_TAG_CUBIC) return false;
|
||||
if(tag == FT_CURVE_TAG_CONIC) {
|
||||
if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) {
|
||||
// start at last point if it is on the curve
|
||||
v_start = v_last;
|
||||
limit--;
|
||||
}
|
||||
else {
|
||||
// if both first and last points are conic,
|
||||
// start at their middle and record its position
|
||||
// for closure
|
||||
v_start.x = (v_start.x + v_last.x) / 2;
|
||||
v_start.y = (v_start.y + v_last.y) / 2;
|
||||
v_last = v_start;
|
||||
}
|
||||
point--;
|
||||
tags--;
|
||||
}
|
||||
path.Move(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
|
||||
while(point < limit) {
|
||||
point++;
|
||||
tags++;
|
||||
|
||||
tag = FT_CURVE_TAG(tags[0]);
|
||||
switch(tag) {
|
||||
case FT_CURVE_TAG_ON:
|
||||
path.Line(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy);
|
||||
continue;
|
||||
case FT_CURVE_TAG_CONIC:
|
||||
v_control.x = point->x;
|
||||
v_control.y = point->y;
|
||||
Do_Conic:
|
||||
if(point < limit) {
|
||||
FT_Vector vec;
|
||||
FT_Vector v_middle;
|
||||
point++;
|
||||
tags++;
|
||||
tag = FT_CURVE_TAG(tags[0]);
|
||||
vec.x = point->x;
|
||||
vec.y = point->y;
|
||||
if(tag == FT_CURVE_TAG_ON) {
|
||||
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
|
||||
ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy);
|
||||
continue;
|
||||
}
|
||||
if(tag != FT_CURVE_TAG_CONIC) return false;
|
||||
v_middle.x = (v_control.x + vec.x) / 2;
|
||||
v_middle.y = (v_control.y + vec.y) / 2;
|
||||
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
|
||||
ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy);
|
||||
v_control = vec;
|
||||
goto Do_Conic;
|
||||
}
|
||||
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
|
||||
ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
|
||||
goto Close;
|
||||
|
||||
default:
|
||||
FT_Vector vec1, vec2;
|
||||
if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
|
||||
return false;
|
||||
vec1.x = point[0].x;
|
||||
vec1.y = point[0].y;
|
||||
vec2.x = point[1].x;
|
||||
vec2.y = point[1].y;
|
||||
point += 2;
|
||||
tags += 2;
|
||||
if(point <= limit) {
|
||||
FT_Vector vec;
|
||||
vec.x = point->x;
|
||||
vec.y = point->y;
|
||||
path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy,
|
||||
ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy,
|
||||
ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy);
|
||||
continue;
|
||||
}
|
||||
path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy,
|
||||
ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy,
|
||||
ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
|
||||
goto Close;
|
||||
}
|
||||
}
|
||||
Close:
|
||||
path.Close();
|
||||
first = last + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Painter::CharacterOp(double x, double y, int ch, Font fnt)
|
||||
{
|
||||
PAINTER_TIMING("CharacterOp");
|
||||
FontInfo fi = fnt.Info();
|
||||
FT_Face face = XftLockFace(fi.GetXftFont());
|
||||
int glyph_index = FT_Get_Char_Index(face, ch);
|
||||
if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0)
|
||||
RenderOutline(face->glyph->outline, *this, x, y + fnt.Info().GetAscent());
|
||||
XftUnlockFace(fi.GetXftFont());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::ColorStop0(Attr& a, double pos, const RGBA& color)
|
||||
{
|
||||
pos = minmax(pos, 0.0, 1.0);
|
||||
int i = FindLowerBound(a.stop, pos);
|
||||
a.stop.Insert(i, pos);
|
||||
a.stop_color.Insert(i, color);
|
||||
}
|
||||
|
||||
void BufferPainter::ColorStopOp(double pos, const RGBA& color)
|
||||
{
|
||||
ColorStop0(pathattr, pos, color);
|
||||
if(!inpath)
|
||||
ColorStop0(attr, pos, color);
|
||||
}
|
||||
|
||||
void BufferPainter::ClearStopsOp()
|
||||
{
|
||||
pathattr.stop.Clear();
|
||||
pathattr.stop_color.Clear();
|
||||
if(!inpath) {
|
||||
attr.stop.Clear();
|
||||
attr.stop_color.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void BufferPainter::MakeGradient(RGBA *t, RGBA color1, RGBA color2, int cx)
|
||||
{
|
||||
int l = 0;
|
||||
RGBA cl = color1;
|
||||
for(int i = 0; i <= pathattr.stop.GetCount(); i++) {
|
||||
int h;
|
||||
RGBA ch;
|
||||
if(i < pathattr.stop.GetCount()) {
|
||||
h = (int)(pathattr.stop[i] * (cx - 1));
|
||||
ch = pathattr.stop_color[i];
|
||||
}
|
||||
else {
|
||||
h = cx - 1;
|
||||
ch = color2;
|
||||
}
|
||||
int w = h - l;
|
||||
for(int j = 0; j < w; j++) {
|
||||
t->r = ((w - j) * cl.r + j * ch.r) / w;
|
||||
t->g = ((w - j) * cl.g + j * ch.g) / w;
|
||||
t->b = ((w - j) * cl.b + j * ch.b) / w;
|
||||
t->a = ((w - j) * cl.a + j * ch.a) / w;
|
||||
t++;
|
||||
}
|
||||
cl = ch;
|
||||
l = h;
|
||||
}
|
||||
*t = cl;
|
||||
}
|
||||
|
||||
void BufferPainter::FillOp(double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2, int style)
|
||||
{
|
||||
int n = max(2, int((fabs(pathrect.GetWidth()) + fabs(pathrect.GetHeight()))
|
||||
* pathattr.mtx.scale()));
|
||||
ImageBuffer ib(n, 1);
|
||||
MakeGradient(ib, color1, color2, n);
|
||||
Fill(ib, x1, y1, x2, y2, FILL_VPAD | FILL_FAST |
|
||||
(style == GRADIENT_PAD ? FILL_HPAD : style == GRADIENT_REPEAT
|
||||
? FILL_HREPEAT : FILL_HREFLECT));
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::BeginMaskOp()
|
||||
{
|
||||
attr.mask = true;
|
||||
Size sz = buffer.GetSize();
|
||||
mask.Add() = buffer;
|
||||
buffer.Create(sz);
|
||||
SetRbuf();
|
||||
Clear(RGBAZero());
|
||||
Begin();
|
||||
}
|
||||
|
||||
void BufferPainter::FinishMask()
|
||||
{
|
||||
RGBA *s = ~buffer;
|
||||
RGBA *e = ~buffer + buffer.GetLength();
|
||||
byte *t, *cs;
|
||||
if(clip.GetCount())
|
||||
cs = ~clip.Top();
|
||||
if(!attr.hasclip) {
|
||||
clip.Add().Alloc(size.cx * size.cy);
|
||||
attr.hasclip = true;
|
||||
attr.cliplevel = clip.GetCount();
|
||||
}
|
||||
t = ~clip.Top();
|
||||
if(clip.GetCount() == 1)
|
||||
while(s < e) {
|
||||
byte v = ((s->a + (s->a >> 7)) * (77 * s->r + 151 * s->g + 28 * s->b)) >> 16;
|
||||
*t = v;
|
||||
s++;
|
||||
t++;
|
||||
}
|
||||
else
|
||||
while(s < e) {
|
||||
byte v = ((s->a + (s->a >> 7)) * (77 * s->r + 151 * s->g + 28 * s->b)) >> 16;
|
||||
*t = (*cs * (v + (v >> 7))) >> 8;
|
||||
s++;
|
||||
t++;
|
||||
cs++;
|
||||
}
|
||||
buffer = mask.Top();
|
||||
mask.Drop();
|
||||
SetRbuf();
|
||||
attr.mask = false;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
Matrix2D Translate2D(double x, double y)
|
||||
{
|
||||
Matrix2D m;
|
||||
m.tx = x;
|
||||
m.ty = y;
|
||||
return m;
|
||||
}
|
||||
|
||||
Matrix2D Rotate2D(double angle)
|
||||
{
|
||||
Matrix2D m;
|
||||
*(agg::trans_affine *)&m = agg::trans_affine_rotation(angle);
|
||||
return m;
|
||||
}
|
||||
|
||||
Matrix2D Scale2D(double scalex, double scaley)
|
||||
{
|
||||
Matrix2D m;
|
||||
*(agg::trans_affine *)&m = agg::trans_affine_scaling(scalex, scaley);
|
||||
return m;
|
||||
}
|
||||
|
||||
Matrix2D Scale2D(double scale)
|
||||
{
|
||||
return Scale2D(scale, scale);
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
template <class T>
|
||||
void sGet(T& r, StringStream& ss)
|
||||
{
|
||||
ss.Get(&r, sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
T sGet(StringStream& ss)
|
||||
{
|
||||
T r;
|
||||
ss.Get(&r, sizeof(T));
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
Pointf sGetPoint(StringStream& ss)
|
||||
{
|
||||
Pointf p;
|
||||
p.x = sGet<double>(ss);
|
||||
p.y = sGet<double>(ss);
|
||||
return p;
|
||||
}
|
||||
|
||||
void Painter::Paint(const Painting& pic)
|
||||
{
|
||||
StringStream ss(pic.cmd);
|
||||
Pointf p, p1, p2;
|
||||
RGBA c, c1;
|
||||
Value v;
|
||||
int f, ch, n, hasdx;
|
||||
Matrix2D m;
|
||||
double r, w;
|
||||
Font fnt;
|
||||
int ii = 0;
|
||||
for(;;) {
|
||||
int cmd = ss.Get();
|
||||
if(cmd < 0)
|
||||
return;
|
||||
bool rel = cmd & 1;
|
||||
switch(cmd) {
|
||||
case PAINTING_CLEAR:
|
||||
Clear(sGet<RGBA>(ss));
|
||||
break;
|
||||
case PAINTING_MOVE:
|
||||
case PAINTING_MOVE_REL:
|
||||
p = sGetPoint(ss);
|
||||
Move(p.x, p.y, rel);
|
||||
break;
|
||||
case PAINTING_LINE:
|
||||
case PAINTING_LINE_REL:
|
||||
p = sGetPoint(ss);
|
||||
Line(p.x, p.y, rel);
|
||||
break;
|
||||
case PAINTING_QUADRATIC:
|
||||
case PAINTING_QUADRATIC_REL:
|
||||
p1 = sGetPoint(ss);
|
||||
p = sGetPoint(ss);
|
||||
Quadratic(p1.x, p1.y, p.x, p.y, rel);
|
||||
break;
|
||||
case PAINTING_QUADRATIC_S:
|
||||
case PAINTING_QUADRATIC_S_REL:
|
||||
p = sGetPoint(ss);
|
||||
Quadratic(p.x, p.y, rel);
|
||||
break;
|
||||
case PAINTING_CUBIC:
|
||||
case PAINTING_CUBIC_REL:
|
||||
p1 = sGetPoint(ss);
|
||||
p2 = sGetPoint(ss);
|
||||
p = sGetPoint(ss);
|
||||
Cubic(p1.x, p1.y, p2.x, p2.y, p.x, p.y, rel);
|
||||
break;
|
||||
case PAINTING_CUBIC_S:
|
||||
case PAINTING_CUBIC_S_REL:
|
||||
p2 = sGetPoint(ss);
|
||||
p = sGetPoint(ss);
|
||||
Cubic(p2.x, p2.y, p.x, p.y, rel);
|
||||
break;
|
||||
case PAINTING_CLOSE:
|
||||
Close();
|
||||
break;
|
||||
case PAINTING_FILL_SOLID:
|
||||
Fill(sGet<RGBA>(ss));
|
||||
break;
|
||||
case PAINTING_FILL_IMAGE:
|
||||
sGet(m, ss);
|
||||
f = ss.Get();
|
||||
if(ii >= pic.data.GetCount())
|
||||
return;
|
||||
v = pic.data[ii++];
|
||||
if(!v.Is<Image>())
|
||||
return;
|
||||
Fill((Image)v, m, f);
|
||||
break;
|
||||
case PAINTING_FILL_GRADIENT:
|
||||
p = sGetPoint(ss);
|
||||
sGet(c, ss);
|
||||
p1 = sGetPoint(ss);
|
||||
sGet(c1, ss);
|
||||
f = ss.Get();
|
||||
Fill(p.x, p.y, c, p1.x, p1.y, c1, f);
|
||||
break;
|
||||
case PAINTING_FILL_RADIAL:
|
||||
p = sGetPoint(ss);
|
||||
sGet(c, ss);
|
||||
p1 = sGetPoint(ss);
|
||||
sGet(r, ss);
|
||||
sGet(c1, ss);
|
||||
f = ss.Get();
|
||||
Fill(p.x, p.y, c, p1.x, p1.y, r, c1, f);
|
||||
break;
|
||||
case PAINTING_STROKE_SOLID:
|
||||
sGet(w, ss);
|
||||
sGet(c, ss);
|
||||
Stroke(w, c);
|
||||
break;
|
||||
case PAINTING_STROKE_IMAGE:
|
||||
sGet(w, ss);
|
||||
sGet(m, ss);
|
||||
f = ss.Get();
|
||||
if(ii >= pic.data.GetCount())
|
||||
return;
|
||||
v = pic.data[ii++];
|
||||
if(!v.Is<Image>())
|
||||
return;
|
||||
Stroke(w, (Image)v, m, f);
|
||||
break;
|
||||
case PAINTING_STROKE_GRADIENT:
|
||||
sGet(w, ss);
|
||||
p = sGetPoint(ss);
|
||||
sGet(c, ss);
|
||||
p1 = sGetPoint(ss);
|
||||
sGet(c1, ss);
|
||||
f = ss.Get();
|
||||
Stroke(w, p.x, p.y, c, p1.x, p1.y, c1, f);
|
||||
break;
|
||||
case PAINTING_STROKE_RADIAL:
|
||||
sGet(w, ss);
|
||||
p = sGetPoint(ss);
|
||||
sGet(c, ss);
|
||||
p1 = sGetPoint(ss);
|
||||
sGet(r, ss);
|
||||
sGet(c1, ss);
|
||||
f = ss.Get();
|
||||
Stroke(w, p.x, p.y, c, p1.x, p1.y, r, c1, f);
|
||||
break;
|
||||
case PAINTING_CLIP:
|
||||
Clip();
|
||||
break;
|
||||
case PAINTING_CHARACTER:
|
||||
p = sGetPoint(ss);
|
||||
ch = ss.Get32();
|
||||
sGet(fnt, ss);
|
||||
Character(p.x, p.y, ch, fnt);
|
||||
break;
|
||||
case PAINTING_TEXT:
|
||||
{
|
||||
p = sGetPoint(ss);
|
||||
n = ss.Get32();
|
||||
hasdx = ss.Get();
|
||||
sGet(fnt, ss);
|
||||
Buffer<wchar> txt(n);
|
||||
Buffer<double> dx(hasdx * n);
|
||||
for(int i = 0; i < n; i++) {
|
||||
txt[i] = ss.Get32();
|
||||
if(hasdx)
|
||||
sGet(dx[i], ss);
|
||||
}
|
||||
Text(p.x, p.y, txt, fnt, n, hasdx ? ~dx : NULL);
|
||||
}
|
||||
break;
|
||||
case PAINTING_COLORSTOP:
|
||||
sGet(r, ss);
|
||||
sGet(c, ss);
|
||||
ColorStop(r, c);
|
||||
break;
|
||||
case PAINTING_CLEARSTOPS:
|
||||
ClearStops();
|
||||
break;
|
||||
case PAINTING_OPACITY:
|
||||
Opacity(sGet<double>(ss));
|
||||
break;
|
||||
case PAINTING_LINECAP:
|
||||
LineCap(ss.Get());
|
||||
break;
|
||||
case PAINTING_LINEJOIN:
|
||||
LineJoin(ss.Get());
|
||||
break;
|
||||
case PAINTING_MITERLIMIT:
|
||||
MiterLimit(ss.Get());
|
||||
break;
|
||||
case PAINTING_EVENODD:
|
||||
EvenOdd(ss.Get());
|
||||
break;
|
||||
case PAINTING_DASH:
|
||||
{
|
||||
n = ss.Get32();
|
||||
Vector<double> dash;
|
||||
for(int i = 0; i < n; i++)
|
||||
dash.Add(sGet<double>(ss));
|
||||
r = sGet<double>(ss);
|
||||
Dash(dash, r);
|
||||
}
|
||||
break;
|
||||
case PAINTING_NOAA:
|
||||
NoAA(ss.Get());
|
||||
break;
|
||||
case PAINTING_TRANSFORM:
|
||||
sGet(m, ss);
|
||||
Transform(m);
|
||||
break;
|
||||
case PAINTING_BEGIN:
|
||||
Begin();
|
||||
break;
|
||||
case PAINTING_END:
|
||||
End();
|
||||
break;
|
||||
case PAINTING_BEGINMASK:
|
||||
BeginMask();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintImageBufferPaintingFn(ImageBuffer& ib, const Painting& p, Size sz, Point pos, bool noaa)
|
||||
{
|
||||
BufferPainter sw(ib);
|
||||
sw.NoAA(noaa);
|
||||
Sizef psz = p.GetSize();
|
||||
sw.Translate(-pos.x, -pos.y);
|
||||
sw.Scale(sz.cx / psz.cx, sz.cy / psz.cy);
|
||||
sw.Paint(p);
|
||||
}
|
||||
|
||||
void PaintImageBufferDrawingFn(ImageBuffer& ib, const Drawing& iw, bool noaa)
|
||||
{
|
||||
BufferPainter sw(ib);
|
||||
sw.NoAA(noaa);
|
||||
Sizef sz = ib.GetSize();
|
||||
Size isz = iw.GetSize();
|
||||
sw.Scale(sz.cx / isz.cx, sz.cy / isz.cy);
|
||||
sw.DrawDrawing(0, 0, isz.cx, isz.cy, iw);
|
||||
}
|
||||
|
||||
void RegisterPaintingFns__(void (*ig)(ImageBuffer& ib, const Painting& pw, Size sz, Point pos, bool noaa),
|
||||
void (*iw)(ImageBuffer& ib, const Drawing& p, bool noaa));
|
||||
|
||||
|
||||
INITBLOCK
|
||||
{
|
||||
RegisterPaintingFns__(PaintImageBufferPaintingFn, PaintImageBufferDrawingFn);
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,278 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void Painter::OffsetOp(Point p)
|
||||
{
|
||||
Begin();
|
||||
Translate(p.x, p.y);
|
||||
}
|
||||
|
||||
void Painter::RectPath(int x, int y, int cx, int cy)
|
||||
{
|
||||
Move(x, y).Line(x + cx, y).Line(x + cx, y + cy).Line(x, y + cy).Close();
|
||||
}
|
||||
|
||||
void Painter::RectPath(const Rect& r)
|
||||
{
|
||||
RectPath(r.left, r.top, r.GetWidth(), r.GetHeight());
|
||||
}
|
||||
|
||||
bool Painter::ClipOp(const Rect& r)
|
||||
{
|
||||
Begin();
|
||||
RectPath(r);
|
||||
Clip();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Painter::ClipoffOp(const Rect& r)
|
||||
{
|
||||
Begin();
|
||||
RectPath(r);
|
||||
Clip();
|
||||
Translate(r.left, r.top);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Painter::ExcludeClipOp(const Rect& r)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Painter::IntersectClipOp(const Rect& r)
|
||||
{
|
||||
return true;
|
||||
RectPath(r);
|
||||
Clip();
|
||||
return true;
|
||||
}
|
||||
|
||||
Rect Painter::GetClipOp() const
|
||||
{
|
||||
return Rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
bool Painter::IsPaintingOp(const Rect& r) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Painter::DrawRectOp(int x, int y, int cx, int cy, Color color)
|
||||
{
|
||||
RectPath(x, y, cx, cy);
|
||||
Fill(color);
|
||||
}
|
||||
|
||||
void Painter::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color)
|
||||
{
|
||||
// Color and src support!!!
|
||||
RectPath(x, y, cx, cy);
|
||||
Fill(img, Translate2D(x, y));
|
||||
}
|
||||
|
||||
void Painter::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color)
|
||||
{
|
||||
double h = width / 2;
|
||||
Move(x1 + h, y1 + h);
|
||||
Line(x2 + h, y2 + h);
|
||||
Stroke(max(width, 0), color);
|
||||
}
|
||||
|
||||
void Painter::DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts,
|
||||
int count_count, int width, Color color, Color doxor)
|
||||
{
|
||||
}
|
||||
|
||||
void Painter::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count,
|
||||
const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts,
|
||||
int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor)
|
||||
{
|
||||
}
|
||||
|
||||
void Painter::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color)
|
||||
{
|
||||
}
|
||||
|
||||
void Painter::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor)
|
||||
{
|
||||
Sizef sz = r.GetSize();
|
||||
Ellipse(r.left + sz.cx / 2, r.top + sz.cy / 2, sz.cx / 2, sz.cy / 2);
|
||||
Fill(color);
|
||||
Stroke(max(pen, 0), pencolor);
|
||||
}
|
||||
|
||||
void Painter::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx)
|
||||
{
|
||||
Begin();
|
||||
EvenOdd(true);
|
||||
if(angle)
|
||||
Rotate(angle * M_2PI / 36000);
|
||||
if(n < 0)
|
||||
n = wstrlen(text);
|
||||
double *ddx = NULL;
|
||||
Buffer<double> h;
|
||||
if(dx) {
|
||||
h.Alloc(n);
|
||||
ddx = h;
|
||||
for(int i = 0; i < n; i++)
|
||||
ddx[i] = dx[i];
|
||||
}
|
||||
Text(x, y, text, font, n, ddx);
|
||||
Fill(ink);
|
||||
End();
|
||||
}
|
||||
|
||||
void Painter::DrawPaintingOp(const Rect& target, const Painting& p)
|
||||
{
|
||||
Size sz = target.GetSize();
|
||||
Sizef psz = p.GetSize();
|
||||
Begin();
|
||||
Translate(target.left, target.top);
|
||||
Scale(sz.cx / psz.cx, sz.cy / psz.cy);
|
||||
Paint(p);
|
||||
End();
|
||||
}
|
||||
|
||||
Painter& Painter::Move(double x, double y)
|
||||
{
|
||||
return Move(x, y, false);
|
||||
}
|
||||
|
||||
Painter& Painter::Line(double x, double y)
|
||||
{
|
||||
return Line(x, y, false);
|
||||
}
|
||||
|
||||
Painter& Painter::Quadratic(double x1, double y1, double x, double y)
|
||||
{
|
||||
return Quadratic(x1, y1, x, y, false);
|
||||
}
|
||||
|
||||
Painter& Painter::Quadratic(double x, double y)
|
||||
{
|
||||
return Quadratic(x, y, false);
|
||||
}
|
||||
|
||||
Painter& Painter::Cubic(double x1, double y1, double x2, double y2, double x, double y)
|
||||
{
|
||||
return Cubic(x1, y1, x2, y2, x, y, false);
|
||||
}
|
||||
|
||||
Painter& Painter::Cubic(double x2, double y2, double x, double y)
|
||||
{
|
||||
return Cubic(x2, y2, x, y, false);
|
||||
}
|
||||
|
||||
Painter& Painter::RelMove(double x, double y)
|
||||
{
|
||||
return Move(x, y, true);
|
||||
}
|
||||
|
||||
Painter& Painter::RelLine(double x, double y)
|
||||
{
|
||||
return Line(x, y, true);
|
||||
}
|
||||
|
||||
Painter& Painter::RelQuadratic(double x1, double y1, double x, double y)
|
||||
{
|
||||
return Quadratic(x1, y1, x, y, true);
|
||||
}
|
||||
|
||||
Painter& Painter::RelQuadratic(double x, double y)
|
||||
{
|
||||
return Quadratic(x, y, true);
|
||||
}
|
||||
|
||||
Painter& Painter::RelCubic(double x1, double y1, double x2, double y2, double x, double y)
|
||||
{
|
||||
return Cubic(x1, y1, x2, y2, x, y, true);
|
||||
}
|
||||
|
||||
Painter& Painter::RelCubic(double x2, double y2, double x, double y)
|
||||
{
|
||||
return Cubic(x2, y2, x, y, true);
|
||||
}
|
||||
|
||||
Matrix2D GetImageLineMatrix(double x1, double y1, double x2, double y2, const Image& image)
|
||||
{
|
||||
Matrix2D m;
|
||||
Size sz = image.GetSize();
|
||||
m.scale(agg::calc_distance(x1, y1, x2, y2) / sz.cx);
|
||||
if(fabs(x2 - x1) < fabs(y2 - y1) * 1e-6)
|
||||
m.rotate(y2 > y1 ? M_PI_2 : -M_PI_2);
|
||||
else
|
||||
m.rotate(atan((y2 - y1) / (x2 - x1)));
|
||||
m.translate(x1, y1);
|
||||
return m;
|
||||
}
|
||||
|
||||
Painter& Painter::Fill(const Image& image, double x1, double y1,
|
||||
double x2, double y2, dword flags)
|
||||
{
|
||||
return Fill(image, GetImageLineMatrix(x1, y1, x2, y2, image), flags);
|
||||
}
|
||||
|
||||
Painter& Painter::Stroke(double width, const Image& image, double x1, double y1,
|
||||
double x2, double y2, dword flags)
|
||||
{
|
||||
return Stroke(width, image, GetImageLineMatrix(x1, y1, x2, y2, image), flags);
|
||||
}
|
||||
|
||||
Painter& Painter::Dash(const char *dash, double start)
|
||||
{
|
||||
Vector<double> d;
|
||||
CParser p(dash);
|
||||
try {
|
||||
while(!p.IsEof())
|
||||
if(p.Char(':'))
|
||||
start = p.ReadDouble();
|
||||
else
|
||||
d.Add(p.ReadDouble());
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
Dash(d, start);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Painter::Translate(double x, double y)
|
||||
{
|
||||
Transform(Translate2D(x, y));
|
||||
}
|
||||
|
||||
void Painter::Rotate(double a)
|
||||
{
|
||||
Transform(Rotate2D(a));
|
||||
}
|
||||
|
||||
void Painter::Scale(double scalex, double scaley)
|
||||
{
|
||||
Transform(Scale2D(scalex, scaley));
|
||||
}
|
||||
|
||||
void Painter::Scale(double scale)
|
||||
{
|
||||
Transform(Scale2D(scale));
|
||||
}
|
||||
|
||||
Painter& Painter::Ellipse(double x, double y, double rx, double ry)
|
||||
{
|
||||
return Arc(x, y, rx, ry, 0, M_2PI);
|
||||
}
|
||||
|
||||
Painter& Painter::Circle(double x, double y, double r)
|
||||
{
|
||||
return Ellipse(x, y, r, r);
|
||||
}
|
||||
|
||||
Painter& Painter::Rectangle(double x, double y, double cx, double cy)
|
||||
{
|
||||
Move(x, y);
|
||||
Line(x + cx, y);
|
||||
Line(x + cx, y + cy);
|
||||
Line(x, y + cy);
|
||||
Close();
|
||||
return *this;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
#ifndef _SDraw_SDraw_h
|
||||
#define _SDraw_SDraw_h
|
||||
|
||||
#include <Draw/Draw.h>
|
||||
|
||||
#define PAINTER_TIMING(x) // RTIMING(x)
|
||||
|
||||
#define AGGUPP 1
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_renderer_base.h"
|
||||
#include "agg_renderer_scanline.h"
|
||||
#include "agg_rasterizer_scanline_aa.h"
|
||||
#include "agg_scanline_u.h"
|
||||
#include "agg_scanline_p.h"
|
||||
#include "agg_path_storage.h"
|
||||
#include "agg_conv_transform.h"
|
||||
#include "agg_conv_stroke.h"
|
||||
#include "agg_conv_curve.h"
|
||||
#include "agg_conv_dash.h"
|
||||
#include "agg_span_allocator.h"
|
||||
#include "agg_span_interpolator_linear.h"
|
||||
#include "agg_alpha_mask_u8.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
struct Matrix2D : agg::trans_affine {
|
||||
Matrix2D operator*(const Matrix2D& s) const { Matrix2D x = *this; x *= s; return x; }
|
||||
|
||||
void Transform(double& x, double& y) const { transform(&x, &y); }
|
||||
Pointf Transformed(double x, double y) const { Transform(x, y); return Pointf(x, y); }
|
||||
Pointf Transformed(Pointf p) const { Transform(p.x, p.y); return p; }
|
||||
Matrix2D Inverted() const { Matrix2D h = *this; h.invert(); return h; }
|
||||
};
|
||||
|
||||
Matrix2D Translate2D(double x, double y);
|
||||
Matrix2D Rotate2D(double angle);
|
||||
Matrix2D Scale2D(double scalex, double scaley);
|
||||
Matrix2D Scale2D(double scale);
|
||||
Matrix2D Sheer2D();
|
||||
|
||||
enum {
|
||||
LINECAP_BUTT = agg::butt_cap,
|
||||
LINECAP_SQUARE = agg::square_cap,
|
||||
LINECAP_ROUND = agg::round_cap,
|
||||
|
||||
LINEJOIN_MITER = agg::miter_join_revert,
|
||||
LINEJOIN_ROUND = agg::round_join,
|
||||
LINEJOIN_BEVEL = agg::bevel_join,
|
||||
|
||||
FILL_EXACT = 0,
|
||||
|
||||
FILL_HPAD = 1,
|
||||
FILL_HREPEAT = 2,
|
||||
FILL_HREFLECT = 3,
|
||||
|
||||
FILL_VPAD = 4,
|
||||
FILL_VREPEAT = 8,
|
||||
FILL_VREFLECT = 12,
|
||||
|
||||
FILL_PAD = FILL_HPAD|FILL_VPAD,
|
||||
FILL_REPEAT = FILL_HREPEAT|FILL_VREPEAT,
|
||||
FILL_REFLECT = FILL_HREFLECT|FILL_VREFLECT,
|
||||
|
||||
FILL_FAST = 128,
|
||||
|
||||
GRADIENT_PAD = 0,
|
||||
GRADIENT_REPEAT = 1,
|
||||
GRADIENT_REFLECT = 2,
|
||||
};
|
||||
|
||||
class Painting;
|
||||
|
||||
class Painter : public Draw {
|
||||
protected:
|
||||
virtual void OffsetOp(Point p);
|
||||
virtual bool ClipOp(const Rect& r);
|
||||
virtual bool ClipoffOp(const Rect& r);
|
||||
virtual bool ExcludeClipOp(const Rect& r);
|
||||
virtual bool IntersectClipOp(const Rect& r);
|
||||
virtual Rect GetClipOp() const;
|
||||
virtual bool IsPaintingOp(const Rect& r) const;
|
||||
|
||||
virtual void DrawRectOp(int x, int y, int cx, int cy, Color color);
|
||||
virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color);
|
||||
virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color);
|
||||
|
||||
virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count,
|
||||
const int *counts, int count_count,
|
||||
int width, Color color, Color doxor);
|
||||
virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count,
|
||||
const int *subpolygon_counts, int scc,
|
||||
const int *disjunct_polygon_counts, int dpcc,
|
||||
Color color, int width, Color outline,
|
||||
uint64 pattern, Color doxor);
|
||||
virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color);
|
||||
|
||||
virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor);
|
||||
virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font,
|
||||
Color ink, int n, const int *dx);
|
||||
virtual void DrawPaintingOp(const Rect& target, const Painting& w);
|
||||
|
||||
protected:
|
||||
virtual void ClearOp(const RGBA& color) = 0;
|
||||
|
||||
virtual void MoveOp(double x, double y, bool rel) = 0;
|
||||
virtual void LineOp(double x, double y, bool rel) = 0;
|
||||
virtual void QuadraticOp(double x1, double y1, double x, double y, bool rel) = 0;
|
||||
virtual void QuadraticOp(double x, double y, bool rel) = 0;
|
||||
virtual void CubicOp(double x1, double y1, double x2, double y2, double x, double y, bool rel) = 0;
|
||||
virtual void CubicOp(double x2, double y2, double x, double y, bool rel) = 0;
|
||||
virtual void CloseOp() = 0;
|
||||
|
||||
virtual void FillOp(const RGBA& color) = 0;
|
||||
virtual void FillOp(const Image& image, const Matrix2D& transsrc, dword flags) = 0;
|
||||
virtual void FillOp(double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2,
|
||||
int style) = 0;
|
||||
virtual void FillOp(double fx, double fy, const RGBA& color1,
|
||||
double x1, double y1, double r, const RGBA& color2,
|
||||
int style) = 0;
|
||||
|
||||
virtual void StrokeOp(double width, const RGBA& rgba) = 0;
|
||||
virtual void StrokeOp(double width, const Image& image, const Matrix2D& transsrc,
|
||||
dword flags) = 0;
|
||||
virtual void StrokeOp(double width, double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2,
|
||||
int style) = 0;
|
||||
virtual void StrokeOp(double width, double fx, double fy, const RGBA& color1,
|
||||
double x, double y, double r, const RGBA& color2,
|
||||
int style) = 0;
|
||||
|
||||
virtual void ClipOp() = 0;
|
||||
|
||||
virtual void CharacterOp(double x, double y, int ch, Font fnt);
|
||||
virtual void TextOp(double x, double y, const wchar *text, Font fnt, int n = -1, double *dx = NULL);
|
||||
|
||||
virtual void ColorStopOp(double pos, const RGBA& color) = 0;
|
||||
virtual void ClearStopsOp() = 0;
|
||||
|
||||
virtual void OpacityOp(double o) = 0;
|
||||
virtual void LineCapOp(int linecap) = 0;
|
||||
virtual void LineJoinOp(int linejoin) = 0;
|
||||
virtual void MiterLimitOp(double l) = 0;
|
||||
virtual void EvenOddOp(bool evenodd) = 0;
|
||||
virtual void DashOp(const Vector<double>& dash, double start = 0) = 0;
|
||||
virtual void NoAAOp(bool noaa) = 0;
|
||||
|
||||
virtual void TransformOp(const Matrix2D& m) = 0;
|
||||
|
||||
virtual void BeginOp() = 0;
|
||||
virtual void EndOp() = 0;
|
||||
|
||||
virtual void BeginMaskOp() = 0;
|
||||
|
||||
private:
|
||||
Pointf ReadPoint(CParser& p);
|
||||
void RectPath(int x, int y, int cx, int cy);
|
||||
void RectPath(const Rect& r);
|
||||
|
||||
static RGBA GetRGBA(StringStream& ss);
|
||||
|
||||
public:
|
||||
void Clear(const RGBA& color);
|
||||
|
||||
Painter& Move(double x, double y, bool rel);
|
||||
Painter& Line(double x, double y, bool rel);
|
||||
Painter& Quadratic(double x1, double y1, double x, double y, bool rel);
|
||||
Painter& Quadratic(double x, double y, bool rel);
|
||||
Painter& Cubic(double x1, double y1, double x2, double y2, double x, double y, bool rel);
|
||||
Painter& Cubic(double x2, double y2, double x, double y, bool rel);
|
||||
|
||||
Painter& Move(double x, double y);
|
||||
Painter& Line(double x, double y);
|
||||
Painter& Quadratic(double x1, double y1, double x, double y);
|
||||
Painter& Quadratic(double x, double y);
|
||||
Painter& Cubic(double x1, double y1, double x2, double y2, double x, double y);
|
||||
Painter& Cubic(double x2, double y2, double x, double y);
|
||||
|
||||
Painter& RelMove(double x, double y);
|
||||
Painter& RelLine(double x, double y);
|
||||
Painter& RelQuadratic(double x1, double y1, double x, double y);
|
||||
Painter& RelQuadratic(double x, double y);
|
||||
Painter& RelCubic(double x1, double y1, double x2, double y2, double x, double y);
|
||||
Painter& RelCubic(double x2, double y2, double x, double y);
|
||||
|
||||
Painter& Close();
|
||||
|
||||
Painter& Fill(const RGBA& color);
|
||||
Painter& Fill(const Image& image, const Matrix2D& transsrc = Matrix2D(), dword flags = 0);
|
||||
Painter& Fill(const Image& image, double x1, double y1, double x2, double y2,
|
||||
dword flags = 0);
|
||||
Painter& Fill(double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2, int style = GRADIENT_PAD);
|
||||
Painter& Fill(double fx, double fy, const RGBA& color1,
|
||||
double x, double y, double r, const RGBA& color2, int style = GRADIENT_PAD);
|
||||
Painter& Fill(double x, double y, const RGBA& color1,
|
||||
double r, const RGBA& color2, int style = GRADIENT_PAD);
|
||||
|
||||
Painter& Stroke(double width, const RGBA& color);
|
||||
Painter& Stroke(double width, const Image& image, const Matrix2D& transsrc, dword flags = 0);
|
||||
Painter& Stroke(double width, const Image& image, double x1, double y1, double x2, double y2,
|
||||
dword flags = 0);
|
||||
Painter& Stroke(double width, double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2,
|
||||
int style = GRADIENT_PAD);
|
||||
Painter& Stroke(double width, double fx, double fy, const RGBA& color1,
|
||||
double x1, double y1, double r, const RGBA& color2, int style = GRADIENT_PAD);
|
||||
Painter& Stroke(double width, double x1, double y1, const RGBA& color1,
|
||||
double r, const RGBA& color2, int style = GRADIENT_PAD);
|
||||
|
||||
Painter& Clip();
|
||||
|
||||
Painter& Character(double x, double y, int ch, Font fnt);
|
||||
Painter& Text(double x, double y, const wchar *text, Font fnt, int n = -1, double *dx = NULL);
|
||||
Painter& Text(double x, double y, const WString& s, Font fnt, double *dx = NULL);
|
||||
Painter& Text(double x, double y, const String& s, Font fnt, double *dx = NULL);
|
||||
Painter& Text(double x, double y, const char *text, Font fnt, int n = -1, double *dx = NULL);
|
||||
|
||||
Painter& Path(CParser& p);
|
||||
Painter& Path(const char *path);
|
||||
|
||||
Painter& ColorStop(double pos, const RGBA& color);
|
||||
Painter& ClearStops();
|
||||
|
||||
Painter& Opacity(double o);
|
||||
Painter& LineCap(int linecap);
|
||||
Painter& LineJoin(int linejoin);
|
||||
Painter& MiterLimit(double l);
|
||||
Painter& EvenOdd(bool evenodd);
|
||||
Painter& Dash(const Vector<double>& dash, double start = 0);
|
||||
Painter& Dash(const char *dash, double start = 0);
|
||||
Painter& NoAA(bool noaa = true);
|
||||
|
||||
void Transform(const Matrix2D& m);
|
||||
|
||||
void Begin();
|
||||
void End();
|
||||
|
||||
void BeginMask();
|
||||
|
||||
void Translate(double x, double y);
|
||||
void Rotate(double a);
|
||||
void Scale(double scalex, double scaley);
|
||||
void Scale(double scale);
|
||||
|
||||
void Paint(const Painting& p);
|
||||
|
||||
Painter& Arc(double x, double y, double rx, double ry,
|
||||
double start_angle, double sweep_angle, bool startline = false);
|
||||
Painter& Ellipse(double x, double y, double rx, double ry);
|
||||
Painter& Circle(double x, double y, double r);
|
||||
Painter& Rectangle(double x, double y, double cx, double cy);
|
||||
};
|
||||
|
||||
#include "BufferPainter.h"
|
||||
#include "Painting.h"
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
||||
#include "Painter.hpp"
|
||||
|
||||
#endif
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
NAMESPACE_UPP
|
||||
|
||||
inline void Painter::Clear(const RGBA& color)
|
||||
{
|
||||
ClearOp(color);
|
||||
}
|
||||
|
||||
inline Painter& Painter::Move(double x, double y, bool rel)
|
||||
{
|
||||
MoveOp(x, y, rel);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Line(double x, double y, bool rel)
|
||||
{
|
||||
LineOp(x, y, rel);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Quadratic(double x1, double y1, double x, double y, bool rel)
|
||||
{
|
||||
QuadraticOp(x1, y1, x, y, rel);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Quadratic(double x, double y, bool rel)
|
||||
{
|
||||
QuadraticOp(x, y, rel);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Cubic(double x1, double y1, double x2, double y2, double x, double y, bool rel)
|
||||
{
|
||||
CubicOp(x1, y1, x2, y2, x, y, rel);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Cubic(double x2, double y2, double x, double y, bool rel)
|
||||
{
|
||||
CubicOp(x2, y2, x, y, rel);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Close()
|
||||
{
|
||||
CloseOp();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Fill(const RGBA& color)
|
||||
{
|
||||
FillOp(color);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Fill(const Image& image, const Matrix2D& transsrc, dword flags)
|
||||
{
|
||||
FillOp(image, transsrc, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Fill(double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2, int style)
|
||||
{
|
||||
FillOp(x1, y1, color1, x2, y2, color2, style);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Fill(double fx, double fy, const RGBA& color1, double x1, double y1, double r, const RGBA& color2, int style)
|
||||
{
|
||||
FillOp(fx, fy, color1, x1, y1, r, color2, style);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Fill(double x1, double y1, const RGBA& color1, double r, const RGBA& color2, int style)
|
||||
{
|
||||
return Fill(x1, y1, color1, x1, y1, r, color2, style);
|
||||
}
|
||||
|
||||
inline Painter& Painter::Stroke(double width, const RGBA& color)
|
||||
{
|
||||
StrokeOp(width, color);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Stroke(double width, const Image& image, const Matrix2D& transsrc, dword flags)
|
||||
{
|
||||
StrokeOp(width, image, transsrc, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Stroke(double width, double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2, int style)
|
||||
{
|
||||
StrokeOp(width, x1, y1, color1, x2, y2, color2, style);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Stroke(double width, double fx, double fy, const RGBA& color1,
|
||||
double x1, double y1, double r, const RGBA& color2, int style)
|
||||
{
|
||||
StrokeOp(width, fx, fy, color1, x1, y1, r, color2, style);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Stroke(double width, double x1, double y1, const RGBA& color1, double r, const RGBA& color2, int style)
|
||||
{
|
||||
return Stroke(width, x1, y1, color1, x1, y1, r, color2, style);
|
||||
}
|
||||
|
||||
inline Painter& Painter::Clip()
|
||||
{
|
||||
ClipOp();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::ColorStop(double pos, const RGBA& color)
|
||||
{
|
||||
ColorStopOp(pos, color);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::ClearStops()
|
||||
{
|
||||
ClearStopsOp();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Opacity(double o)
|
||||
{
|
||||
OpacityOp(o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::LineCap(int linecap)
|
||||
{
|
||||
LineCapOp(linecap);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::LineJoin(int linejoin)
|
||||
{
|
||||
LineJoinOp(linejoin);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::MiterLimit(double l)
|
||||
{
|
||||
MiterLimitOp(l);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::EvenOdd(bool evenodd)
|
||||
{
|
||||
EvenOddOp(evenodd);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::Dash(const Vector<double>& dash, double start)
|
||||
{
|
||||
if(dash.GetCount() & 1) {
|
||||
Vector<double> dash1;
|
||||
dash1.Append(dash);
|
||||
dash1.Append(dash);
|
||||
DashOp(dash1, start);
|
||||
}
|
||||
else
|
||||
DashOp(dash, start);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Painter& Painter::NoAA(bool noaa)
|
||||
{
|
||||
NoAAOp(noaa);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void Painter::Transform(const Matrix2D& m)
|
||||
{
|
||||
TransformOp(m);
|
||||
}
|
||||
|
||||
inline void Painter::Begin()
|
||||
{
|
||||
BeginOp();
|
||||
}
|
||||
|
||||
inline void Painter::End()
|
||||
{
|
||||
EndOp();
|
||||
}
|
||||
|
||||
inline void Painter::BeginMask()
|
||||
{
|
||||
BeginMaskOp();
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
description "Advanced rendering system";
|
||||
|
||||
optimize_speed;
|
||||
|
||||
file
|
||||
Painter.h,
|
||||
Painter.hpp,
|
||||
Matrix2D.cpp,
|
||||
Painter.cpp,
|
||||
Arc.cpp,
|
||||
FontX11.cpp,
|
||||
FontWin32.cpp,
|
||||
Text.cpp,
|
||||
Path.cpp,
|
||||
BufferPainter.h,
|
||||
PixFmt.cpp,
|
||||
BufferPainter.cpp,
|
||||
Context.cpp,
|
||||
Fill.cpp,
|
||||
Gradient.cpp,
|
||||
RadialGradient.cpp,
|
||||
Stroke.cpp,
|
||||
Clip.cpp,
|
||||
Mask.cpp,
|
||||
Painting.h,
|
||||
Painting.cpp,
|
||||
PaintPainting.icpp,
|
||||
agg readonly separator,
|
||||
agg_array.h,
|
||||
agg_alpha_mask_u8.h,
|
||||
agg_basics.h,
|
||||
agg_clip_liang_barsky.h,
|
||||
agg_config.h,
|
||||
agg_conv_adaptor_vcgen.h,
|
||||
agg_conv_curve.h,
|
||||
agg_conv_dash.h,
|
||||
agg_conv_stroke.h,
|
||||
agg_conv_transform.h,
|
||||
agg_curves.h,
|
||||
agg_curves.cpp,
|
||||
agg_dda_line.h,
|
||||
agg_gamma_functions.h,
|
||||
agg_math.h,
|
||||
agg_path_storage.h,
|
||||
agg_rasterizer_cells_aa.h,
|
||||
agg_rasterizer_scanline_aa.h,
|
||||
agg_rasterizer_sl_clip.h,
|
||||
agg_renderer_base.h,
|
||||
agg_renderer_scanline.h,
|
||||
agg_rendering_buffer.h,
|
||||
agg_scanline_p.h,
|
||||
agg_span_allocator.h,
|
||||
agg_span_interpolator_linear.h,
|
||||
agg_trans_affine.h,
|
||||
agg_trans_affine.cpp,
|
||||
agg_shorten_path.h,
|
||||
agg_math_stroke.h,
|
||||
agg_vcgen_stroke.h,
|
||||
agg_vcgen_stroke.cpp,
|
||||
agg_vcgen_dash.h,
|
||||
agg_vcgen_dash.cpp,
|
||||
agg_vertex_sequence.h;
|
||||
|
||||
|
|
@ -1,256 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void PaintingPainter::ClearOp(const RGBA& color)
|
||||
{
|
||||
Put(PAINTING_CLEAR);
|
||||
Put(color);
|
||||
}
|
||||
|
||||
void PaintingPainter::MoveOp(double x, double y, bool rel)
|
||||
{
|
||||
Put(PAINTING_MOVE + rel);
|
||||
Putf(x, y);
|
||||
}
|
||||
|
||||
void PaintingPainter::LineOp(double x, double y, bool rel)
|
||||
{
|
||||
Put(PAINTING_LINE + rel);
|
||||
Putf(x, y);
|
||||
}
|
||||
|
||||
void PaintingPainter::QuadraticOp(double x1, double y1, double x, double y, bool rel)
|
||||
{
|
||||
Put(PAINTING_QUADRATIC + rel);
|
||||
Putf(x1, y1);
|
||||
Putf(x, y);
|
||||
}
|
||||
|
||||
void PaintingPainter::QuadraticOp(double x, double y, bool rel)
|
||||
{
|
||||
Put(PAINTING_QUADRATIC_S + rel);
|
||||
Putf(x, y);
|
||||
}
|
||||
|
||||
void PaintingPainter::CubicOp(double x1, double y1, double x2, double y2, double x, double y, bool rel)
|
||||
{
|
||||
Put(PAINTING_CUBIC + rel);
|
||||
Putf(x1, y1);
|
||||
Putf(x2, y2);
|
||||
Putf(x, y);
|
||||
}
|
||||
|
||||
void PaintingPainter::CubicOp(double x2, double y2, double x, double y, bool rel)
|
||||
{
|
||||
Put(PAINTING_CUBIC_S + rel);
|
||||
Putf(x2, y2);
|
||||
Putf(x, y);
|
||||
}
|
||||
|
||||
void PaintingPainter::CloseOp()
|
||||
{
|
||||
Put(PAINTING_CLOSE);
|
||||
}
|
||||
|
||||
void PaintingPainter::FillOp(const RGBA& color)
|
||||
{
|
||||
Put(PAINTING_FILL_SOLID);
|
||||
Put(color);
|
||||
}
|
||||
|
||||
void PaintingPainter::FillOp(const Image& image, const Matrix2D& transsrc, dword flags)
|
||||
{
|
||||
Put(PAINTING_FILL_IMAGE);
|
||||
Putf(transsrc);
|
||||
Put(flags);
|
||||
data.Add(image);
|
||||
}
|
||||
|
||||
void PaintingPainter::FillOp(double x1, double y1, const RGBA& color1, double x2, double y2, const RGBA& color2, int style)
|
||||
{
|
||||
Put(PAINTING_FILL_GRADIENT);
|
||||
Putf(x1, y1);
|
||||
Put(color1);
|
||||
Putf(x2, y2);
|
||||
Put(color2);
|
||||
Put(style);
|
||||
}
|
||||
|
||||
void PaintingPainter::FillOp(double fx, double fy, const RGBA& color1, double x, double y, double r, const RGBA& color2, int style)
|
||||
{
|
||||
Put(PAINTING_FILL_RADIAL);
|
||||
Putf(fx, fy);
|
||||
Put(color1);
|
||||
Putf(x, y);
|
||||
Putf(r);
|
||||
Put(color2);
|
||||
Put(style);
|
||||
}
|
||||
|
||||
void PaintingPainter::StrokeOp(double width, const RGBA& color)
|
||||
{
|
||||
Put(PAINTING_STROKE_SOLID);
|
||||
Putf(width);
|
||||
Put(color);
|
||||
}
|
||||
|
||||
void PaintingPainter::StrokeOp(double width, const Image& image, const Matrix2D& transsrc, dword flags)
|
||||
{
|
||||
Put(PAINTING_STROKE_IMAGE);
|
||||
Putf(width);
|
||||
Putf(transsrc);
|
||||
Put(flags);
|
||||
data.Add(image);
|
||||
}
|
||||
|
||||
void PaintingPainter::StrokeOp(double width, double x1, double y1, const RGBA& color1, double x2, double y2, const RGBA& color2, int style)
|
||||
{
|
||||
Put(PAINTING_STROKE_GRADIENT);
|
||||
Putf(width);
|
||||
Putf(x1, y1);
|
||||
Put(color1);
|
||||
Putf(x2, y2);
|
||||
Put(color2);
|
||||
Put(style);
|
||||
}
|
||||
|
||||
void PaintingPainter::StrokeOp(double width, double fx, double fy, const RGBA& color1, double x, double y, double r, const RGBA& color2, int style)
|
||||
{
|
||||
Put(PAINTING_STROKE_RADIAL);
|
||||
Putf(width);
|
||||
Putf(fx, fy);
|
||||
Put(color1);
|
||||
Putf(x, y);
|
||||
Putf(r);
|
||||
Put(color2);
|
||||
Put(style);
|
||||
}
|
||||
|
||||
void PaintingPainter::ClipOp()
|
||||
{
|
||||
Put(PAINTING_CLIP);
|
||||
}
|
||||
|
||||
void PaintingPainter::CharacterOp(double x, double y, int ch, Font fnt)
|
||||
{
|
||||
Put(PAINTING_CHARACTER);
|
||||
Putf(x, y);
|
||||
Put32(ch);
|
||||
Put(fnt);
|
||||
}
|
||||
|
||||
void PaintingPainter::TextOp(double x, double y, const wchar *text, Font fnt, int n, double *dx)
|
||||
{
|
||||
Put(PAINTING_TEXT);
|
||||
Putf(x, y);
|
||||
Put32(n);
|
||||
Put((bool)dx);
|
||||
Put(fnt);
|
||||
for(int i = 0; i < n; i++) {
|
||||
Put32(text[i]);
|
||||
if(dx)
|
||||
Putf(dx[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintingPainter::ColorStopOp(double pos, const RGBA& color)
|
||||
{
|
||||
Put(PAINTING_COLORSTOP);
|
||||
Putf(pos);
|
||||
Put(color);
|
||||
}
|
||||
|
||||
void PaintingPainter::ClearStopsOp()
|
||||
{
|
||||
Put(PAINTING_CLEARSTOPS);
|
||||
}
|
||||
|
||||
void PaintingPainter::OpacityOp(double o)
|
||||
{
|
||||
Put(PAINTING_OPACITY);
|
||||
Putf(o);
|
||||
}
|
||||
|
||||
void PaintingPainter::LineCapOp(int linecap)
|
||||
{
|
||||
Put(PAINTING_LINECAP);
|
||||
Put(linecap);
|
||||
}
|
||||
|
||||
void PaintingPainter::LineJoinOp(int linejoin)
|
||||
{
|
||||
Put(PAINTING_LINEJOIN);
|
||||
Put(linejoin);
|
||||
}
|
||||
|
||||
void PaintingPainter::MiterLimitOp(double l)
|
||||
{
|
||||
Put(PAINTING_MITERLIMIT);
|
||||
Putf(l);
|
||||
}
|
||||
|
||||
void PaintingPainter::EvenOddOp(bool evenodd)
|
||||
{
|
||||
Put(PAINTING_EVENODD);
|
||||
Put(evenodd);
|
||||
}
|
||||
|
||||
void PaintingPainter::DashOp(const Vector<double>& dash, double start)
|
||||
{
|
||||
Put(PAINTING_DASH);
|
||||
Put32(dash.GetCount());
|
||||
for(int i = 0; i < dash.GetCount(); i++)
|
||||
Putf(dash[i]);
|
||||
Putf(start);
|
||||
}
|
||||
|
||||
void PaintingPainter::NoAAOp(bool noaa)
|
||||
{
|
||||
Put(PAINTING_NOAA);
|
||||
Put(noaa);
|
||||
}
|
||||
|
||||
void PaintingPainter::TransformOp(const Matrix2D& m)
|
||||
{
|
||||
Put(PAINTING_TRANSFORM);
|
||||
Putf(m);
|
||||
}
|
||||
|
||||
void PaintingPainter::BeginOp()
|
||||
{
|
||||
Put(PAINTING_BEGIN);
|
||||
}
|
||||
|
||||
void PaintingPainter::EndOp()
|
||||
{
|
||||
Put(PAINTING_END);
|
||||
}
|
||||
|
||||
void PaintingPainter::BeginMaskOp()
|
||||
{
|
||||
Put(PAINTING_BEGINMASK);
|
||||
}
|
||||
|
||||
Painting PaintingPainter::GetResult()
|
||||
{
|
||||
Painting p;
|
||||
p.cmd = cmd.GetResult();
|
||||
p.data = data;
|
||||
p.size = size;
|
||||
return p;
|
||||
}
|
||||
|
||||
void PaintingPainter::Create(double cx, double cy)
|
||||
{
|
||||
cmd.Create();
|
||||
size.cx = cx;
|
||||
size.cy = cy;
|
||||
}
|
||||
|
||||
void PaintingPainter::Create(Sizef sz)
|
||||
{
|
||||
Create(sz.cx, sz.cy);
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
enum {
|
||||
PAINTING_EOF,
|
||||
PAINTING_CLEAR,
|
||||
|
||||
PAINTING_MOVE,
|
||||
PAINTING_MOVE_REL,
|
||||
PAINTING_LINE,
|
||||
PAINTING_LINE_REL,
|
||||
PAINTING_QUADRATIC,
|
||||
PAINTING_QUADRATIC_REL,
|
||||
PAINTING_QUADRATIC_S,
|
||||
PAINTING_QUADRATIC_S_REL,
|
||||
PAINTING_CUBIC,
|
||||
PAINTING_CUBIC_REL,
|
||||
PAINTING_CUBIC_S,
|
||||
PAINTING_CUBIC_S_REL,
|
||||
PAINTING_CLOSE,
|
||||
|
||||
PAINTING_FILL_SOLID,
|
||||
PAINTING_FILL_IMAGE,
|
||||
PAINTING_FILL_GRADIENT,
|
||||
PAINTING_FILL_RADIAL,
|
||||
|
||||
PAINTING_STROKE_SOLID,
|
||||
PAINTING_STROKE_IMAGE,
|
||||
PAINTING_STROKE_GRADIENT,
|
||||
PAINTING_STROKE_RADIAL,
|
||||
|
||||
PAINTING_CLIP,
|
||||
|
||||
PAINTING_CHARACTER,
|
||||
PAINTING_TEXT,
|
||||
|
||||
PAINTING_COLORSTOP,
|
||||
PAINTING_CLEARSTOPS,
|
||||
PAINTING_OPACITY,
|
||||
PAINTING_LINECAP,
|
||||
PAINTING_LINEJOIN,
|
||||
PAINTING_MITERLIMIT,
|
||||
PAINTING_EVENODD,
|
||||
PAINTING_DASH,
|
||||
PAINTING_NOAA,
|
||||
|
||||
PAINTING_TRANSFORM,
|
||||
PAINTING_BEGIN,
|
||||
PAINTING_END,
|
||||
PAINTING_BEGINMASK,
|
||||
};
|
||||
|
||||
class PaintingPainter : public Painter {
|
||||
StringStream cmd;
|
||||
ValueArray data;
|
||||
Sizef size;
|
||||
|
||||
void Put(int c) { cmd.Put(c); }
|
||||
void Put32(int c) { cmd.Put32(c); }
|
||||
void Put(const RGBA& c) { cmd.Put(&c, sizeof(RGBA)); }
|
||||
void Putf(double d) { cmd.Put(&d, sizeof(double)); }
|
||||
void Putf(double x, double y) { Putf(x); Putf(y); }
|
||||
void Putf(const Matrix2D& m) { cmd.Put(&m, sizeof(Matrix2D)); }
|
||||
void Put(const Font& f) { cmd.Put(&f, sizeof(Font)); }
|
||||
|
||||
protected:
|
||||
virtual void ClearOp(const RGBA& color);
|
||||
|
||||
virtual void MoveOp(double x, double y, bool rel);
|
||||
virtual void LineOp(double x, double y, bool rel);
|
||||
virtual void QuadraticOp(double x1, double y1, double x, double y, bool rel);
|
||||
virtual void QuadraticOp(double x, double y, bool rel);
|
||||
virtual void CubicOp(double x1, double y1, double x2, double y2, double x, double y, bool rel);
|
||||
virtual void CubicOp(double x2, double y2, double x, double y, bool rel);
|
||||
virtual void CloseOp();
|
||||
|
||||
virtual void FillOp(const RGBA& color);
|
||||
virtual void FillOp(const Image& image, const Matrix2D& transsrc, dword flags);
|
||||
virtual void FillOp(double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2,
|
||||
int style);
|
||||
virtual void FillOp(double fx, double fy, const RGBA& color1,
|
||||
double x1, double y1, double r, const RGBA& color2,
|
||||
int style);
|
||||
|
||||
virtual void StrokeOp(double width, const RGBA& rgba);
|
||||
virtual void StrokeOp(double width, const Image& image, const Matrix2D& transsrc,
|
||||
dword flags);
|
||||
virtual void StrokeOp(double width, double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2,
|
||||
int style);
|
||||
virtual void StrokeOp(double width, double fx, double fy, const RGBA& color1,
|
||||
double x, double y, double r, const RGBA& color2,
|
||||
int style);
|
||||
|
||||
virtual void ClipOp();
|
||||
|
||||
virtual void CharacterOp(double x, double y, int ch, Font fnt);
|
||||
virtual void TextOp(double x, double y, const wchar *text, Font fnt, int n = -1, double *dx = NULL);
|
||||
|
||||
virtual void ColorStopOp(double pos, const RGBA& color);
|
||||
virtual void ClearStopsOp();
|
||||
|
||||
virtual void OpacityOp(double o);
|
||||
virtual void LineCapOp(int linecap);
|
||||
virtual void LineJoinOp(int linejoin);
|
||||
virtual void MiterLimitOp(double l);
|
||||
virtual void EvenOddOp(bool evenodd);
|
||||
virtual void DashOp(const Vector<double>& dash, double start);
|
||||
virtual void NoAAOp(bool noaa);
|
||||
|
||||
virtual void TransformOp(const Matrix2D& m);
|
||||
|
||||
virtual void BeginOp();
|
||||
virtual void EndOp();
|
||||
|
||||
virtual void BeginMaskOp();
|
||||
|
||||
public:
|
||||
Painting GetResult();
|
||||
operator Painting() { return GetResult(); }
|
||||
|
||||
void Create(double cx, double cy);
|
||||
void Create(Sizef sz);
|
||||
|
||||
Sizef GetSize() const { return size; }
|
||||
|
||||
PaintingPainter() {}
|
||||
PaintingPainter(double cx, double cy) { Create(cx, cy); }
|
||||
PaintingPainter(Sizef sz) { Create(sz); }
|
||||
};
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
Pointf Painter::ReadPoint(CParser& p)
|
||||
{
|
||||
Pointf t;
|
||||
t.x = p.IsDouble() ? p.ReadDouble() : 0;
|
||||
p.Char(',');
|
||||
t.y = p.IsDouble() ? p.ReadDouble() : 0;
|
||||
return t;
|
||||
}
|
||||
|
||||
Painter& Painter::Path(CParser& p)
|
||||
{
|
||||
while(!p.IsEof()) {
|
||||
int c = p.GetChar();
|
||||
p.Spaces();
|
||||
bool rel = IsLower(c);
|
||||
Pointf t, t1, t2;
|
||||
switch(ToUpper(c)) {
|
||||
case 'M':
|
||||
t = ReadPoint(p);
|
||||
Move(t.x, t.y);
|
||||
case 'L':
|
||||
while(p.IsDouble()) {
|
||||
t = ReadPoint(p);
|
||||
Line(t.x, t.y, rel);
|
||||
}
|
||||
break;
|
||||
case 'Z':
|
||||
Close();
|
||||
break;
|
||||
case 'H':
|
||||
while(p.IsDouble())
|
||||
Line(p.ReadDouble(), Null, rel);
|
||||
break;
|
||||
case 'V':
|
||||
while(p.IsDouble())
|
||||
Line(Null, p.ReadDouble(), rel);
|
||||
break;
|
||||
case 'C':
|
||||
while(p.IsDouble()) {
|
||||
t1 = ReadPoint(p);
|
||||
t2 = ReadPoint(p);
|
||||
t = ReadPoint(p);
|
||||
Cubic(t1.x, t1.y, t2.x, t2.y, t.x, t.y, rel);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
while(p.IsDouble()) {
|
||||
t2 = ReadPoint(p);
|
||||
t = ReadPoint(p);
|
||||
Cubic(t2.x, t2.y, t.x, t.y, rel);
|
||||
}
|
||||
break;
|
||||
case 'Q':
|
||||
while(p.IsDouble()) {
|
||||
t1 = ReadPoint(p);
|
||||
t = ReadPoint(p);
|
||||
Quadratic(t1.x, t1.y, t.x, t.y, rel);
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
while(p.IsDouble()) {
|
||||
t = ReadPoint(p);
|
||||
Quadratic(t.x, t.y, rel);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Painter& Painter::Path(const char *path)
|
||||
{
|
||||
CParser p(path);
|
||||
Path(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void BufferPainter::upp_pixfmt::blend_hline(int x, int y, int len, RGBA c, byte cover)
|
||||
{
|
||||
PAINTER_TIMING("Blend hline");
|
||||
if(c.a == 0) return;
|
||||
RGBA *t = ptr(x, y);
|
||||
if(noaa)
|
||||
cover = cover > 127 ? 255 : 0;
|
||||
if((c.a & cover) == 255) {
|
||||
#if 1
|
||||
while(len >= 16) {
|
||||
t[0] = c; t[1] = c; t[2] = c; t[3] = c;
|
||||
t[4] = c; t[5] = c; t[6] = c; t[7] = c;
|
||||
t[8] = c; t[9] = c; t[10] = c; t[11] = c;
|
||||
t[12] = c; t[13] = c; t[14] = c; t[15] = c;
|
||||
t += 16;
|
||||
len -= 16;
|
||||
}
|
||||
switch(len) {
|
||||
case 15: t[14] = c;
|
||||
case 14: t[13] = c;
|
||||
case 13: t[12] = c;
|
||||
case 12: t[11] = c;
|
||||
case 11: t[10] = c;
|
||||
case 10: t[9] = c;
|
||||
case 9: t[8] = c;
|
||||
case 8: t[7] = c;
|
||||
case 7: t[6] = c;
|
||||
case 6: t[5] = c;
|
||||
case 5: t[4] = c;
|
||||
case 4: t[3] = c;
|
||||
case 3: t[2] = c;
|
||||
case 2: t[1] = c;
|
||||
case 1: t[0] = c;
|
||||
}
|
||||
#else
|
||||
do
|
||||
*t++ = c;
|
||||
while(--len);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if(cover != 255)
|
||||
c = MulA(c, cover);
|
||||
RGBA *e = t + len;
|
||||
int alpha = 256 - (c.a + (c.a >> 7));
|
||||
while(t < e)
|
||||
AlphaBlend(*t++, c);
|
||||
}
|
||||
FinishBlend();
|
||||
}
|
||||
|
||||
void BufferPainter::upp_pixfmt::blend_solid_hspan(int x, int y, int len,
|
||||
const RGBA& c, const byte *covers)
|
||||
{
|
||||
PAINTER_TIMING("Blend solid hspan");
|
||||
if(c.a == 0) return;
|
||||
RGBA *t = ptr(x, y);
|
||||
#ifdef USE_MMX
|
||||
if(!noaa) {
|
||||
AlphaBlendCover((dword *)t, *(dword *)&c, covers, len);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
RGBA *e = t + len;
|
||||
while(t < e) {
|
||||
byte cover = *covers++;
|
||||
if(noaa)
|
||||
cover = cover > 127 ? 255 : 0;
|
||||
if((cover & c.a) == 255) // is it worth it?
|
||||
*t++ = c;
|
||||
else
|
||||
AlphaBlendCover(*t++, c, cover);
|
||||
}
|
||||
#endif
|
||||
FinishBlend();
|
||||
}
|
||||
|
||||
void BufferPainter::upp_pixfmt::blend_color_hspan(int x, int y, int len, const RGBA *colors,
|
||||
const byte *covers, byte cover)
|
||||
{
|
||||
PAINTER_TIMING("Blend color hspan");
|
||||
RGBA *t = ptr(x, y);
|
||||
RGBA *e = t + len;
|
||||
if(noaa)
|
||||
cover = cover > 127 ? 255 : 0;
|
||||
while(t < e) {
|
||||
if(covers) {
|
||||
cover = *covers++;
|
||||
if(noaa)
|
||||
cover = cover > 127 ? 255 : 0;
|
||||
}
|
||||
if((cover & colors->a) == 255)
|
||||
*t = *colors;
|
||||
else
|
||||
if(cover == 255)
|
||||
AlphaBlend(*t, *colors);
|
||||
else
|
||||
AlphaBlendCover(*t, *colors, cover);
|
||||
colors++;
|
||||
t++;
|
||||
}
|
||||
FinishBlend();
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
uint16 g_sqrt_table[1024] = //----------g_sqrt_table
|
||||
{
|
||||
0,
|
||||
2048,2896,3547,4096,4579,5017,5418,5793,6144,6476,6792,7094,7384,7663,7932,8192,8444,
|
||||
8689,8927,9159,9385,9606,9822,10033,10240,10443,10642,10837,11029,11217,11403,11585,
|
||||
11765,11942,12116,12288,12457,12625,12790,12953,13114,13273,13430,13585,13738,13890,
|
||||
14040,14189,14336,14482,14626,14768,14910,15050,15188,15326,15462,15597,15731,15864,
|
||||
15995,16126,16255,16384,16512,16638,16764,16888,17012,17135,17257,17378,17498,17618,
|
||||
17736,17854,17971,18087,18203,18318,18432,18545,18658,18770,18882,18992,19102,19212,
|
||||
19321,19429,19537,19644,19750,19856,19961,20066,20170,20274,20377,20480,20582,20684,
|
||||
20785,20886,20986,21085,21185,21283,21382,21480,21577,21674,21771,21867,21962,22058,
|
||||
22153,22247,22341,22435,22528,22621,22713,22806,22897,22989,23080,23170,23261,23351,
|
||||
23440,23530,23619,23707,23796,23884,23971,24059,24146,24232,24319,24405,24491,24576,
|
||||
24661,24746,24831,24915,24999,25083,25166,25249,25332,25415,25497,25580,25661,25743,
|
||||
25824,25905,25986,26067,26147,26227,26307,26387,26466,26545,26624,26703,26781,26859,
|
||||
26937,27015,27092,27170,27247,27324,27400,27477,27553,27629,27705,27780,27856,27931,
|
||||
28006,28081,28155,28230,28304,28378,28452,28525,28599,28672,28745,28818,28891,28963,
|
||||
29035,29108,29180,29251,29323,29394,29466,29537,29608,29678,29749,29819,29890,29960,
|
||||
30030,30099,30169,30238,30308,30377,30446,30515,30583,30652,30720,30788,30856,30924,
|
||||
30992,31059,31127,31194,31261,31328,31395,31462,31529,31595,31661,31727,31794,31859,
|
||||
31925,31991,32056,32122,32187,32252,32317,32382,32446,32511,32575,32640,32704,32768,
|
||||
32832,32896,32959,33023,33086,33150,33213,33276,33339,33402,33465,33527,33590,33652,
|
||||
33714,33776,33839,33900,33962,34024,34086,34147,34208,34270,34331,34392,34453,34514,
|
||||
34574,34635,34695,34756,34816,34876,34936,34996,35056,35116,35176,35235,35295,35354,
|
||||
35413,35472,35531,35590,35649,35708,35767,35825,35884,35942,36001,36059,36117,36175,
|
||||
36233,36291,36348,36406,36464,36521,36578,36636,36693,36750,36807,36864,36921,36978,
|
||||
37034,37091,37147,37204,37260,37316,37372,37429,37485,37540,37596,37652,37708,37763,
|
||||
37819,37874,37929,37985,38040,38095,38150,38205,38260,38315,38369,38424,38478,38533,
|
||||
38587,38642,38696,38750,38804,38858,38912,38966,39020,39073,39127,39181,39234,39287,
|
||||
39341,39394,39447,39500,39553,39606,39659,39712,39765,39818,39870,39923,39975,40028,
|
||||
40080,40132,40185,40237,40289,40341,40393,40445,40497,40548,40600,40652,40703,40755,
|
||||
40806,40857,40909,40960,41011,41062,41113,41164,41215,41266,41317,41368,41418,41469,
|
||||
41519,41570,41620,41671,41721,41771,41821,41871,41922,41972,42021,42071,42121,42171,
|
||||
42221,42270,42320,42369,42419,42468,42518,42567,42616,42665,42714,42763,42813,42861,
|
||||
42910,42959,43008,43057,43105,43154,43203,43251,43300,43348,43396,43445,43493,43541,
|
||||
43589,43637,43685,43733,43781,43829,43877,43925,43972,44020,44068,44115,44163,44210,
|
||||
44258,44305,44352,44400,44447,44494,44541,44588,44635,44682,44729,44776,44823,44869,
|
||||
44916,44963,45009,45056,45103,45149,45195,45242,45288,45334,45381,45427,45473,45519,
|
||||
45565,45611,45657,45703,45749,45795,45840,45886,45932,45977,46023,46069,46114,46160,
|
||||
46205,46250,46296,46341,46386,46431,46477,46522,46567,46612,46657,46702,46746,46791,
|
||||
46836,46881,46926,46970,47015,47059,47104,47149,47193,47237,47282,47326,47370,47415,
|
||||
47459,47503,47547,47591,47635,47679,47723,47767,47811,47855,47899,47942,47986,48030,
|
||||
48074,48117,48161,48204,48248,48291,48335,48378,48421,48465,48508,48551,48594,48637,
|
||||
48680,48723,48766,48809,48852,48895,48938,48981,49024,49067,49109,49152,49195,49237,
|
||||
49280,49322,49365,49407,49450,49492,49535,49577,49619,49661,49704,49746,49788,49830,
|
||||
49872,49914,49956,49998,50040,50082,50124,50166,50207,50249,50291,50332,50374,50416,
|
||||
50457,50499,50540,50582,50623,50665,50706,50747,50789,50830,50871,50912,50954,50995,
|
||||
51036,51077,51118,51159,51200,51241,51282,51323,51364,51404,51445,51486,51527,51567,
|
||||
51608,51649,51689,51730,51770,51811,51851,51892,51932,51972,52013,52053,52093,52134,
|
||||
52174,52214,52254,52294,52334,52374,52414,52454,52494,52534,52574,52614,52654,52694,
|
||||
52734,52773,52813,52853,52892,52932,52972,53011,53051,53090,53130,53169,53209,53248,
|
||||
53287,53327,53366,53405,53445,53484,53523,53562,53601,53640,53679,53719,53758,53797,
|
||||
53836,53874,53913,53952,53991,54030,54069,54108,54146,54185,54224,54262,54301,54340,
|
||||
54378,54417,54455,54494,54532,54571,54609,54647,54686,54724,54762,54801,54839,54877,
|
||||
54915,54954,54992,55030,55068,55106,55144,55182,55220,55258,55296,55334,55372,55410,
|
||||
55447,55485,55523,55561,55599,55636,55674,55712,55749,55787,55824,55862,55900,55937,
|
||||
55975,56012,56049,56087,56124,56162,56199,56236,56273,56311,56348,56385,56422,56459,
|
||||
56497,56534,56571,56608,56645,56682,56719,56756,56793,56830,56867,56903,56940,56977,
|
||||
57014,57051,57087,57124,57161,57198,57234,57271,57307,57344,57381,57417,57454,57490,
|
||||
57527,57563,57599,57636,57672,57709,57745,57781,57817,57854,57890,57926,57962,57999,
|
||||
58035,58071,58107,58143,58179,58215,58251,58287,58323,58359,58395,58431,58467,58503,
|
||||
58538,58574,58610,58646,58682,58717,58753,58789,58824,58860,58896,58931,58967,59002,
|
||||
59038,59073,59109,59144,59180,59215,59251,59286,59321,59357,59392,59427,59463,59498,
|
||||
59533,59568,59603,59639,59674,59709,59744,59779,59814,59849,59884,59919,59954,59989,
|
||||
60024,60059,60094,60129,60164,60199,60233,60268,60303,60338,60373,60407,60442,60477,
|
||||
60511,60546,60581,60615,60650,60684,60719,60753,60788,60822,60857,60891,60926,60960,
|
||||
60995,61029,61063,61098,61132,61166,61201,61235,61269,61303,61338,61372,61406,61440,
|
||||
61474,61508,61542,61576,61610,61644,61678,61712,61746,61780,61814,61848,61882,61916,
|
||||
61950,61984,62018,62051,62085,62119,62153,62186,62220,62254,62287,62321,62355,62388,
|
||||
62422,62456,62489,62523,62556,62590,62623,62657,62690,62724,62757,62790,62824,62857,
|
||||
62891,62924,62957,62991,63024,63057,63090,63124,63157,63190,63223,63256,63289,63323,
|
||||
63356,63389,63422,63455,63488,63521,63554,63587,63620,63653,63686,63719,63752,63785,
|
||||
63817,63850,63883,63916,63949,63982,64014,64047,64080,64113,64145,64178,64211,64243,
|
||||
64276,64309,64341,64374,64406,64439,64471,64504,64536,64569,64601,64634,64666,64699,
|
||||
64731,64763,64796,64828,64861,64893,64925,64957,64990,65022,65054,65086,65119,65151,
|
||||
65183,65215,65247,65279,65312,65344,65376,65408,65440,65472,65504
|
||||
};
|
||||
|
||||
|
||||
int8 g_elder_bit_table[256] = //---------g_elder_bit_table
|
||||
{
|
||||
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
||||
};
|
||||
|
||||
unsigned fastint_sqrt(unsigned val)
|
||||
{
|
||||
unsigned t = val;
|
||||
int bit=0;
|
||||
unsigned shift = 11;
|
||||
bit = t >> 24;
|
||||
if(bit)
|
||||
bit = g_elder_bit_table[bit] + 24;
|
||||
else {
|
||||
bit = (t >> 16) & 0xFF;
|
||||
if(bit)
|
||||
bit = g_elder_bit_table[bit] + 16;
|
||||
else {
|
||||
bit = (t >> 8) & 0xFF;
|
||||
if(bit)
|
||||
bit = g_elder_bit_table[bit] + 8;
|
||||
else
|
||||
bit = g_elder_bit_table[t];
|
||||
}
|
||||
}
|
||||
bit -= 9;
|
||||
if(bit > 0) {
|
||||
bit = (bit >> 1) + (bit & 1);
|
||||
shift -= bit;
|
||||
val >>= (bit << 1);
|
||||
}
|
||||
return g_sqrt_table[val] >> shift;
|
||||
}
|
||||
|
||||
struct UppRadialSpan {
|
||||
agg::span_interpolator_linear<> interpolator;
|
||||
int cx, cy, r, fx, fy;
|
||||
int style;
|
||||
int alpha;
|
||||
RGBA gradient[2048];
|
||||
bool focus;
|
||||
double C;
|
||||
|
||||
void SetAlpha(int a) { alpha = a + (a >> 7); }
|
||||
|
||||
void prepare() {}
|
||||
|
||||
void Set(int _x, int _y, int _r, int _fx, int _fy)
|
||||
{
|
||||
cx = _x;
|
||||
cy = _y;
|
||||
r = _r;
|
||||
fx = _fx;
|
||||
fy = _fy;
|
||||
focus = cx != fx || cy != fy;
|
||||
if(focus) {
|
||||
fx -= cx;
|
||||
fy -= cy;
|
||||
double fx2 = double(fx) * double(fx);
|
||||
double fy2 = double(fy) * double(fy);
|
||||
C = fx * fx + fy * fy - r * r;
|
||||
}
|
||||
else {
|
||||
cx <<= 6;
|
||||
cy <<= 6;
|
||||
r <<= 6;
|
||||
}
|
||||
}
|
||||
|
||||
void generate(RGBA *_span, int x, int y, unsigned len)
|
||||
{
|
||||
if(r <= 0)
|
||||
return;
|
||||
interpolator.begin(x + 0.5, y + 0.5, len);
|
||||
RGBA *span = (RGBA *)_span;
|
||||
while(len--) {
|
||||
interpolator.coordinates(&x, &y);
|
||||
int h;
|
||||
if(focus) {
|
||||
const double q256 = 1 / 256.0;
|
||||
double dx = q256 * x - cx - fx;
|
||||
double dy = q256 * y - cy - fy;
|
||||
if(dx == 0 && dy == 0)
|
||||
h = 0;
|
||||
else {
|
||||
double A = dx * dx + dy * dy;
|
||||
double b = (fx * dx + fy * dy);
|
||||
double t = (sqrt(b * b - A * C) - b) / (A);
|
||||
h = t >= 0.001 ? int(2047 / t) : 2047;
|
||||
}
|
||||
}
|
||||
else {
|
||||
x >>= 2;
|
||||
y >>= 2;
|
||||
int dc = Upp::fastint_sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
|
||||
h = 2047 * dc / r;
|
||||
}
|
||||
if(style == GRADIENT_REPEAT)
|
||||
h = h & 2047;
|
||||
else
|
||||
if(style == GRADIENT_REFLECT)
|
||||
h = (h & 2048) ? (2047 - h & 2047) : (h & 2047);
|
||||
else
|
||||
h = minmax(h, 0, 2047);
|
||||
RGBA v = gradient[h];
|
||||
if(alpha == 256)
|
||||
*span = v;
|
||||
else {
|
||||
span->r = byte((alpha * v.r) >> 8);
|
||||
span->g = byte((alpha * v.g) >> 8);
|
||||
span->b = byte((alpha * v.b) >> 8);
|
||||
span->a = byte((alpha * v.a) >> 8);
|
||||
}
|
||||
++span;
|
||||
++interpolator;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void BufferPainter::FillOp(double fx, double fy, const RGBA& color1,
|
||||
double x, double y, double r, const RGBA& color2, int style)
|
||||
{
|
||||
if(inpath)
|
||||
path.close_polygon();
|
||||
pixf.noaa = pathattr.noaa;
|
||||
span_alloc sa;
|
||||
Matrix2D m = pathattr.mtx;
|
||||
m.invert();
|
||||
UppRadialSpan sg;
|
||||
sg.interpolator.transformer(m);
|
||||
sg.SetAlpha(int(pathattr.opacity * 255));
|
||||
sg.style = style;
|
||||
sg.Set((int)x, (int)y, (int)r, (int)fx, (int)fy);
|
||||
MakeGradient(sg.gradient, color1, color2, 2048);
|
||||
|
||||
rasterizer.reset();
|
||||
rasterizer.filling_rule(pathattr.evenodd ? agg::fill_even_odd : agg::fill_non_zero);
|
||||
rasterizer.add_path(curved_trans);
|
||||
|
||||
if(clip.GetCount()) {
|
||||
agg::rendering_buffer mask_rbuf;
|
||||
mask_rbuf.attach(~clip.Top(), size.cx, size.cy, size.cx);
|
||||
agg::alpha_mask_gray8 mask(mask_rbuf);
|
||||
agg::scanline_u8_am<agg::alpha_mask_gray8> sl(mask);
|
||||
agg::render_scanlines_aa(rasterizer, sl, renb, sa, sg);
|
||||
}
|
||||
else
|
||||
agg::render_scanlines_aa(rasterizer, scanline_p, renb, sa, sg);
|
||||
rasterizer.reset();
|
||||
inpath = false;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
BufferPainter::StrokeInfo BufferPainter::BeginStroke(double width)
|
||||
{
|
||||
StrokeInfo f;
|
||||
double scl = pathattr.mtx.scale();
|
||||
curved.approximation_scale(scl);
|
||||
curved.angle_tolerance(0.0);
|
||||
if(width * scl > 1.0)
|
||||
curved.angle_tolerance(0.2);
|
||||
if(pathattr.dash.GetCount()) {
|
||||
agg::conv_dash<Curved> dashed(curved);
|
||||
dashed.Set(&pathattr.dash, pathattr.dash_start);
|
||||
agg::conv_stroke<agg::conv_dash<Curved> > curved_stroked(dashed);
|
||||
curved_stroked.width(width);
|
||||
curved_stroked.line_join((agg::line_join_e)pathattr.join);
|
||||
curved_stroked.line_cap((agg::line_cap_e)pathattr.cap);
|
||||
curved_stroked.miter_limit(pathattr.miter_limit);
|
||||
curved_stroked.approximation_scale(scl);
|
||||
f.path.concat_path(curved_stroked);
|
||||
}
|
||||
else {
|
||||
agg::conv_stroke<Curved> curved_stroked(curved);
|
||||
curved_stroked.width(width);
|
||||
curved_stroked.line_join((agg::line_join_e)pathattr.join);
|
||||
curved_stroked.line_cap((agg::line_cap_e)pathattr.cap);
|
||||
curved_stroked.miter_limit(pathattr.miter_limit);
|
||||
curved_stroked.approximation_scale(scl);
|
||||
f.path.concat_path(curved_stroked);
|
||||
}
|
||||
Swap(f.path, path);
|
||||
f.evenodd = pathattr.evenodd;
|
||||
pathattr.evenodd = false;
|
||||
inpath = false;
|
||||
return f;
|
||||
}
|
||||
|
||||
void BufferPainter::EndStroke(StrokeInfo& f)
|
||||
{
|
||||
Swap(f.path, path);
|
||||
pathattr.evenodd = f.evenodd;
|
||||
}
|
||||
|
||||
void BufferPainter::StrokeOp(double width, const RGBA& color)
|
||||
{
|
||||
StrokeInfo f = BeginStroke(width);
|
||||
Fill(color);
|
||||
EndStroke(f);
|
||||
}
|
||||
|
||||
void BufferPainter::StrokeOp(double width, const Image& image, const Matrix2D& transsrc, dword flags)
|
||||
{
|
||||
StrokeInfo f = BeginStroke(width);
|
||||
Fill(image, transsrc, flags);
|
||||
EndStroke(f);
|
||||
}
|
||||
|
||||
void BufferPainter::StrokeOp(double width, double x1, double y1, const RGBA& color1,
|
||||
double x2, double y2, const RGBA& color2, int style)
|
||||
{
|
||||
StrokeInfo f = BeginStroke(width);
|
||||
Fill(x1, y1, color1, x2, y2, color2, style);
|
||||
EndStroke(f);
|
||||
}
|
||||
|
||||
void BufferPainter::StrokeOp(double width, double fx, double fy, const RGBA& color1,
|
||||
double x, double y, double r, const RGBA& color2, int style)
|
||||
{
|
||||
StrokeInfo f = BeginStroke(width);
|
||||
Fill(fx, fy, color1, x, y, r, color2, style);
|
||||
EndStroke(f);
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
#include "Painter.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void Painter::TextOp(double x, double y, const wchar *text, Font fnt, int n, double *dx)
|
||||
{
|
||||
FontInfo fi = fnt.Info();
|
||||
if(n < 0)
|
||||
n = wstrlen(text);
|
||||
while(n) {
|
||||
int ch = *text++;
|
||||
Character(x, y, ch, fnt);
|
||||
if(dx)
|
||||
x += *dx++;
|
||||
else
|
||||
x += fi[ch];
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
Painter& Painter::Character(double x, double y, int ch, Font fnt)
|
||||
{
|
||||
CharacterOp(x, y, ch, fnt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Painter& Painter::Text(double x, double y, const wchar *text, Font fnt, int n, double *dx)
|
||||
{
|
||||
TextOp(x, y, text, fnt, n, dx);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Painter& Painter::Text(double x, double y, const WString& s, Font fnt, double *dx)
|
||||
{
|
||||
Text(x, y, s, fnt, s.GetLength(), dx);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Painter& Painter::Text(double x, double y, const String& s, Font fnt, double *dx)
|
||||
{
|
||||
Text(x, y, s.ToWString(), fnt, dx);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Painter& Painter::Text(double x, double y, const char *text, Font fnt, int n, double *dx)
|
||||
{
|
||||
Text(x, y, ToUnicode(text, n < 0 ? strlen(text) : n, CHARSET_DEFAULT), fnt, dx);
|
||||
return *this;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,499 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// scanline_u8 class
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_ALPHA_MASK_U8_INCLUDED
|
||||
#define AGG_ALPHA_MASK_U8_INCLUDED
|
||||
|
||||
#include <string.h>
|
||||
#include "agg_basics.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//===================================================one_component_mask_u8
|
||||
struct one_component_mask_u8
|
||||
{
|
||||
static unsigned calculate(const int8u* p) { return *p; }
|
||||
};
|
||||
|
||||
|
||||
//=====================================================rgb_to_gray_mask_u8
|
||||
template<unsigned R, unsigned G, unsigned B>
|
||||
struct rgb_to_gray_mask_u8
|
||||
{
|
||||
static unsigned calculate(const int8u* p)
|
||||
{
|
||||
return (p[R]*77 + p[G]*150 + p[B]*29) >> 8;
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================alpha_mask_u8
|
||||
template<unsigned Step=1, unsigned Offset=0, class MaskF=one_component_mask_u8>
|
||||
class alpha_mask_u8
|
||||
{
|
||||
public:
|
||||
typedef int8u cover_type;
|
||||
typedef alpha_mask_u8<Step, Offset, MaskF> self_type;
|
||||
enum cover_scale_e
|
||||
{
|
||||
cover_shift = 8,
|
||||
cover_none = 0,
|
||||
cover_full = 255
|
||||
};
|
||||
|
||||
alpha_mask_u8() : m_rbuf(0) {}
|
||||
explicit alpha_mask_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {}
|
||||
|
||||
void attach(rendering_buffer& rbuf) { m_rbuf = &rbuf; }
|
||||
|
||||
MaskF& mask_function() { return m_mask_function; }
|
||||
const MaskF& mask_function() const { return m_mask_function; }
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
cover_type pixel(int x, int y) const
|
||||
{
|
||||
if(x >= 0 && y >= 0 &&
|
||||
x < (int)m_rbuf->width() &&
|
||||
y < (int)m_rbuf->height())
|
||||
{
|
||||
return (cover_type)m_mask_function.calculate(
|
||||
m_rbuf->row_ptr(y) + x * Step + Offset);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
cover_type combine_pixel(int x, int y, cover_type val) const
|
||||
{
|
||||
if(x >= 0 && y >= 0 &&
|
||||
x < (int)m_rbuf->width() &&
|
||||
y < (int)m_rbuf->height())
|
||||
{
|
||||
return (cover_type)((cover_full + val *
|
||||
m_mask_function.calculate(
|
||||
m_rbuf->row_ptr(y) + x * Step + Offset)) >>
|
||||
cover_shift);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void fill_hspan(int x, int y, cover_type* dst, int num_pix) const
|
||||
{
|
||||
int xmax = m_rbuf->width() - 1;
|
||||
int ymax = m_rbuf->height() - 1;
|
||||
|
||||
int count = num_pix;
|
||||
cover_type* covers = dst;
|
||||
|
||||
if(y < 0 || y > ymax)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
|
||||
if(x < 0)
|
||||
{
|
||||
count += x;
|
||||
if(count <= 0)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
memset(covers, 0, -x * sizeof(cover_type));
|
||||
covers -= x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if(x + count > xmax)
|
||||
{
|
||||
int rest = x + count - xmax - 1;
|
||||
count -= rest;
|
||||
if(count <= 0)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
memset(covers + count, 0, rest * sizeof(cover_type));
|
||||
}
|
||||
|
||||
const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
do
|
||||
{
|
||||
*covers++ = (cover_type)m_mask_function.calculate(mask);
|
||||
mask += Step;
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void combine_hspan(int x, int y, cover_type* dst, int num_pix) const
|
||||
{
|
||||
int xmax = m_rbuf->width() - 1;
|
||||
int ymax = m_rbuf->height() - 1;
|
||||
|
||||
int count = num_pix;
|
||||
cover_type* covers = dst;
|
||||
|
||||
if(y < 0 || y > ymax)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
|
||||
if(x < 0)
|
||||
{
|
||||
count += x;
|
||||
if(count <= 0)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
memset(covers, 0, -x * sizeof(cover_type));
|
||||
covers -= x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if(x + count > xmax)
|
||||
{
|
||||
int rest = x + count - xmax - 1;
|
||||
count -= rest;
|
||||
if(count <= 0)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
memset(covers + count, 0, rest * sizeof(cover_type));
|
||||
}
|
||||
|
||||
const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
do
|
||||
{
|
||||
*covers = (cover_type)((cover_full + (*covers) *
|
||||
m_mask_function.calculate(mask)) >>
|
||||
cover_shift);
|
||||
++covers;
|
||||
mask += Step;
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void fill_vspan(int x, int y, cover_type* dst, int num_pix) const
|
||||
{
|
||||
int xmax = m_rbuf->width() - 1;
|
||||
int ymax = m_rbuf->height() - 1;
|
||||
|
||||
int count = num_pix;
|
||||
cover_type* covers = dst;
|
||||
|
||||
if(x < 0 || x > xmax)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
|
||||
if(y < 0)
|
||||
{
|
||||
count += y;
|
||||
if(count <= 0)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
memset(covers, 0, -y * sizeof(cover_type));
|
||||
covers -= y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if(y + count > ymax)
|
||||
{
|
||||
int rest = y + count - ymax - 1;
|
||||
count -= rest;
|
||||
if(count <= 0)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
memset(covers + count, 0, rest * sizeof(cover_type));
|
||||
}
|
||||
|
||||
const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
do
|
||||
{
|
||||
*covers++ = (cover_type)m_mask_function.calculate(mask);
|
||||
mask += m_rbuf->stride();
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void combine_vspan(int x, int y, cover_type* dst, int num_pix) const
|
||||
{
|
||||
int xmax = m_rbuf->width() - 1;
|
||||
int ymax = m_rbuf->height() - 1;
|
||||
|
||||
int count = num_pix;
|
||||
cover_type* covers = dst;
|
||||
|
||||
if(x < 0 || x > xmax)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
|
||||
if(y < 0)
|
||||
{
|
||||
count += y;
|
||||
if(count <= 0)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
memset(covers, 0, -y * sizeof(cover_type));
|
||||
covers -= y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if(y + count > ymax)
|
||||
{
|
||||
int rest = y + count - ymax - 1;
|
||||
count -= rest;
|
||||
if(count <= 0)
|
||||
{
|
||||
memset(dst, 0, num_pix * sizeof(cover_type));
|
||||
return;
|
||||
}
|
||||
memset(covers + count, 0, rest * sizeof(cover_type));
|
||||
}
|
||||
|
||||
const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
do
|
||||
{
|
||||
*covers = (cover_type)((cover_full + (*covers) *
|
||||
m_mask_function.calculate(mask)) >>
|
||||
cover_shift);
|
||||
++covers;
|
||||
mask += m_rbuf->stride();
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
alpha_mask_u8(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
rendering_buffer* m_rbuf;
|
||||
MaskF m_mask_function;
|
||||
};
|
||||
|
||||
|
||||
typedef alpha_mask_u8<1, 0> alpha_mask_gray8; //----alpha_mask_gray8
|
||||
|
||||
typedef alpha_mask_u8<3, 0> alpha_mask_rgb24r; //----alpha_mask_rgb24r
|
||||
typedef alpha_mask_u8<3, 1> alpha_mask_rgb24g; //----alpha_mask_rgb24g
|
||||
typedef alpha_mask_u8<3, 2> alpha_mask_rgb24b; //----alpha_mask_rgb24b
|
||||
|
||||
typedef alpha_mask_u8<3, 2> alpha_mask_bgr24r; //----alpha_mask_bgr24r
|
||||
typedef alpha_mask_u8<3, 1> alpha_mask_bgr24g; //----alpha_mask_bgr24g
|
||||
typedef alpha_mask_u8<3, 0> alpha_mask_bgr24b; //----alpha_mask_bgr24b
|
||||
|
||||
typedef alpha_mask_u8<4, 0> alpha_mask_rgba32r; //----alpha_mask_rgba32r
|
||||
typedef alpha_mask_u8<4, 1> alpha_mask_rgba32g; //----alpha_mask_rgba32g
|
||||
typedef alpha_mask_u8<4, 2> alpha_mask_rgba32b; //----alpha_mask_rgba32b
|
||||
typedef alpha_mask_u8<4, 3> alpha_mask_rgba32a; //----alpha_mask_rgba32a
|
||||
|
||||
typedef alpha_mask_u8<4, 1> alpha_mask_argb32r; //----alpha_mask_argb32r
|
||||
typedef alpha_mask_u8<4, 2> alpha_mask_argb32g; //----alpha_mask_argb32g
|
||||
typedef alpha_mask_u8<4, 3> alpha_mask_argb32b; //----alpha_mask_argb32b
|
||||
typedef alpha_mask_u8<4, 0> alpha_mask_argb32a; //----alpha_mask_argb32a
|
||||
|
||||
typedef alpha_mask_u8<4, 2> alpha_mask_bgra32r; //----alpha_mask_bgra32r
|
||||
typedef alpha_mask_u8<4, 1> alpha_mask_bgra32g; //----alpha_mask_bgra32g
|
||||
typedef alpha_mask_u8<4, 0> alpha_mask_bgra32b; //----alpha_mask_bgra32b
|
||||
typedef alpha_mask_u8<4, 3> alpha_mask_bgra32a; //----alpha_mask_bgra32a
|
||||
|
||||
typedef alpha_mask_u8<4, 3> alpha_mask_abgr32r; //----alpha_mask_abgr32r
|
||||
typedef alpha_mask_u8<4, 2> alpha_mask_abgr32g; //----alpha_mask_abgr32g
|
||||
typedef alpha_mask_u8<4, 1> alpha_mask_abgr32b; //----alpha_mask_abgr32b
|
||||
typedef alpha_mask_u8<4, 0> alpha_mask_abgr32a; //----alpha_mask_abgr32a
|
||||
|
||||
typedef alpha_mask_u8<3, 0, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_rgb24gray; //----alpha_mask_rgb24gray
|
||||
typedef alpha_mask_u8<3, 0, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_bgr24gray; //----alpha_mask_bgr24gray
|
||||
typedef alpha_mask_u8<4, 0, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_rgba32gray; //----alpha_mask_rgba32gray
|
||||
typedef alpha_mask_u8<4, 1, rgb_to_gray_mask_u8<0, 1, 2> > alpha_mask_argb32gray; //----alpha_mask_argb32gray
|
||||
typedef alpha_mask_u8<4, 0, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_bgra32gray; //----alpha_mask_bgra32gray
|
||||
typedef alpha_mask_u8<4, 1, rgb_to_gray_mask_u8<2, 1, 0> > alpha_mask_abgr32gray; //----alpha_mask_abgr32gray
|
||||
|
||||
|
||||
|
||||
//==========================================================amask_no_clip_u8
|
||||
template<unsigned Step=1, unsigned Offset=0, class MaskF=one_component_mask_u8>
|
||||
class amask_no_clip_u8
|
||||
{
|
||||
public:
|
||||
typedef int8u cover_type;
|
||||
typedef amask_no_clip_u8<Step, Offset, MaskF> self_type;
|
||||
enum cover_scale_e
|
||||
{
|
||||
cover_shift = 8,
|
||||
cover_none = 0,
|
||||
cover_full = 255
|
||||
};
|
||||
|
||||
amask_no_clip_u8() : m_rbuf(0) {}
|
||||
explicit amask_no_clip_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {}
|
||||
|
||||
void attach(rendering_buffer& rbuf) { m_rbuf = &rbuf; }
|
||||
|
||||
MaskF& mask_function() { return m_mask_function; }
|
||||
const MaskF& mask_function() const { return m_mask_function; }
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
cover_type pixel(int x, int y) const
|
||||
{
|
||||
return (cover_type)m_mask_function.calculate(
|
||||
m_rbuf->row_ptr(y) + x * Step + Offset);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
cover_type combine_pixel(int x, int y, cover_type val) const
|
||||
{
|
||||
return (cover_type)((cover_full + val *
|
||||
m_mask_function.calculate(
|
||||
m_rbuf->row_ptr(y) + x * Step + Offset)) >>
|
||||
cover_shift);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void fill_hspan(int x, int y, cover_type* dst, int num_pix) const
|
||||
{
|
||||
const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
do
|
||||
{
|
||||
*dst++ = (cover_type)m_mask_function.calculate(mask);
|
||||
mask += Step;
|
||||
}
|
||||
while(--num_pix);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void combine_hspan(int x, int y, cover_type* dst, int num_pix) const
|
||||
{
|
||||
const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
do
|
||||
{
|
||||
*dst = (cover_type)((cover_full + (*dst) *
|
||||
m_mask_function.calculate(mask)) >>
|
||||
cover_shift);
|
||||
++dst;
|
||||
mask += Step;
|
||||
}
|
||||
while(--num_pix);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void fill_vspan(int x, int y, cover_type* dst, int num_pix) const
|
||||
{
|
||||
const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
do
|
||||
{
|
||||
*dst++ = (cover_type)m_mask_function.calculate(mask);
|
||||
mask += m_rbuf->stride();
|
||||
}
|
||||
while(--num_pix);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void combine_vspan(int x, int y, cover_type* dst, int num_pix) const
|
||||
{
|
||||
const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
|
||||
do
|
||||
{
|
||||
*dst = (cover_type)((cover_full + (*dst) *
|
||||
m_mask_function.calculate(mask)) >>
|
||||
cover_shift);
|
||||
++dst;
|
||||
mask += m_rbuf->stride();
|
||||
}
|
||||
while(--num_pix);
|
||||
}
|
||||
|
||||
private:
|
||||
amask_no_clip_u8(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
rendering_buffer* m_rbuf;
|
||||
MaskF m_mask_function;
|
||||
};
|
||||
|
||||
|
||||
typedef amask_no_clip_u8<1, 0> amask_no_clip_gray8; //----amask_no_clip_gray8
|
||||
|
||||
typedef amask_no_clip_u8<3, 0> amask_no_clip_rgb24r; //----amask_no_clip_rgb24r
|
||||
typedef amask_no_clip_u8<3, 1> amask_no_clip_rgb24g; //----amask_no_clip_rgb24g
|
||||
typedef amask_no_clip_u8<3, 2> amask_no_clip_rgb24b; //----amask_no_clip_rgb24b
|
||||
|
||||
typedef amask_no_clip_u8<3, 2> amask_no_clip_bgr24r; //----amask_no_clip_bgr24r
|
||||
typedef amask_no_clip_u8<3, 1> amask_no_clip_bgr24g; //----amask_no_clip_bgr24g
|
||||
typedef amask_no_clip_u8<3, 0> amask_no_clip_bgr24b; //----amask_no_clip_bgr24b
|
||||
|
||||
typedef amask_no_clip_u8<4, 0> amask_no_clip_rgba32r; //----amask_no_clip_rgba32r
|
||||
typedef amask_no_clip_u8<4, 1> amask_no_clip_rgba32g; //----amask_no_clip_rgba32g
|
||||
typedef amask_no_clip_u8<4, 2> amask_no_clip_rgba32b; //----amask_no_clip_rgba32b
|
||||
typedef amask_no_clip_u8<4, 3> amask_no_clip_rgba32a; //----amask_no_clip_rgba32a
|
||||
|
||||
typedef amask_no_clip_u8<4, 1> amask_no_clip_argb32r; //----amask_no_clip_argb32r
|
||||
typedef amask_no_clip_u8<4, 2> amask_no_clip_argb32g; //----amask_no_clip_argb32g
|
||||
typedef amask_no_clip_u8<4, 3> amask_no_clip_argb32b; //----amask_no_clip_argb32b
|
||||
typedef amask_no_clip_u8<4, 0> amask_no_clip_argb32a; //----amask_no_clip_argb32a
|
||||
|
||||
typedef amask_no_clip_u8<4, 2> amask_no_clip_bgra32r; //----amask_no_clip_bgra32r
|
||||
typedef amask_no_clip_u8<4, 1> amask_no_clip_bgra32g; //----amask_no_clip_bgra32g
|
||||
typedef amask_no_clip_u8<4, 0> amask_no_clip_bgra32b; //----amask_no_clip_bgra32b
|
||||
typedef amask_no_clip_u8<4, 3> amask_no_clip_bgra32a; //----amask_no_clip_bgra32a
|
||||
|
||||
typedef amask_no_clip_u8<4, 3> amask_no_clip_abgr32r; //----amask_no_clip_abgr32r
|
||||
typedef amask_no_clip_u8<4, 2> amask_no_clip_abgr32g; //----amask_no_clip_abgr32g
|
||||
typedef amask_no_clip_u8<4, 1> amask_no_clip_abgr32b; //----amask_no_clip_abgr32b
|
||||
typedef amask_no_clip_u8<4, 0> amask_no_clip_abgr32a; //----amask_no_clip_abgr32a
|
||||
|
||||
typedef amask_no_clip_u8<3, 0, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_rgb24gray; //----amask_no_clip_rgb24gray
|
||||
typedef amask_no_clip_u8<3, 0, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_bgr24gray; //----amask_no_clip_bgr24gray
|
||||
typedef amask_no_clip_u8<4, 0, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_rgba32gray; //----amask_no_clip_rgba32gray
|
||||
typedef amask_no_clip_u8<4, 1, rgb_to_gray_mask_u8<0, 1, 2> > amask_no_clip_argb32gray; //----amask_no_clip_argb32gray
|
||||
typedef amask_no_clip_u8<4, 0, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_bgra32gray; //----amask_no_clip_bgra32gray
|
||||
typedef amask_no_clip_u8<4, 1, rgb_to_gray_mask_u8<2, 1, 0> > amask_no_clip_abgr32gray; //----amask_no_clip_abgr32gray
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,530 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_BASICS_INCLUDED
|
||||
#define AGG_BASICS_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_config.h"
|
||||
|
||||
//---------------------------------------------------------AGG_CUSTOM_ALLOCATOR
|
||||
#ifdef AGG_CUSTOM_ALLOCATOR
|
||||
#include "agg_allocator.h"
|
||||
#else
|
||||
namespace agg
|
||||
{
|
||||
// The policy of all AGG containers and memory allocation strategy
|
||||
// in general is that no allocated data requires explicit construction.
|
||||
// It means that the allocator can be really simple; you can even
|
||||
// replace new/delete to malloc/free. The constructors and destructors
|
||||
// won't be called in this case, however everything will remain working.
|
||||
// The second argument of deallocate() is the size of the allocated
|
||||
// block. You can use this information if you wish.
|
||||
//------------------------------------------------------------pod_allocator
|
||||
template<class T> struct pod_allocator
|
||||
{
|
||||
static T* allocate(unsigned num) { return new T [num]; }
|
||||
static void deallocate(T* ptr, unsigned) { delete [] ptr; }
|
||||
};
|
||||
|
||||
// Single object allocator. It's also can be replaced with your custom
|
||||
// allocator. The difference is that it can only allocate a single
|
||||
// object and the constructor and destructor must be called.
|
||||
// In AGG there is no need to allocate an array of objects with
|
||||
// calling their constructors (only single ones). So that, if you
|
||||
// replace these new/delete to malloc/free make sure that the in-place
|
||||
// new is called and take care of calling the destructor too.
|
||||
//------------------------------------------------------------obj_allocator
|
||||
template<class T> struct obj_allocator
|
||||
{
|
||||
static T* allocate() { return new T; }
|
||||
static void deallocate(T* ptr) { delete ptr; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-------------------------------------------------------- Default basic types
|
||||
//
|
||||
// If the compiler has different capacity of the basic types you can redefine
|
||||
// them via the compiler command line or by generating agg_config.h that is
|
||||
// empty by default.
|
||||
//
|
||||
#ifndef AGG_INT8
|
||||
#define AGG_INT8 signed char
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT8U
|
||||
#define AGG_INT8U unsigned char
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT16
|
||||
#define AGG_INT16 short
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT16U
|
||||
#define AGG_INT16U unsigned short
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT32
|
||||
#define AGG_INT32 int
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT32U
|
||||
#define AGG_INT32U unsigned
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT64
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#define AGG_INT64 signed __int64
|
||||
#else
|
||||
#define AGG_INT64 signed long long
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT64U
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#define AGG_INT64U unsigned __int64
|
||||
#else
|
||||
#define AGG_INT64U unsigned long long
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//------------------------------------------------ Some fixes for MS Visual C++
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable:4786) // Identifier was truncated...
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define AGG_INLINE __forceinline
|
||||
#else
|
||||
#define AGG_INLINE inline
|
||||
#endif
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
typedef AGG_INT8 int8; //----int8
|
||||
typedef AGG_INT8U int8u; //----int8u
|
||||
typedef AGG_INT16 int16; //----int16
|
||||
typedef AGG_INT16U int16u; //----int16u
|
||||
typedef AGG_INT32 int32; //----int32
|
||||
typedef AGG_INT32U int32u; //----int32u
|
||||
typedef AGG_INT64 int64; //----int64
|
||||
typedef AGG_INT64U int64u; //----int64u
|
||||
|
||||
#if defined(AGG_FISTP)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4035) //Disable warning "no return value"
|
||||
AGG_INLINE int iround(double v) //-------iround
|
||||
{
|
||||
int t;
|
||||
__asm fld qword ptr [v]
|
||||
__asm fistp dword ptr [t]
|
||||
__asm mov eax, dword ptr [t]
|
||||
}
|
||||
AGG_INLINE unsigned uround(double v) //-------uround
|
||||
{
|
||||
unsigned t;
|
||||
__asm fld qword ptr [v]
|
||||
__asm fistp dword ptr [t]
|
||||
__asm mov eax, dword ptr [t]
|
||||
}
|
||||
#pragma warning(pop)
|
||||
AGG_INLINE unsigned ufloor(double v) //-------ufloor
|
||||
{
|
||||
return unsigned(floor(v));
|
||||
}
|
||||
AGG_INLINE unsigned uceil(double v) //--------uceil
|
||||
{
|
||||
return unsigned(ceil(v));
|
||||
}
|
||||
#elif defined(AGG_QIFIST)
|
||||
AGG_INLINE int iround(double v)
|
||||
{
|
||||
return int(v);
|
||||
}
|
||||
AGG_INLINE int uround(double v)
|
||||
{
|
||||
return unsigned(v);
|
||||
}
|
||||
AGG_INLINE unsigned ufloor(double v)
|
||||
{
|
||||
return unsigned(floor(v));
|
||||
}
|
||||
AGG_INLINE unsigned uceil(double v)
|
||||
{
|
||||
return unsigned(ceil(v));
|
||||
}
|
||||
#else
|
||||
AGG_INLINE int iround(double v)
|
||||
{
|
||||
return int((v < 0.0) ? v - 0.5 : v + 0.5);
|
||||
}
|
||||
AGG_INLINE int uround(double v)
|
||||
{
|
||||
return unsigned(v + 0.5);
|
||||
}
|
||||
AGG_INLINE unsigned ufloor(double v)
|
||||
{
|
||||
return unsigned(v);
|
||||
}
|
||||
AGG_INLINE unsigned uceil(double v)
|
||||
{
|
||||
return unsigned(ceil(v));
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------saturation
|
||||
template<int Limit> struct saturation
|
||||
{
|
||||
AGG_INLINE static int iround(double v)
|
||||
{
|
||||
if(v < double(-Limit)) return -Limit;
|
||||
if(v > double( Limit)) return Limit;
|
||||
return agg::iround(v);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------mul_one
|
||||
template<unsigned Shift> struct mul_one
|
||||
{
|
||||
AGG_INLINE static unsigned mul(unsigned a, unsigned b)
|
||||
{
|
||||
register unsigned q = a * b + (1 << (Shift-1));
|
||||
return (q + (q >> Shift)) >> Shift;
|
||||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
typedef unsigned char cover_type; //----cover_type
|
||||
enum cover_scale_e
|
||||
{
|
||||
cover_shift = 8, //----cover_shift
|
||||
cover_size = 1 << cover_shift, //----cover_size
|
||||
cover_mask = cover_size - 1, //----cover_mask
|
||||
cover_none = 0, //----cover_none
|
||||
cover_full = cover_mask //----cover_full
|
||||
};
|
||||
|
||||
//----------------------------------------------------poly_subpixel_scale_e
|
||||
// These constants determine the subpixel accuracy, to be more precise,
|
||||
// the number of bits of the fractional part of the coordinates.
|
||||
// The possible coordinate capacity in bits can be calculated by formula:
|
||||
// sizeof(int) * 8 - poly_subpixel_shift, i.e, for 32-bit integers and
|
||||
// 8-bits fractional part the capacity is 24 bits.
|
||||
enum poly_subpixel_scale_e
|
||||
{
|
||||
poly_subpixel_shift = 8, //----poly_subpixel_shift
|
||||
poly_subpixel_scale = 1<<poly_subpixel_shift, //----poly_subpixel_scale
|
||||
poly_subpixel_mask = poly_subpixel_scale-1, //----poly_subpixel_mask
|
||||
};
|
||||
|
||||
//----------------------------------------------------------filling_rule_e
|
||||
enum filling_rule_e
|
||||
{
|
||||
fill_non_zero,
|
||||
fill_even_odd
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------pi
|
||||
const double pi = 3.14159265358979323846;
|
||||
|
||||
//------------------------------------------------------------------deg2rad
|
||||
inline double deg2rad(double deg)
|
||||
{
|
||||
return deg * pi / 180.0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------rad2deg
|
||||
inline double rad2deg(double rad)
|
||||
{
|
||||
return rad * 180.0 / pi;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------rect_base
|
||||
template<class T> struct rect_base
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef rect_base<T> self_type;
|
||||
T x1, y1, x2, y2;
|
||||
|
||||
rect_base() {}
|
||||
rect_base(T x1_, T y1_, T x2_, T y2_) :
|
||||
x1(x1_), y1(y1_), x2(x2_), y2(y2_) {}
|
||||
|
||||
void init(T x1_, T y1_, T x2_, T y2_)
|
||||
{
|
||||
x1 = x1_; y1 = y1_; x2 = x2_; y2 = y2_;
|
||||
}
|
||||
|
||||
const self_type& normalize()
|
||||
{
|
||||
T t;
|
||||
if(x1 > x2) { t = x1; x1 = x2; x2 = t; }
|
||||
if(y1 > y2) { t = y1; y1 = y2; y2 = t; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool clip(const self_type& r)
|
||||
{
|
||||
if(x2 > r.x2) x2 = r.x2;
|
||||
if(y2 > r.y2) y2 = r.y2;
|
||||
if(x1 < r.x1) x1 = r.x1;
|
||||
if(y1 < r.y1) y1 = r.y1;
|
||||
return x1 <= x2 && y1 <= y2;
|
||||
}
|
||||
|
||||
bool is_valid() const
|
||||
{
|
||||
return x1 <= x2 && y1 <= y2;
|
||||
}
|
||||
|
||||
bool hit_test(T x, T y) const
|
||||
{
|
||||
return (x >= x1 && x <= x2 && y >= y1 && y <= y2);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------intersect_rectangles
|
||||
template<class Rect>
|
||||
inline Rect intersect_rectangles(const Rect& r1, const Rect& r2)
|
||||
{
|
||||
Rect r = r1;
|
||||
|
||||
// First process x2,y2 because the other order
|
||||
// results in Internal Compiler Error under
|
||||
// Microsoft Visual C++ .NET 2003 69462-335-0000007-18038 in
|
||||
// case of "Maximize Speed" optimization option.
|
||||
//-----------------
|
||||
if(r.x2 > r2.x2) r.x2 = r2.x2;
|
||||
if(r.y2 > r2.y2) r.y2 = r2.y2;
|
||||
if(r.x1 < r2.x1) r.x1 = r2.x1;
|
||||
if(r.y1 < r2.y1) r.y1 = r2.y1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------unite_rectangles
|
||||
template<class Rect>
|
||||
inline Rect unite_rectangles(const Rect& r1, const Rect& r2)
|
||||
{
|
||||
Rect r = r1;
|
||||
if(r.x2 < r2.x2) r.x2 = r2.x2;
|
||||
if(r.y2 < r2.y2) r.y2 = r2.y2;
|
||||
if(r.x1 > r2.x1) r.x1 = r2.x1;
|
||||
if(r.y1 > r2.y1) r.y1 = r2.y1;
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef rect_base<int> rect_i; //----rect_i
|
||||
typedef rect_base<float> rect_f; //----rect_f
|
||||
typedef rect_base<double> rect_d; //----rect_d
|
||||
|
||||
//---------------------------------------------------------path_commands_e
|
||||
enum path_commands_e
|
||||
{
|
||||
path_cmd_stop = 0, //----path_cmd_stop
|
||||
path_cmd_move_to = 1, //----path_cmd_move_to
|
||||
path_cmd_line_to = 2, //----path_cmd_line_to
|
||||
path_cmd_curve3 = 3, //----path_cmd_curve3
|
||||
path_cmd_curve4 = 4, //----path_cmd_curve4
|
||||
path_cmd_curveN = 5, //----path_cmd_curveN
|
||||
path_cmd_catrom = 6, //----path_cmd_catrom
|
||||
path_cmd_ubspline = 7, //----path_cmd_ubspline
|
||||
path_cmd_end_poly = 0x0F, //----path_cmd_end_poly
|
||||
path_cmd_mask = 0x0F //----path_cmd_mask
|
||||
};
|
||||
|
||||
//------------------------------------------------------------path_flags_e
|
||||
enum path_flags_e
|
||||
{
|
||||
path_flags_none = 0, //----path_flags_none
|
||||
path_flags_ccw = 0x10, //----path_flags_ccw
|
||||
path_flags_cw = 0x20, //----path_flags_cw
|
||||
path_flags_close = 0x40, //----path_flags_close
|
||||
path_flags_mask = 0xF0 //----path_flags_mask
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------is_vertex
|
||||
inline bool is_vertex(unsigned c)
|
||||
{
|
||||
return c >= path_cmd_move_to && c < path_cmd_end_poly;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------is_drawing
|
||||
inline bool is_drawing(unsigned c)
|
||||
{
|
||||
return c >= path_cmd_line_to && c < path_cmd_end_poly;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------is_stop
|
||||
inline bool is_stop(unsigned c)
|
||||
{
|
||||
return c == path_cmd_stop;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------is_move_to
|
||||
inline bool is_move_to(unsigned c)
|
||||
{
|
||||
return c == path_cmd_move_to;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------is_line_to
|
||||
inline bool is_line_to(unsigned c)
|
||||
{
|
||||
return c == path_cmd_line_to;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------is_curve
|
||||
inline bool is_curve(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve3 || c == path_cmd_curve4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_curve3
|
||||
inline bool is_curve3(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve3;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_curve4
|
||||
inline bool is_curve4(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve4;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------is_end_poly
|
||||
inline bool is_end_poly(unsigned c)
|
||||
{
|
||||
return (c & path_cmd_mask) == path_cmd_end_poly;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------is_close
|
||||
inline bool is_close(unsigned c)
|
||||
{
|
||||
return (c & ~(path_flags_cw | path_flags_ccw)) ==
|
||||
(path_cmd_end_poly | path_flags_close);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------is_next_poly
|
||||
inline bool is_next_poly(unsigned c)
|
||||
{
|
||||
return is_stop(c) || is_move_to(c) || is_end_poly(c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------is_cw
|
||||
inline bool is_cw(unsigned c)
|
||||
{
|
||||
return (c & path_flags_cw) != 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------is_ccw
|
||||
inline bool is_ccw(unsigned c)
|
||||
{
|
||||
return (c & path_flags_ccw) != 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------is_oriented
|
||||
inline bool is_oriented(unsigned c)
|
||||
{
|
||||
return (c & (path_flags_cw | path_flags_ccw)) != 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_closed
|
||||
inline bool is_closed(unsigned c)
|
||||
{
|
||||
return (c & path_flags_close) != 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------get_close_flag
|
||||
inline unsigned get_close_flag(unsigned c)
|
||||
{
|
||||
return c & path_flags_close;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------clear_orientation
|
||||
inline unsigned clear_orientation(unsigned c)
|
||||
{
|
||||
return c & ~(path_flags_cw | path_flags_ccw);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------get_orientation
|
||||
inline unsigned get_orientation(unsigned c)
|
||||
{
|
||||
return c & (path_flags_cw | path_flags_ccw);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------set_orientation
|
||||
inline unsigned set_orientation(unsigned c, unsigned o)
|
||||
{
|
||||
return clear_orientation(c) | o;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------point_base
|
||||
template<class T> struct point_base
|
||||
{
|
||||
typedef T value_type;
|
||||
T x,y;
|
||||
point_base() {}
|
||||
point_base(T x_, T y_) : x(x_), y(y_) {}
|
||||
};
|
||||
typedef point_base<int> point_i; //-----point_i
|
||||
typedef point_base<float> point_f; //-----point_f
|
||||
typedef point_base<double> point_d; //-----point_d
|
||||
|
||||
//-------------------------------------------------------------vertex_base
|
||||
template<class T> struct vertex_base
|
||||
{
|
||||
typedef T value_type;
|
||||
T x,y;
|
||||
unsigned cmd;
|
||||
vertex_base() {}
|
||||
vertex_base(T x_, T y_, unsigned cmd_) : x(x_), y(y_), cmd(cmd_) {}
|
||||
};
|
||||
typedef vertex_base<int> vertex_i; //-----vertex_i
|
||||
typedef vertex_base<float> vertex_f; //-----vertex_f
|
||||
typedef vertex_base<double> vertex_d; //-----vertex_d
|
||||
|
||||
//----------------------------------------------------------------row_info
|
||||
template<class T> struct row_info
|
||||
{
|
||||
int x1, x2;
|
||||
T* ptr;
|
||||
row_info() {}
|
||||
row_info(int x1_, int x2_, T* ptr_) : x1(x1_), x2(x2_), ptr(ptr_) {}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------const_row_info
|
||||
template<class T> struct const_row_info
|
||||
{
|
||||
int x1, x2;
|
||||
const T* ptr;
|
||||
const_row_info() {}
|
||||
const_row_info(int x1_, int x2_, const T* ptr_) :
|
||||
x1(x1_), x2(x2_), ptr(ptr_) {}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------is_equal_eps
|
||||
template<class T> inline bool is_equal_eps(T v1, T v2, T epsilon)
|
||||
{
|
||||
return fabs(v1 - v2) <= double(epsilon);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,333 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Liang-Barsky clipping
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CLIP_LIANG_BARSKY_INCLUDED
|
||||
#define AGG_CLIP_LIANG_BARSKY_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum clipping_flags_e
|
||||
{
|
||||
clipping_flags_x1_clipped = 4,
|
||||
clipping_flags_x2_clipped = 1,
|
||||
clipping_flags_y1_clipped = 8,
|
||||
clipping_flags_y2_clipped = 2,
|
||||
clipping_flags_x_clipped = clipping_flags_x1_clipped | clipping_flags_x2_clipped,
|
||||
clipping_flags_y_clipped = clipping_flags_y1_clipped | clipping_flags_y2_clipped
|
||||
};
|
||||
|
||||
//----------------------------------------------------------clipping_flags
|
||||
// Determine the clipping code of the vertex according to the
|
||||
// Cyrus-Beck line clipping algorithm
|
||||
//
|
||||
// | |
|
||||
// 0110 | 0010 | 0011
|
||||
// | |
|
||||
// -------+--------+-------- clip_box.y2
|
||||
// | |
|
||||
// 0100 | 0000 | 0001
|
||||
// | |
|
||||
// -------+--------+-------- clip_box.y1
|
||||
// | |
|
||||
// 1100 | 1000 | 1001
|
||||
// | |
|
||||
// clip_box.x1 clip_box.x2
|
||||
//
|
||||
//
|
||||
template<class T>
|
||||
inline unsigned clipping_flags(T x, T y, const rect_base<T>& clip_box)
|
||||
{
|
||||
return (x > clip_box.x2) |
|
||||
((y > clip_box.y2) << 1) |
|
||||
((x < clip_box.x1) << 2) |
|
||||
((y < clip_box.y1) << 3);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------clipping_flags_x
|
||||
template<class T>
|
||||
inline unsigned clipping_flags_x(T x, const rect_base<T>& clip_box)
|
||||
{
|
||||
return (x > clip_box.x2) | ((x < clip_box.x1) << 2);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------clipping_flags_y
|
||||
template<class T>
|
||||
inline unsigned clipping_flags_y(T y, const rect_base<T>& clip_box)
|
||||
{
|
||||
return ((y > clip_box.y2) << 1) | ((y < clip_box.y1) << 3);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------clip_liang_barsky
|
||||
template<class T>
|
||||
inline unsigned clip_liang_barsky(T x1, T y1, T x2, T y2,
|
||||
const rect_base<T>& clip_box,
|
||||
T* x, T* y)
|
||||
{
|
||||
const double nearzero = 1e-30;
|
||||
|
||||
double deltax = x2 - x1;
|
||||
double deltay = y2 - y1;
|
||||
double xin;
|
||||
double xout;
|
||||
double yin;
|
||||
double yout;
|
||||
double tinx;
|
||||
double tiny;
|
||||
double toutx;
|
||||
double touty;
|
||||
double tin1;
|
||||
double tin2;
|
||||
double tout1;
|
||||
unsigned np = 0;
|
||||
|
||||
if(deltax == 0.0)
|
||||
{
|
||||
// bump off of the vertical
|
||||
deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
|
||||
}
|
||||
|
||||
if(deltay == 0.0)
|
||||
{
|
||||
// bump off of the horizontal
|
||||
deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
|
||||
}
|
||||
|
||||
if(deltax > 0.0)
|
||||
{
|
||||
// points to right
|
||||
xin = clip_box.x1;
|
||||
xout = clip_box.x2;
|
||||
}
|
||||
else
|
||||
{
|
||||
xin = clip_box.x2;
|
||||
xout = clip_box.x1;
|
||||
}
|
||||
|
||||
if(deltay > 0.0)
|
||||
{
|
||||
// points up
|
||||
yin = clip_box.y1;
|
||||
yout = clip_box.y2;
|
||||
}
|
||||
else
|
||||
{
|
||||
yin = clip_box.y2;
|
||||
yout = clip_box.y1;
|
||||
}
|
||||
|
||||
tinx = (xin - x1) / deltax;
|
||||
tiny = (yin - y1) / deltay;
|
||||
|
||||
if (tinx < tiny)
|
||||
{
|
||||
// hits x first
|
||||
tin1 = tinx;
|
||||
tin2 = tiny;
|
||||
}
|
||||
else
|
||||
{
|
||||
// hits y first
|
||||
tin1 = tiny;
|
||||
tin2 = tinx;
|
||||
}
|
||||
|
||||
if(tin1 <= 1.0)
|
||||
{
|
||||
if(0.0 < tin1)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)yin;
|
||||
++np;
|
||||
}
|
||||
|
||||
if(tin2 <= 1.0)
|
||||
{
|
||||
toutx = (xout - x1) / deltax;
|
||||
touty = (yout - y1) / deltay;
|
||||
|
||||
tout1 = (toutx < touty) ? toutx : touty;
|
||||
|
||||
if(tin2 > 0.0 || tout1 > 0.0)
|
||||
{
|
||||
if(tin2 <= tout1)
|
||||
{
|
||||
if(tin2 > 0.0)
|
||||
{
|
||||
if(tinx > tiny)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)(y1 + tinx * deltay);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)(x1 + tiny * deltax);
|
||||
*y++ = (T)yin;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
|
||||
if(tout1 < 1.0)
|
||||
{
|
||||
if(toutx < touty)
|
||||
{
|
||||
*x++ = (T)xout;
|
||||
*y++ = (T)(y1 + toutx * deltay);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)(x1 + touty * deltax);
|
||||
*y++ = (T)yout;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = x2;
|
||||
*y++ = y2;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tinx > tiny)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)yout;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)xout;
|
||||
*y++ = (T)yin;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return np;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template<class T>
|
||||
bool clip_move_point(T x1, T y1, T x2, T y2,
|
||||
const rect_base<T>& clip_box,
|
||||
T* x, T* y, unsigned flags)
|
||||
{
|
||||
T bound;
|
||||
|
||||
if(flags & clipping_flags_x_clipped)
|
||||
{
|
||||
if(x1 == x2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bound = (flags & clipping_flags_x1_clipped) ? clip_box.x1 : clip_box.x2;
|
||||
*y = (T)(double(bound - x1) * (y2 - y1) / (x2 - x1) + y1);
|
||||
*x = bound;
|
||||
}
|
||||
|
||||
flags = clipping_flags_y(*y, clip_box);
|
||||
if(flags & clipping_flags_y_clipped)
|
||||
{
|
||||
if(y1 == y2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bound = (flags & clipping_flags_y1_clipped) ? clip_box.y1 : clip_box.y2;
|
||||
*x = (T)(double(bound - y1) * (x2 - x1) / (y2 - y1) + x1);
|
||||
*y = bound;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------clip_line_segment
|
||||
// Returns: ret >= 4 - Fully clipped
|
||||
// (ret & 1) != 0 - First point has been moved
|
||||
// (ret & 2) != 0 - Second point has been moved
|
||||
//
|
||||
template<class T>
|
||||
unsigned clip_line_segment(T* x1, T* y1, T* x2, T* y2,
|
||||
const rect_base<T>& clip_box)
|
||||
{
|
||||
unsigned f1 = clipping_flags(*x1, *y1, clip_box);
|
||||
unsigned f2 = clipping_flags(*x2, *y2, clip_box);
|
||||
unsigned ret = 0;
|
||||
|
||||
if((f2 | f1) == 0)
|
||||
{
|
||||
// Fully visible
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((f1 & clipping_flags_x_clipped) != 0 &&
|
||||
(f1 & clipping_flags_x_clipped) == (f2 & clipping_flags_x_clipped))
|
||||
{
|
||||
// Fully clipped
|
||||
return 4;
|
||||
}
|
||||
|
||||
if((f1 & clipping_flags_y_clipped) != 0 &&
|
||||
(f1 & clipping_flags_y_clipped) == (f2 & clipping_flags_y_clipped))
|
||||
{
|
||||
// Fully clipped
|
||||
return 4;
|
||||
}
|
||||
|
||||
T tx1 = *x1;
|
||||
T ty1 = *y1;
|
||||
T tx2 = *x2;
|
||||
T ty2 = *y2;
|
||||
if(f1)
|
||||
{
|
||||
if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x1, y1, f1))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
if(*x1 == *x2 && *y1 == *y2)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
ret |= 1;
|
||||
}
|
||||
if(f2)
|
||||
{
|
||||
if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x2, y2, f2))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
if(*x1 == *x2 && *y1 == *y2)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
ret |= 2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#ifndef AGG_CONFIG_INCLUDED
|
||||
#define AGG_CONFIG_INCLUDED
|
||||
|
||||
// This file can be used to redefine certain data types.
|
||||
|
||||
//---------------------------------------
|
||||
// 1. Default basic types such as:
|
||||
//
|
||||
// AGG_INT8
|
||||
// AGG_INT8U
|
||||
// AGG_INT16
|
||||
// AGG_INT16U
|
||||
// AGG_INT32
|
||||
// AGG_INT32U
|
||||
// AGG_INT64
|
||||
// AGG_INT64U
|
||||
//
|
||||
// Just replace this file with new defines if necessary.
|
||||
// For example, if your compiler doesn't have a 64 bit integer type
|
||||
// you can still use AGG if you define the follows:
|
||||
//
|
||||
// #define AGG_INT64 int
|
||||
// #define AGG_INT64U unsigned
|
||||
//
|
||||
// It will result in overflow in 16 bit-per-component image/pattern resampling
|
||||
// but it won't result any crash and the rest of the library will remain
|
||||
// fully functional.
|
||||
|
||||
|
||||
//---------------------------------------
|
||||
// 2. Default rendering_buffer type. Can be:
|
||||
//
|
||||
// Provides faster access for massive pixel operations,
|
||||
// such as blur, image filtering:
|
||||
// #define AGG_RENDERING_BUFFER row_ptr_cache<int8u>
|
||||
//
|
||||
// Provides cheaper creation and destruction (no mem allocs):
|
||||
// #define AGG_RENDERING_BUFFER row_accessor<int8u>
|
||||
//
|
||||
// You can still use both of them simultaneouslyin your applications
|
||||
// This #define is used only for default rendering_buffer type,
|
||||
// in short hand typedefs like pixfmt_rgba32.
|
||||
|
||||
#endif
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_CONV_ADAPTOR_VCGEN_INCLUDED
|
||||
#define AGG_CONV_ADAPTOR_VCGEN_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//------------------------------------------------------------null_markers
|
||||
struct null_markers
|
||||
{
|
||||
void remove_all() {}
|
||||
void add_vertex(double, double, unsigned) {}
|
||||
void prepare_src() {}
|
||||
|
||||
void rewind(unsigned) {}
|
||||
unsigned vertex(double*, double*) { return path_cmd_stop; }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------conv_adaptor_vcgen
|
||||
template<class VertexSource,
|
||||
class Generator,
|
||||
class Markers=null_markers> class conv_adaptor_vcgen
|
||||
{
|
||||
enum status
|
||||
{
|
||||
initial,
|
||||
accumulate,
|
||||
generate
|
||||
};
|
||||
|
||||
public:
|
||||
explicit conv_adaptor_vcgen(VertexSource& source) :
|
||||
m_source(&source),
|
||||
m_status(initial)
|
||||
{}
|
||||
void attach(VertexSource& source) { m_source = &source; }
|
||||
|
||||
Generator& generator() { return m_generator; }
|
||||
const Generator& generator() const { return m_generator; }
|
||||
|
||||
Markers& markers() { return m_markers; }
|
||||
const Markers& markers() const { return m_markers; }
|
||||
|
||||
void rewind(unsigned path_id)
|
||||
{
|
||||
m_source->rewind(path_id);
|
||||
m_status = initial;
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
private:
|
||||
// Prohibit copying
|
||||
conv_adaptor_vcgen(const conv_adaptor_vcgen<VertexSource, Generator, Markers>&);
|
||||
const conv_adaptor_vcgen<VertexSource, Generator, Markers>&
|
||||
operator = (const conv_adaptor_vcgen<VertexSource, Generator, Markers>&);
|
||||
|
||||
VertexSource* m_source;
|
||||
Generator m_generator;
|
||||
Markers m_markers;
|
||||
status m_status;
|
||||
unsigned m_last_cmd;
|
||||
double m_start_x;
|
||||
double m_start_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class VertexSource, class Generator, class Markers>
|
||||
unsigned conv_adaptor_vcgen<VertexSource, Generator, Markers>::vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_stop;
|
||||
bool done = false;
|
||||
while(!done)
|
||||
{
|
||||
switch(m_status)
|
||||
{
|
||||
case initial:
|
||||
m_markers.remove_all();
|
||||
m_last_cmd = m_source->vertex(&m_start_x, &m_start_y);
|
||||
m_status = accumulate;
|
||||
|
||||
case accumulate:
|
||||
if(is_stop(m_last_cmd)) return path_cmd_stop;
|
||||
|
||||
m_generator.remove_all();
|
||||
m_generator.add_vertex(m_start_x, m_start_y, path_cmd_move_to);
|
||||
m_markers.add_vertex(m_start_x, m_start_y, path_cmd_move_to);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
cmd = m_source->vertex(x, y);
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_last_cmd = cmd;
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
m_start_x = *x;
|
||||
m_start_y = *y;
|
||||
break;
|
||||
}
|
||||
m_generator.add_vertex(*x, *y, cmd);
|
||||
m_markers.add_vertex(*x, *y, path_cmd_line_to);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_stop(cmd))
|
||||
{
|
||||
m_last_cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
if(is_end_poly(cmd))
|
||||
{
|
||||
m_generator.add_vertex(*x, *y, cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_generator.rewind(0);
|
||||
m_status = generate;
|
||||
|
||||
case generate:
|
||||
cmd = m_generator.vertex(x, y);
|
||||
if(is_stop(cmd))
|
||||
{
|
||||
m_status = accumulate;
|
||||
break;
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// classes conv_curve
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_CONV_CURVE_INCLUDED
|
||||
#define AGG_CONV_CURVE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_curves.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
|
||||
//---------------------------------------------------------------conv_curve
|
||||
// Curve converter class. Any path storage can have Bezier curves defined
|
||||
// by their control points. There're two types of curves supported: curve3
|
||||
// and curve4. Curve3 is a conic Bezier curve with 2 endpoints and 1 control
|
||||
// point. Curve4 has 2 control points (4 points in total) and can be used
|
||||
// to interpolate more complicated curves. Curve4, unlike curve3 can be used
|
||||
// to approximate arcs, both circular and elliptical. Curves are approximated
|
||||
// with straight lines and one of the approaches is just to store the whole
|
||||
// sequence of vertices that approximate our curve. It takes additional
|
||||
// memory, and at the same time the consecutive vertices can be calculated
|
||||
// on demand.
|
||||
//
|
||||
// Initially, path storages are not suppose to keep all the vertices of the
|
||||
// curves (although, nothing prevents us from doing so). Instead, path_storage
|
||||
// keeps only vertices, needed to calculate a curve on demand. Those vertices
|
||||
// are marked with special commands. So, if the path_storage contains curves
|
||||
// (which are not real curves yet), and we render this storage directly,
|
||||
// all we will see is only 2 or 3 straight line segments (for curve3 and
|
||||
// curve4 respectively). If we need to see real curves drawn we need to
|
||||
// include this class into the conversion pipeline.
|
||||
//
|
||||
// Class conv_curve recognizes commands path_cmd_curve3 and path_cmd_curve4
|
||||
// and converts these vertices into a move_to/line_to sequence.
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VertexSource,
|
||||
class Curve3=curve3,
|
||||
class Curve4=curve4> class conv_curve
|
||||
{
|
||||
public:
|
||||
typedef Curve3 curve3_type;
|
||||
typedef Curve4 curve4_type;
|
||||
typedef conv_curve<VertexSource, Curve3, Curve4> self_type;
|
||||
|
||||
explicit conv_curve(VertexSource& source) :
|
||||
m_source(&source), m_last_x(0.0), m_last_y(0.0) {}
|
||||
void attach(VertexSource& source) { m_source = &source; }
|
||||
|
||||
void approximation_method(curve_approximation_method_e v)
|
||||
{
|
||||
m_curve3.approximation_method(v);
|
||||
m_curve4.approximation_method(v);
|
||||
}
|
||||
|
||||
curve_approximation_method_e approximation_method() const
|
||||
{
|
||||
return m_curve4.approximation_method();
|
||||
}
|
||||
|
||||
void approximation_scale(double s)
|
||||
{
|
||||
m_curve3.approximation_scale(s);
|
||||
m_curve4.approximation_scale(s);
|
||||
}
|
||||
|
||||
double approximation_scale() const
|
||||
{
|
||||
return m_curve4.approximation_scale();
|
||||
}
|
||||
|
||||
void angle_tolerance(double v)
|
||||
{
|
||||
m_curve3.angle_tolerance(v);
|
||||
m_curve4.angle_tolerance(v);
|
||||
}
|
||||
|
||||
double angle_tolerance() const
|
||||
{
|
||||
return m_curve4.angle_tolerance();
|
||||
}
|
||||
|
||||
void cusp_limit(double v)
|
||||
{
|
||||
m_curve3.cusp_limit(v);
|
||||
m_curve4.cusp_limit(v);
|
||||
}
|
||||
|
||||
double cusp_limit() const
|
||||
{
|
||||
return m_curve4.cusp_limit();
|
||||
}
|
||||
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
private:
|
||||
conv_curve(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
VertexSource* m_source;
|
||||
double m_last_x;
|
||||
double m_last_y;
|
||||
curve3_type m_curve3;
|
||||
curve4_type m_curve4;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class VertexSource, class Curve3, class Curve4>
|
||||
void conv_curve<VertexSource, Curve3, Curve4>::rewind(unsigned path_id)
|
||||
{
|
||||
m_source->rewind(path_id);
|
||||
m_last_x = 0.0;
|
||||
m_last_y = 0.0;
|
||||
m_curve3.reset();
|
||||
m_curve4.reset();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class VertexSource, class Curve3, class Curve4>
|
||||
unsigned conv_curve<VertexSource, Curve3, Curve4>::vertex(double* x, double* y)
|
||||
{
|
||||
if(!is_stop(m_curve3.vertex(x, y)))
|
||||
{
|
||||
m_last_x = *x;
|
||||
m_last_y = *y;
|
||||
return path_cmd_line_to;
|
||||
}
|
||||
|
||||
if(!is_stop(m_curve4.vertex(x, y)))
|
||||
{
|
||||
m_last_x = *x;
|
||||
m_last_y = *y;
|
||||
return path_cmd_line_to;
|
||||
}
|
||||
|
||||
double ct2_x;
|
||||
double ct2_y;
|
||||
double end_x;
|
||||
double end_y;
|
||||
|
||||
unsigned cmd = m_source->vertex(x, y);
|
||||
switch(cmd)
|
||||
{
|
||||
case path_cmd_curve3:
|
||||
m_source->vertex(&end_x, &end_y);
|
||||
|
||||
m_curve3.init(m_last_x, m_last_y,
|
||||
*x, *y,
|
||||
end_x, end_y);
|
||||
|
||||
m_curve3.vertex(x, y); // First call returns path_cmd_move_to
|
||||
m_curve3.vertex(x, y); // This is the first vertex of the curve
|
||||
cmd = path_cmd_line_to;
|
||||
break;
|
||||
|
||||
case path_cmd_curve4:
|
||||
m_source->vertex(&ct2_x, &ct2_y);
|
||||
m_source->vertex(&end_x, &end_y);
|
||||
|
||||
m_curve4.init(m_last_x, m_last_y,
|
||||
*x, *y,
|
||||
ct2_x, ct2_y,
|
||||
end_x, end_y);
|
||||
|
||||
m_curve4.vertex(x, y); // First call returns path_cmd_move_to
|
||||
m_curve4.vertex(x, y); // This is the first vertex of the curve
|
||||
cmd = path_cmd_line_to;
|
||||
break;
|
||||
}
|
||||
m_last_x = *x;
|
||||
m_last_y = *y;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// conv_dash
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CONV_DASH_INCLUDED
|
||||
#define AGG_CONV_DASH_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vcgen_dash.h"
|
||||
#include "agg_conv_adaptor_vcgen.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//---------------------------------------------------------------conv_dash
|
||||
template<class VertexSource, class Markers=null_markers>
|
||||
struct conv_dash : public conv_adaptor_vcgen<VertexSource, vcgen_dash, Markers>
|
||||
{
|
||||
typedef Markers marker_type;
|
||||
typedef conv_adaptor_vcgen<VertexSource, vcgen_dash, Markers> base_type;
|
||||
|
||||
conv_dash(VertexSource& vs) :
|
||||
conv_adaptor_vcgen<VertexSource, vcgen_dash, Markers>(vs)
|
||||
{
|
||||
}
|
||||
|
||||
void Set(const Upp::Vector<double> *dash, double start) {
|
||||
base_type::generator().Set(dash, start);
|
||||
}
|
||||
|
||||
void shorten(double s) { base_type::generator().shorten(s); }
|
||||
double shorten() const { return base_type::generator().shorten(); }
|
||||
|
||||
private:
|
||||
conv_dash(const conv_dash<VertexSource, Markers>&);
|
||||
const conv_dash<VertexSource, Markers>&
|
||||
operator = (const conv_dash<VertexSource, Markers>&);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// conv_stroke
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CONV_STROKE_INCLUDED
|
||||
#define AGG_CONV_STROKE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vcgen_stroke.h"
|
||||
#include "agg_conv_adaptor_vcgen.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------conv_stroke
|
||||
template<class VertexSource, class Markers=null_markers>
|
||||
struct conv_stroke :
|
||||
public conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers>
|
||||
{
|
||||
typedef Markers marker_type;
|
||||
typedef conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers> base_type;
|
||||
|
||||
conv_stroke(VertexSource& vs) :
|
||||
conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers>(vs)
|
||||
{
|
||||
}
|
||||
|
||||
void line_cap(line_cap_e lc) { base_type::generator().line_cap(lc); }
|
||||
void line_join(line_join_e lj) { base_type::generator().line_join(lj); }
|
||||
void inner_join(inner_join_e ij) { base_type::generator().inner_join(ij); }
|
||||
|
||||
line_cap_e line_cap() const { return base_type::generator().line_cap(); }
|
||||
line_join_e line_join() const { return base_type::generator().line_join(); }
|
||||
inner_join_e inner_join() const { return base_type::generator().inner_join(); }
|
||||
|
||||
void width(double w) { base_type::generator().width(w); }
|
||||
void miter_limit(double ml) { base_type::generator().miter_limit(ml); }
|
||||
void miter_limit_theta(double t) { base_type::generator().miter_limit_theta(t); }
|
||||
void inner_miter_limit(double ml) { base_type::generator().inner_miter_limit(ml); }
|
||||
void approximation_scale(double as) { base_type::generator().approximation_scale(as); }
|
||||
|
||||
double width() const { return base_type::generator().width(); }
|
||||
double miter_limit() const { return base_type::generator().miter_limit(); }
|
||||
double inner_miter_limit() const { return base_type::generator().inner_miter_limit(); }
|
||||
double approximation_scale() const { return base_type::generator().approximation_scale(); }
|
||||
|
||||
void shorten(double s) { base_type::generator().shorten(s); }
|
||||
double shorten() const { return base_type::generator().shorten(); }
|
||||
|
||||
private:
|
||||
conv_stroke(const conv_stroke<VertexSource, Markers>&);
|
||||
const conv_stroke<VertexSource, Markers>&
|
||||
operator = (const conv_stroke<VertexSource, Markers>&);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class conv_transform
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CONV_TRANSFORM_INCLUDED
|
||||
#define AGG_CONV_TRANSFORM_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//----------------------------------------------------------conv_transform
|
||||
template<class VertexSource, class Transformer=trans_affine> class conv_transform
|
||||
{
|
||||
public:
|
||||
conv_transform(VertexSource& source, const Transformer& tr) :
|
||||
m_source(&source), m_trans(&tr) {}
|
||||
void attach(VertexSource& source) { m_source = &source; }
|
||||
|
||||
void rewind(unsigned path_id)
|
||||
{
|
||||
m_source->rewind(path_id);
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = m_source->vertex(x, y);
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_trans->transform(x, y);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void transformer(const Transformer& tr)
|
||||
{
|
||||
m_trans = &tr;
|
||||
}
|
||||
|
||||
private:
|
||||
conv_transform(const conv_transform<VertexSource>&);
|
||||
const conv_transform<VertexSource>&
|
||||
operator = (const conv_transform<VertexSource>&);
|
||||
|
||||
VertexSource* m_source;
|
||||
const Transformer* m_trans;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,610 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "Painter.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const double curve_distance_epsilon = 1e-30;
|
||||
const double curve_collinearity_epsilon = 1e-30;
|
||||
const double curve_angle_tolerance_epsilon = 0.01;
|
||||
enum curve_recursion_limit_e { curve_recursion_limit = 32 };
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve3_inc::approximation_scale(double s)
|
||||
{
|
||||
m_scale = s;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double curve3_inc::approximation_scale() const
|
||||
{
|
||||
return m_scale;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve3_inc::init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
m_start_x = x1;
|
||||
m_start_y = y1;
|
||||
m_end_x = x3;
|
||||
m_end_y = y3;
|
||||
|
||||
double dx1 = x2 - x1;
|
||||
double dy1 = y2 - y1;
|
||||
double dx2 = x3 - x2;
|
||||
double dy2 = y3 - y2;
|
||||
|
||||
double len = sqrt(dx1 * dx1 + dy1 * dy1) + sqrt(dx2 * dx2 + dy2 * dy2);
|
||||
|
||||
m_num_steps = uround(len * 0.25 * m_scale);
|
||||
|
||||
if(m_num_steps < 4)
|
||||
{
|
||||
m_num_steps = 4;
|
||||
}
|
||||
|
||||
double subdivide_step = 1.0 / m_num_steps;
|
||||
double subdivide_step2 = subdivide_step * subdivide_step;
|
||||
|
||||
double tmpx = (x1 - x2 * 2.0 + x3) * subdivide_step2;
|
||||
double tmpy = (y1 - y2 * 2.0 + y3) * subdivide_step2;
|
||||
|
||||
m_saved_fx = m_fx = x1;
|
||||
m_saved_fy = m_fy = y1;
|
||||
|
||||
m_saved_dfx = m_dfx = tmpx + (x2 - x1) * (2.0 * subdivide_step);
|
||||
m_saved_dfy = m_dfy = tmpy + (y2 - y1) * (2.0 * subdivide_step);
|
||||
|
||||
m_ddfx = tmpx * 2.0;
|
||||
m_ddfy = tmpy * 2.0;
|
||||
|
||||
m_step = m_num_steps;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve3_inc::rewind(unsigned)
|
||||
{
|
||||
if(m_num_steps == 0)
|
||||
{
|
||||
m_step = -1;
|
||||
return;
|
||||
}
|
||||
m_step = m_num_steps;
|
||||
m_fx = m_saved_fx;
|
||||
m_fy = m_saved_fy;
|
||||
m_dfx = m_saved_dfx;
|
||||
m_dfy = m_saved_dfy;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned curve3_inc::vertex(double* x, double* y)
|
||||
{
|
||||
if(m_step < 0) return path_cmd_stop;
|
||||
if(m_step == m_num_steps)
|
||||
{
|
||||
*x = m_start_x;
|
||||
*y = m_start_y;
|
||||
--m_step;
|
||||
return path_cmd_move_to;
|
||||
}
|
||||
if(m_step == 0)
|
||||
{
|
||||
*x = m_end_x;
|
||||
*y = m_end_y;
|
||||
--m_step;
|
||||
return path_cmd_line_to;
|
||||
}
|
||||
m_fx += m_dfx;
|
||||
m_fy += m_dfy;
|
||||
m_dfx += m_ddfx;
|
||||
m_dfy += m_ddfy;
|
||||
*x = m_fx;
|
||||
*y = m_fy;
|
||||
--m_step;
|
||||
return path_cmd_line_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve3_div::init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
m_points.remove_all();
|
||||
m_distance_tolerance_square = 0.5 / m_approximation_scale;
|
||||
m_distance_tolerance_square *= m_distance_tolerance_square;
|
||||
bezier(x1, y1, x2, y2, x3, y3);
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve3_div::recursive_bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
unsigned level)
|
||||
{
|
||||
if(level > curve_recursion_limit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate all the mid-points of the line segments
|
||||
//----------------------
|
||||
double x12 = (x1 + x2) / 2;
|
||||
double y12 = (y1 + y2) / 2;
|
||||
double x23 = (x2 + x3) / 2;
|
||||
double y23 = (y2 + y3) / 2;
|
||||
double x123 = (x12 + x23) / 2;
|
||||
double y123 = (y12 + y23) / 2;
|
||||
|
||||
double dx = x3-x1;
|
||||
double dy = y3-y1;
|
||||
double d = fabs(((x2 - x3) * dy - (y2 - y3) * dx));
|
||||
double da;
|
||||
|
||||
if(d > curve_collinearity_epsilon)
|
||||
{
|
||||
// Regular case
|
||||
//-----------------
|
||||
if(d * d <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
||||
{
|
||||
// If the curvature doesn't exceed the distance_tolerance value
|
||||
// we tend to finish subdivisions.
|
||||
//----------------------
|
||||
if(m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||
{
|
||||
m_points.add(point_d(x123, y123));
|
||||
return;
|
||||
}
|
||||
|
||||
// Angle & Cusp Condition
|
||||
//----------------------
|
||||
da = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1));
|
||||
if(da >= pi) da = 2*pi - da;
|
||||
|
||||
if(da < m_angle_tolerance)
|
||||
{
|
||||
// Finally we can stop the recursion
|
||||
//----------------------
|
||||
m_points.add(point_d(x123, y123));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Collinear case
|
||||
//------------------
|
||||
da = dx*dx + dy*dy;
|
||||
if(da == 0)
|
||||
{
|
||||
d = calc_sq_distance(x1, y1, x2, y2);
|
||||
}
|
||||
else
|
||||
{
|
||||
d = ((x2 - x1)*dx + (y2 - y1)*dy) / da;
|
||||
if(d > 0 && d < 1)
|
||||
{
|
||||
// Simple collinear case, 1---2---3
|
||||
// We can leave just two endpoints
|
||||
return;
|
||||
}
|
||||
if(d <= 0) d = calc_sq_distance(x2, y2, x1, y1);
|
||||
else if(d >= 1) d = calc_sq_distance(x2, y2, x3, y3);
|
||||
else d = calc_sq_distance(x2, y2, x1 + d*dx, y1 + d*dy);
|
||||
}
|
||||
if(d < m_distance_tolerance_square)
|
||||
{
|
||||
m_points.add(point_d(x2, y2));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue subdivision
|
||||
//----------------------
|
||||
recursive_bezier(x1, y1, x12, y12, x123, y123, level + 1);
|
||||
recursive_bezier(x123, y123, x23, y23, x3, y3, level + 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve3_div::bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
PAINTER_TIMING("curve3_div::bezier");
|
||||
m_points.add(point_d(x1, y1));
|
||||
recursive_bezier(x1, y1, x2, y2, x3, y3, 0);
|
||||
m_points.add(point_d(x3, y3));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve4_inc::approximation_scale(double s)
|
||||
{
|
||||
m_scale = s;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double curve4_inc::approximation_scale() const
|
||||
{
|
||||
return m_scale;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static double MSC60_fix_ICE(double v) { return v; }
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve4_inc::init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
m_start_x = x1;
|
||||
m_start_y = y1;
|
||||
m_end_x = x4;
|
||||
m_end_y = y4;
|
||||
|
||||
double dx1 = x2 - x1;
|
||||
double dy1 = y2 - y1;
|
||||
double dx2 = x3 - x2;
|
||||
double dy2 = y3 - y2;
|
||||
double dx3 = x4 - x3;
|
||||
double dy3 = y4 - y3;
|
||||
|
||||
double len = (sqrt(dx1 * dx1 + dy1 * dy1) +
|
||||
sqrt(dx2 * dx2 + dy2 * dy2) +
|
||||
sqrt(dx3 * dx3 + dy3 * dy3)) * 0.25 * m_scale;
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
m_num_steps = uround(MSC60_fix_ICE(len));
|
||||
#else
|
||||
m_num_steps = uround(len);
|
||||
#endif
|
||||
|
||||
if(m_num_steps < 4)
|
||||
{
|
||||
m_num_steps = 4;
|
||||
}
|
||||
|
||||
double subdivide_step = 1.0 / m_num_steps;
|
||||
double subdivide_step2 = subdivide_step * subdivide_step;
|
||||
double subdivide_step3 = subdivide_step * subdivide_step * subdivide_step;
|
||||
|
||||
double pre1 = 3.0 * subdivide_step;
|
||||
double pre2 = 3.0 * subdivide_step2;
|
||||
double pre4 = 6.0 * subdivide_step2;
|
||||
double pre5 = 6.0 * subdivide_step3;
|
||||
|
||||
double tmp1x = x1 - x2 * 2.0 + x3;
|
||||
double tmp1y = y1 - y2 * 2.0 + y3;
|
||||
|
||||
double tmp2x = (x2 - x3) * 3.0 - x1 + x4;
|
||||
double tmp2y = (y2 - y3) * 3.0 - y1 + y4;
|
||||
|
||||
m_saved_fx = m_fx = x1;
|
||||
m_saved_fy = m_fy = y1;
|
||||
|
||||
m_saved_dfx = m_dfx = (x2 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdivide_step3;
|
||||
m_saved_dfy = m_dfy = (y2 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdivide_step3;
|
||||
|
||||
m_saved_ddfx = m_ddfx = tmp1x * pre4 + tmp2x * pre5;
|
||||
m_saved_ddfy = m_ddfy = tmp1y * pre4 + tmp2y * pre5;
|
||||
|
||||
m_dddfx = tmp2x * pre5;
|
||||
m_dddfy = tmp2y * pre5;
|
||||
|
||||
m_step = m_num_steps;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve4_inc::rewind(unsigned)
|
||||
{
|
||||
if(m_num_steps == 0)
|
||||
{
|
||||
m_step = -1;
|
||||
return;
|
||||
}
|
||||
m_step = m_num_steps;
|
||||
m_fx = m_saved_fx;
|
||||
m_fy = m_saved_fy;
|
||||
m_dfx = m_saved_dfx;
|
||||
m_dfy = m_saved_dfy;
|
||||
m_ddfx = m_saved_ddfx;
|
||||
m_ddfy = m_saved_ddfy;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned curve4_inc::vertex(double* x, double* y)
|
||||
{
|
||||
if(m_step < 0) return path_cmd_stop;
|
||||
if(m_step == m_num_steps)
|
||||
{
|
||||
*x = m_start_x;
|
||||
*y = m_start_y;
|
||||
--m_step;
|
||||
return path_cmd_move_to;
|
||||
}
|
||||
|
||||
if(m_step == 0)
|
||||
{
|
||||
*x = m_end_x;
|
||||
*y = m_end_y;
|
||||
--m_step;
|
||||
return path_cmd_line_to;
|
||||
}
|
||||
|
||||
m_fx += m_dfx;
|
||||
m_fy += m_dfy;
|
||||
m_dfx += m_ddfx;
|
||||
m_dfy += m_ddfy;
|
||||
m_ddfx += m_dddfx;
|
||||
m_ddfy += m_dddfy;
|
||||
|
||||
*x = m_fx;
|
||||
*y = m_fy;
|
||||
--m_step;
|
||||
return path_cmd_line_to;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve4_div::init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
m_points.remove_all();
|
||||
m_distance_tolerance_square = 0.5 / m_approximation_scale;
|
||||
m_distance_tolerance_square *= m_distance_tolerance_square;
|
||||
bezier(x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve4_div::recursive_bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4,
|
||||
unsigned level)
|
||||
{
|
||||
if(level > curve_recursion_limit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate all the mid-points of the line segments
|
||||
//----------------------
|
||||
double x12 = (x1 + x2) / 2;
|
||||
double y12 = (y1 + y2) / 2;
|
||||
double x23 = (x2 + x3) / 2;
|
||||
double y23 = (y2 + y3) / 2;
|
||||
double x34 = (x3 + x4) / 2;
|
||||
double y34 = (y3 + y4) / 2;
|
||||
double x123 = (x12 + x23) / 2;
|
||||
double y123 = (y12 + y23) / 2;
|
||||
double x234 = (x23 + x34) / 2;
|
||||
double y234 = (y23 + y34) / 2;
|
||||
double x1234 = (x123 + x234) / 2;
|
||||
double y1234 = (y123 + y234) / 2;
|
||||
|
||||
|
||||
// Try to approximate the full cubic curve by a single straight line
|
||||
//------------------
|
||||
double dx = x4-x1;
|
||||
double dy = y4-y1;
|
||||
|
||||
double d2 = fabs(((x2 - x4) * dy - (y2 - y4) * dx));
|
||||
double d3 = fabs(((x3 - x4) * dy - (y3 - y4) * dx));
|
||||
double da1, da2, k;
|
||||
|
||||
switch((int(d2 > curve_collinearity_epsilon) << 1) +
|
||||
int(d3 > curve_collinearity_epsilon))
|
||||
{
|
||||
case 0:
|
||||
// All collinear OR p1==p4
|
||||
//----------------------
|
||||
k = dx*dx + dy*dy;
|
||||
if(k == 0)
|
||||
{
|
||||
d2 = calc_sq_distance(x1, y1, x2, y2);
|
||||
d3 = calc_sq_distance(x4, y4, x3, y3);
|
||||
}
|
||||
else
|
||||
{
|
||||
k = 1 / k;
|
||||
da1 = x2 - x1;
|
||||
da2 = y2 - y1;
|
||||
d2 = k * (da1*dx + da2*dy);
|
||||
da1 = x3 - x1;
|
||||
da2 = y3 - y1;
|
||||
d3 = k * (da1*dx + da2*dy);
|
||||
if(d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1)
|
||||
{
|
||||
// Simple collinear case, 1---2---3---4
|
||||
// We can leave just two endpoints
|
||||
return;
|
||||
}
|
||||
if(d2 <= 0) d2 = calc_sq_distance(x2, y2, x1, y1);
|
||||
else if(d2 >= 1) d2 = calc_sq_distance(x2, y2, x4, y4);
|
||||
else d2 = calc_sq_distance(x2, y2, x1 + d2*dx, y1 + d2*dy);
|
||||
|
||||
if(d3 <= 0) d3 = calc_sq_distance(x3, y3, x1, y1);
|
||||
else if(d3 >= 1) d3 = calc_sq_distance(x3, y3, x4, y4);
|
||||
else d3 = calc_sq_distance(x3, y3, x1 + d3*dx, y1 + d3*dy);
|
||||
}
|
||||
if(d2 > d3)
|
||||
{
|
||||
if(d2 < m_distance_tolerance_square)
|
||||
{
|
||||
m_points.add(point_d(x2, y2));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(d3 < m_distance_tolerance_square)
|
||||
{
|
||||
m_points.add(point_d(x3, y3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// p1,p2,p4 are collinear, p3 is significant
|
||||
//----------------------
|
||||
if(d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
||||
{
|
||||
if(m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||
{
|
||||
m_points.add(point_d(x23, y23));
|
||||
return;
|
||||
}
|
||||
|
||||
// Angle Condition
|
||||
//----------------------
|
||||
da1 = fabs(atan2(y4 - y3, x4 - x3) - atan2(y3 - y2, x3 - x2));
|
||||
if(da1 >= pi) da1 = 2*pi - da1;
|
||||
|
||||
if(da1 < m_angle_tolerance)
|
||||
{
|
||||
m_points.add(point_d(x2, y2));
|
||||
m_points.add(point_d(x3, y3));
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_cusp_limit != 0.0)
|
||||
{
|
||||
if(da1 > m_cusp_limit)
|
||||
{
|
||||
m_points.add(point_d(x3, y3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// p1,p3,p4 are collinear, p2 is significant
|
||||
//----------------------
|
||||
if(d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
||||
{
|
||||
if(m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||
{
|
||||
m_points.add(point_d(x23, y23));
|
||||
return;
|
||||
}
|
||||
|
||||
// Angle Condition
|
||||
//----------------------
|
||||
da1 = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1));
|
||||
if(da1 >= pi) da1 = 2*pi - da1;
|
||||
|
||||
if(da1 < m_angle_tolerance)
|
||||
{
|
||||
m_points.add(point_d(x2, y2));
|
||||
m_points.add(point_d(x3, y3));
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_cusp_limit != 0.0)
|
||||
{
|
||||
if(da1 > m_cusp_limit)
|
||||
{
|
||||
m_points.add(point_d(x2, y2));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Regular case
|
||||
//-----------------
|
||||
if((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy))
|
||||
{
|
||||
// If the curvature doesn't exceed the distance_tolerance value
|
||||
// we tend to finish subdivisions.
|
||||
//----------------------
|
||||
if(m_angle_tolerance < curve_angle_tolerance_epsilon)
|
||||
{
|
||||
m_points.add(point_d(x23, y23));
|
||||
return;
|
||||
}
|
||||
|
||||
// Angle & Cusp Condition
|
||||
//----------------------
|
||||
k = atan2(y3 - y2, x3 - x2);
|
||||
da1 = fabs(k - atan2(y2 - y1, x2 - x1));
|
||||
da2 = fabs(atan2(y4 - y3, x4 - x3) - k);
|
||||
if(da1 >= pi) da1 = 2*pi - da1;
|
||||
if(da2 >= pi) da2 = 2*pi - da2;
|
||||
|
||||
if(da1 + da2 < m_angle_tolerance)
|
||||
{
|
||||
// Finally we can stop the recursion
|
||||
//----------------------
|
||||
m_points.add(point_d(x23, y23));
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_cusp_limit != 0.0)
|
||||
{
|
||||
if(da1 > m_cusp_limit)
|
||||
{
|
||||
m_points.add(point_d(x2, y2));
|
||||
return;
|
||||
}
|
||||
|
||||
if(da2 > m_cusp_limit)
|
||||
{
|
||||
m_points.add(point_d(x3, y3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Continue subdivision
|
||||
//----------------------
|
||||
recursive_bezier(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1);
|
||||
recursive_bezier(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void curve4_div::bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
m_points.add(point_d(x1, y1));
|
||||
recursive_bezier(x1, y1, x2, y2, x3, y3, x4, y4, 0);
|
||||
m_points.add(point_d(x4, y4));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,693 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
// Copyright (C) 2005 Tony Juricic (tonygeek@yahoo.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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_CURVES_INCLUDED
|
||||
#define AGG_CURVES_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
// See Implementation agg_curves.cpp
|
||||
|
||||
//--------------------------------------------curve_approximation_method_e
|
||||
enum curve_approximation_method_e
|
||||
{
|
||||
curve_inc,
|
||||
curve_div
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------curve3_inc
|
||||
class curve3_inc
|
||||
{
|
||||
public:
|
||||
curve3_inc() :
|
||||
m_num_steps(0), m_step(0), m_scale(1.0) { }
|
||||
|
||||
curve3_inc(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3) :
|
||||
m_num_steps(0), m_step(0), m_scale(1.0)
|
||||
{
|
||||
init(x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
void reset() { m_num_steps = 0; m_step = -1; }
|
||||
void init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3);
|
||||
|
||||
void approximation_method(curve_approximation_method_e) {}
|
||||
curve_approximation_method_e approximation_method() const { return curve_inc; }
|
||||
|
||||
void approximation_scale(double s);
|
||||
double approximation_scale() const;
|
||||
|
||||
void angle_tolerance(double) {}
|
||||
double angle_tolerance() const { return 0.0; }
|
||||
|
||||
void cusp_limit(double) {}
|
||||
double cusp_limit() const { return 0.0; }
|
||||
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
private:
|
||||
int m_num_steps;
|
||||
int m_step;
|
||||
double m_scale;
|
||||
double m_start_x;
|
||||
double m_start_y;
|
||||
double m_end_x;
|
||||
double m_end_y;
|
||||
double m_fx;
|
||||
double m_fy;
|
||||
double m_dfx;
|
||||
double m_dfy;
|
||||
double m_ddfx;
|
||||
double m_ddfy;
|
||||
double m_saved_fx;
|
||||
double m_saved_fy;
|
||||
double m_saved_dfx;
|
||||
double m_saved_dfy;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------curve3_div
|
||||
class curve3_div
|
||||
{
|
||||
public:
|
||||
curve3_div() :
|
||||
m_approximation_scale(1.0),
|
||||
m_angle_tolerance(0.0),
|
||||
m_count(0)
|
||||
{}
|
||||
|
||||
curve3_div(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3) :
|
||||
m_approximation_scale(1.0),
|
||||
m_angle_tolerance(0.0),
|
||||
m_count(0)
|
||||
{
|
||||
init(x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
void reset() { m_points.remove_all(); m_count = 0; }
|
||||
void init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3);
|
||||
|
||||
void approximation_method(curve_approximation_method_e) {}
|
||||
curve_approximation_method_e approximation_method() const { return curve_div; }
|
||||
|
||||
void approximation_scale(double s) { m_approximation_scale = s; }
|
||||
double approximation_scale() const { return m_approximation_scale; }
|
||||
|
||||
void angle_tolerance(double a) { m_angle_tolerance = a; }
|
||||
double angle_tolerance() const { return m_angle_tolerance; }
|
||||
|
||||
void cusp_limit(double) {}
|
||||
double cusp_limit() const { return 0.0; }
|
||||
|
||||
void rewind(unsigned)
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
if(m_count >= m_points.size()) return path_cmd_stop;
|
||||
const point_d& p = m_points[m_count++];
|
||||
*x = p.x;
|
||||
*y = p.y;
|
||||
return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to;
|
||||
}
|
||||
|
||||
private:
|
||||
void bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3);
|
||||
void recursive_bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
unsigned level);
|
||||
|
||||
double m_approximation_scale;
|
||||
double m_distance_tolerance_square;
|
||||
double m_angle_tolerance;
|
||||
unsigned m_count;
|
||||
pod_bvector<point_d> m_points;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------curve4_points
|
||||
struct curve4_points
|
||||
{
|
||||
double cp[8];
|
||||
curve4_points() {}
|
||||
curve4_points(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2;
|
||||
cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4;
|
||||
}
|
||||
void init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2;
|
||||
cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4;
|
||||
}
|
||||
double operator [] (unsigned i) const { return cp[i]; }
|
||||
double& operator [] (unsigned i) { return cp[i]; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------curve4_inc
|
||||
class curve4_inc
|
||||
{
|
||||
public:
|
||||
curve4_inc() :
|
||||
m_num_steps(0), m_step(0), m_scale(1.0) { }
|
||||
|
||||
curve4_inc(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4) :
|
||||
m_num_steps(0), m_step(0), m_scale(1.0)
|
||||
{
|
||||
init(x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
curve4_inc(const curve4_points& cp) :
|
||||
m_num_steps(0), m_step(0), m_scale(1.0)
|
||||
{
|
||||
init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
void reset() { m_num_steps = 0; m_step = -1; }
|
||||
void init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4);
|
||||
|
||||
void init(const curve4_points& cp)
|
||||
{
|
||||
init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
void approximation_method(curve_approximation_method_e) {}
|
||||
curve_approximation_method_e approximation_method() const { return curve_inc; }
|
||||
|
||||
void approximation_scale(double s);
|
||||
double approximation_scale() const;
|
||||
|
||||
void angle_tolerance(double) {}
|
||||
double angle_tolerance() const { return 0.0; }
|
||||
|
||||
void cusp_limit(double) {}
|
||||
double cusp_limit() const { return 0.0; }
|
||||
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
private:
|
||||
int m_num_steps;
|
||||
int m_step;
|
||||
double m_scale;
|
||||
double m_start_x;
|
||||
double m_start_y;
|
||||
double m_end_x;
|
||||
double m_end_y;
|
||||
double m_fx;
|
||||
double m_fy;
|
||||
double m_dfx;
|
||||
double m_dfy;
|
||||
double m_ddfx;
|
||||
double m_ddfy;
|
||||
double m_dddfx;
|
||||
double m_dddfy;
|
||||
double m_saved_fx;
|
||||
double m_saved_fy;
|
||||
double m_saved_dfx;
|
||||
double m_saved_dfy;
|
||||
double m_saved_ddfx;
|
||||
double m_saved_ddfy;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------catrom_to_bezier
|
||||
inline curve4_points catrom_to_bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
// Trans. matrix Catmull-Rom to Bezier
|
||||
//
|
||||
// 0 1 0 0
|
||||
// -1/6 1 1/6 0
|
||||
// 0 1/6 1 -1/6
|
||||
// 0 0 1 0
|
||||
//
|
||||
return curve4_points(
|
||||
x2,
|
||||
y2,
|
||||
(-x1 + 6*x2 + x3) / 6,
|
||||
(-y1 + 6*y2 + y3) / 6,
|
||||
( x2 + 6*x3 - x4) / 6,
|
||||
( y2 + 6*y3 - y4) / 6,
|
||||
x3,
|
||||
y3);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
inline curve4_points
|
||||
catrom_to_bezier(const curve4_points& cp)
|
||||
{
|
||||
return catrom_to_bezier(cp[0], cp[1], cp[2], cp[3],
|
||||
cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------ubspline_to_bezier
|
||||
inline curve4_points ubspline_to_bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
// Trans. matrix Uniform BSpline to Bezier
|
||||
//
|
||||
// 1/6 4/6 1/6 0
|
||||
// 0 4/6 2/6 0
|
||||
// 0 2/6 4/6 0
|
||||
// 0 1/6 4/6 1/6
|
||||
//
|
||||
return curve4_points(
|
||||
(x1 + 4*x2 + x3) / 6,
|
||||
(y1 + 4*y2 + y3) / 6,
|
||||
(4*x2 + 2*x3) / 6,
|
||||
(4*y2 + 2*y3) / 6,
|
||||
(2*x2 + 4*x3) / 6,
|
||||
(2*y2 + 4*y3) / 6,
|
||||
(x2 + 4*x3 + x4) / 6,
|
||||
(y2 + 4*y3 + y4) / 6);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
inline curve4_points
|
||||
ubspline_to_bezier(const curve4_points& cp)
|
||||
{
|
||||
return ubspline_to_bezier(cp[0], cp[1], cp[2], cp[3],
|
||||
cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------hermite_to_bezier
|
||||
inline curve4_points hermite_to_bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
// Trans. matrix Hermite to Bezier
|
||||
//
|
||||
// 1 0 0 0
|
||||
// 1 0 1/3 0
|
||||
// 0 1 0 -1/3
|
||||
// 0 1 0 0
|
||||
//
|
||||
return curve4_points(
|
||||
x1,
|
||||
y1,
|
||||
(3*x1 + x3) / 3,
|
||||
(3*y1 + y3) / 3,
|
||||
(3*x2 - x4) / 3,
|
||||
(3*y2 - y4) / 3,
|
||||
x2,
|
||||
y2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
inline curve4_points
|
||||
hermite_to_bezier(const curve4_points& cp)
|
||||
{
|
||||
return hermite_to_bezier(cp[0], cp[1], cp[2], cp[3],
|
||||
cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------curve4_div
|
||||
class curve4_div
|
||||
{
|
||||
public:
|
||||
curve4_div() :
|
||||
m_approximation_scale(1.0),
|
||||
m_angle_tolerance(0.0),
|
||||
m_cusp_limit(0.0),
|
||||
m_count(0)
|
||||
{}
|
||||
|
||||
curve4_div(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4) :
|
||||
m_approximation_scale(1.0),
|
||||
m_angle_tolerance(0.0),
|
||||
m_cusp_limit(0.0),
|
||||
m_count(0)
|
||||
{
|
||||
init(x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
curve4_div(const curve4_points& cp) :
|
||||
m_approximation_scale(1.0),
|
||||
m_angle_tolerance(0.0),
|
||||
m_count(0)
|
||||
{
|
||||
init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
void reset() { m_points.remove_all(); m_count = 0; }
|
||||
void init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4);
|
||||
|
||||
void init(const curve4_points& cp)
|
||||
{
|
||||
init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
void approximation_method(curve_approximation_method_e) {}
|
||||
|
||||
curve_approximation_method_e approximation_method() const
|
||||
{
|
||||
return curve_div;
|
||||
}
|
||||
|
||||
void approximation_scale(double s) { m_approximation_scale = s; }
|
||||
double approximation_scale() const { return m_approximation_scale; }
|
||||
|
||||
void angle_tolerance(double a) { m_angle_tolerance = a; }
|
||||
double angle_tolerance() const { return m_angle_tolerance; }
|
||||
|
||||
void cusp_limit(double v)
|
||||
{
|
||||
m_cusp_limit = (v == 0.0) ? 0.0 : pi - v;
|
||||
}
|
||||
|
||||
double cusp_limit() const
|
||||
{
|
||||
return (m_cusp_limit == 0.0) ? 0.0 : pi - m_cusp_limit;
|
||||
}
|
||||
|
||||
void rewind(unsigned)
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
if(m_count >= m_points.size()) return path_cmd_stop;
|
||||
const point_d& p = m_points[m_count++];
|
||||
*x = p.x;
|
||||
*y = p.y;
|
||||
return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to;
|
||||
}
|
||||
|
||||
private:
|
||||
void bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4);
|
||||
|
||||
void recursive_bezier(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4,
|
||||
unsigned level);
|
||||
|
||||
double m_approximation_scale;
|
||||
double m_distance_tolerance_square;
|
||||
double m_angle_tolerance;
|
||||
double m_cusp_limit;
|
||||
unsigned m_count;
|
||||
pod_bvector<point_d> m_points;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------curve3
|
||||
class curve3
|
||||
{
|
||||
public:
|
||||
curve3() : m_approximation_method(curve_div) {}
|
||||
curve3(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3) :
|
||||
m_approximation_method(curve_div)
|
||||
{
|
||||
init(x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_curve_inc.reset();
|
||||
m_curve_div.reset();
|
||||
}
|
||||
|
||||
void init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
if(m_approximation_method == curve_inc)
|
||||
{
|
||||
m_curve_inc.init(x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_curve_div.init(x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
}
|
||||
|
||||
void approximation_method(curve_approximation_method_e v)
|
||||
{
|
||||
m_approximation_method = v;
|
||||
}
|
||||
|
||||
curve_approximation_method_e approximation_method() const
|
||||
{
|
||||
return m_approximation_method;
|
||||
}
|
||||
|
||||
void approximation_scale(double s)
|
||||
{
|
||||
m_curve_inc.approximation_scale(s);
|
||||
m_curve_div.approximation_scale(s);
|
||||
}
|
||||
|
||||
double approximation_scale() const
|
||||
{
|
||||
return m_curve_inc.approximation_scale();
|
||||
}
|
||||
|
||||
void angle_tolerance(double a)
|
||||
{
|
||||
m_curve_div.angle_tolerance(a);
|
||||
}
|
||||
|
||||
double angle_tolerance() const
|
||||
{
|
||||
return m_curve_div.angle_tolerance();
|
||||
}
|
||||
|
||||
void cusp_limit(double v)
|
||||
{
|
||||
m_curve_div.cusp_limit(v);
|
||||
}
|
||||
|
||||
double cusp_limit() const
|
||||
{
|
||||
return m_curve_div.cusp_limit();
|
||||
}
|
||||
|
||||
void rewind(unsigned path_id)
|
||||
{
|
||||
if(m_approximation_method == curve_inc)
|
||||
{
|
||||
m_curve_inc.rewind(path_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_curve_div.rewind(path_id);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
if(m_approximation_method == curve_inc)
|
||||
{
|
||||
return m_curve_inc.vertex(x, y);
|
||||
}
|
||||
return m_curve_div.vertex(x, y);
|
||||
}
|
||||
|
||||
private:
|
||||
curve3_inc m_curve_inc;
|
||||
curve3_div m_curve_div;
|
||||
curve_approximation_method_e m_approximation_method;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------curve4
|
||||
class curve4
|
||||
{
|
||||
public:
|
||||
curve4() : m_approximation_method(curve_div) {}
|
||||
curve4(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4) :
|
||||
m_approximation_method(curve_div)
|
||||
{
|
||||
init(x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
|
||||
curve4(const curve4_points& cp) :
|
||||
m_approximation_method(curve_div)
|
||||
{
|
||||
init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_curve_inc.reset();
|
||||
m_curve_div.reset();
|
||||
}
|
||||
|
||||
void init(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x4, double y4)
|
||||
{
|
||||
if(m_approximation_method == curve_inc)
|
||||
{
|
||||
m_curve_inc.init(x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_curve_div.init(x1, y1, x2, y2, x3, y3, x4, y4);
|
||||
}
|
||||
}
|
||||
|
||||
void init(const curve4_points& cp)
|
||||
{
|
||||
init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
|
||||
}
|
||||
|
||||
void approximation_method(curve_approximation_method_e v)
|
||||
{
|
||||
m_approximation_method = v;
|
||||
}
|
||||
|
||||
curve_approximation_method_e approximation_method() const
|
||||
{
|
||||
return m_approximation_method;
|
||||
}
|
||||
|
||||
void approximation_scale(double s)
|
||||
{
|
||||
m_curve_inc.approximation_scale(s);
|
||||
m_curve_div.approximation_scale(s);
|
||||
}
|
||||
double approximation_scale() const { return m_curve_inc.approximation_scale(); }
|
||||
|
||||
void angle_tolerance(double v)
|
||||
{
|
||||
m_curve_div.angle_tolerance(v);
|
||||
}
|
||||
|
||||
double angle_tolerance() const
|
||||
{
|
||||
return m_curve_div.angle_tolerance();
|
||||
}
|
||||
|
||||
void cusp_limit(double v)
|
||||
{
|
||||
m_curve_div.cusp_limit(v);
|
||||
}
|
||||
|
||||
double cusp_limit() const
|
||||
{
|
||||
return m_curve_div.cusp_limit();
|
||||
}
|
||||
|
||||
void rewind(unsigned path_id)
|
||||
{
|
||||
if(m_approximation_method == curve_inc)
|
||||
{
|
||||
m_curve_inc.rewind(path_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_curve_div.rewind(path_id);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
if(m_approximation_method == curve_inc)
|
||||
{
|
||||
return m_curve_inc.vertex(x, y);
|
||||
}
|
||||
return m_curve_div.vertex(x, y);
|
||||
}
|
||||
|
||||
private:
|
||||
curve4_inc m_curve_inc;
|
||||
curve4_div m_curve_div;
|
||||
curve_approximation_method_e m_approximation_method;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,290 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// classes dda_line_interpolator, dda2_line_interpolator
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_DDA_LINE_INCLUDED
|
||||
#define AGG_DDA_LINE_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//===================================================dda_line_interpolator
|
||||
template<int FractionShift, int YShift=0> class dda_line_interpolator
|
||||
{
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
dda_line_interpolator() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
dda_line_interpolator(int y1, int y2, unsigned count) :
|
||||
m_y(y1),
|
||||
m_inc(((y2 - y1) << FractionShift) / int(count)),
|
||||
m_dy(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator ++ ()
|
||||
{
|
||||
m_dy += m_inc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator -- ()
|
||||
{
|
||||
m_dy -= m_inc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator += (unsigned n)
|
||||
{
|
||||
m_dy += m_inc * n;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator -= (unsigned n)
|
||||
{
|
||||
m_dy -= m_inc * n;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y + (m_dy >> (FractionShift-YShift)); }
|
||||
int dy() const { return m_dy; }
|
||||
|
||||
|
||||
private:
|
||||
int m_y;
|
||||
int m_inc;
|
||||
int m_dy;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=================================================dda2_line_interpolator
|
||||
class dda2_line_interpolator
|
||||
{
|
||||
public:
|
||||
typedef int save_data_type;
|
||||
enum save_size_e { save_size = 2 };
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
dda2_line_interpolator() {}
|
||||
|
||||
//-------------------------------------------- Forward-adjusted line
|
||||
dda2_line_interpolator(int y1, int y2, int count) :
|
||||
m_cnt(count <= 0 ? 1 : count),
|
||||
m_lft((y2 - y1) / m_cnt),
|
||||
m_rem((y2 - y1) % m_cnt),
|
||||
m_mod(m_rem),
|
||||
m_y(y1)
|
||||
{
|
||||
if(m_mod <= 0)
|
||||
{
|
||||
m_mod += count;
|
||||
m_rem += count;
|
||||
m_lft--;
|
||||
}
|
||||
m_mod -= count;
|
||||
}
|
||||
|
||||
//-------------------------------------------- Backward-adjusted line
|
||||
dda2_line_interpolator(int y1, int y2, int count, int) :
|
||||
m_cnt(count <= 0 ? 1 : count),
|
||||
m_lft((y2 - y1) / m_cnt),
|
||||
m_rem((y2 - y1) % m_cnt),
|
||||
m_mod(m_rem),
|
||||
m_y(y1)
|
||||
{
|
||||
if(m_mod <= 0)
|
||||
{
|
||||
m_mod += count;
|
||||
m_rem += count;
|
||||
m_lft--;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------- Backward-adjusted line
|
||||
dda2_line_interpolator(int y, int count) :
|
||||
m_cnt(count <= 0 ? 1 : count),
|
||||
m_lft(y / m_cnt),
|
||||
m_rem(y % m_cnt),
|
||||
m_mod(m_rem),
|
||||
m_y(0)
|
||||
{
|
||||
if(m_mod <= 0)
|
||||
{
|
||||
m_mod += count;
|
||||
m_rem += count;
|
||||
m_lft--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void save(save_data_type* data) const
|
||||
{
|
||||
data[0] = m_mod;
|
||||
data[1] = m_y;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void load(const save_data_type* data)
|
||||
{
|
||||
m_mod = data[0];
|
||||
m_y = data[1];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator++()
|
||||
{
|
||||
m_mod += m_rem;
|
||||
m_y += m_lft;
|
||||
if(m_mod > 0)
|
||||
{
|
||||
m_mod -= m_cnt;
|
||||
m_y++;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator--()
|
||||
{
|
||||
if(m_mod <= m_rem)
|
||||
{
|
||||
m_mod += m_cnt;
|
||||
m_y--;
|
||||
}
|
||||
m_mod -= m_rem;
|
||||
m_y -= m_lft;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void adjust_forward()
|
||||
{
|
||||
m_mod -= m_cnt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void adjust_backward()
|
||||
{
|
||||
m_mod += m_cnt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int mod() const { return m_mod; }
|
||||
int rem() const { return m_rem; }
|
||||
int lft() const { return m_lft; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y; }
|
||||
|
||||
private:
|
||||
int m_cnt;
|
||||
int m_lft;
|
||||
int m_rem;
|
||||
int m_mod;
|
||||
int m_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------line_bresenham_interpolator
|
||||
class line_bresenham_interpolator
|
||||
{
|
||||
public:
|
||||
enum subpixel_scale_e
|
||||
{
|
||||
subpixel_shift = 8,
|
||||
subpixel_scale = 1 << subpixel_shift,
|
||||
subpixel_mask = subpixel_scale - 1
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static int line_lr(int v) { return v >> subpixel_shift; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
line_bresenham_interpolator(int x1, int y1, int x2, int y2) :
|
||||
m_x1_lr(line_lr(x1)),
|
||||
m_y1_lr(line_lr(y1)),
|
||||
m_x2_lr(line_lr(x2)),
|
||||
m_y2_lr(line_lr(y2)),
|
||||
m_ver(abs(m_x2_lr - m_x1_lr) < abs(m_y2_lr - m_y1_lr)),
|
||||
m_len(m_ver ? abs(m_y2_lr - m_y1_lr) :
|
||||
abs(m_x2_lr - m_x1_lr)),
|
||||
m_inc(m_ver ? ((y2 > y1) ? 1 : -1) : ((x2 > x1) ? 1 : -1)),
|
||||
m_interpolator(m_ver ? x1 : y1,
|
||||
m_ver ? x2 : y2,
|
||||
m_len)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool is_ver() const { return m_ver; }
|
||||
unsigned len() const { return m_len; }
|
||||
int inc() const { return m_inc; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void hstep()
|
||||
{
|
||||
++m_interpolator;
|
||||
m_x1_lr += m_inc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void vstep()
|
||||
{
|
||||
++m_interpolator;
|
||||
m_y1_lr += m_inc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int x1() const { return m_x1_lr; }
|
||||
int y1() const { return m_y1_lr; }
|
||||
int x2() const { return line_lr(m_interpolator.y()); }
|
||||
int y2() const { return line_lr(m_interpolator.y()); }
|
||||
int x2_hr() const { return m_interpolator.y(); }
|
||||
int y2_hr() const { return m_interpolator.y(); }
|
||||
|
||||
private:
|
||||
int m_x1_lr;
|
||||
int m_y1_lr;
|
||||
int m_x2_lr;
|
||||
int m_y2_lr;
|
||||
bool m_ver;
|
||||
unsigned m_len;
|
||||
int m_inc;
|
||||
dda2_line_interpolator m_interpolator;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_GAMMA_FUNCTIONS_INCLUDED
|
||||
#define AGG_GAMMA_FUNCTIONS_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//===============================================================gamma_none
|
||||
struct gamma_none
|
||||
{
|
||||
double operator()(double x) const { return x; }
|
||||
};
|
||||
|
||||
|
||||
//==============================================================gamma_power
|
||||
class gamma_power
|
||||
{
|
||||
public:
|
||||
gamma_power() : m_gamma(1.0) {}
|
||||
gamma_power(double g) : m_gamma(g) {}
|
||||
|
||||
void gamma(double g) { m_gamma = g; }
|
||||
double gamma() const { return m_gamma; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
return pow(x, m_gamma);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_gamma;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================gamma_threshold
|
||||
class gamma_threshold
|
||||
{
|
||||
public:
|
||||
gamma_threshold() : m_threshold(0.5) {}
|
||||
gamma_threshold(double t) : m_threshold(t) {}
|
||||
|
||||
void threshold(double t) { m_threshold = t; }
|
||||
double threshold() const { return m_threshold; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
return (x < m_threshold) ? 0.0 : 1.0;
|
||||
}
|
||||
|
||||
private:
|
||||
double m_threshold;
|
||||
};
|
||||
|
||||
|
||||
//============================================================gamma_linear
|
||||
class gamma_linear
|
||||
{
|
||||
public:
|
||||
gamma_linear() : m_start(0.0), m_end(1.0) {}
|
||||
gamma_linear(double s, double e) : m_start(s), m_end(e) {}
|
||||
|
||||
void set(double s, double e) { m_start = s; m_end = e; }
|
||||
void start(double s) { m_start = s; }
|
||||
void end(double e) { m_end = e; }
|
||||
double start() const { return m_start; }
|
||||
double end() const { return m_end; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
if(x < m_start) return 0.0;
|
||||
if(x > m_end) return 1.0;
|
||||
return (x - m_start) / (m_end - m_start);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_start;
|
||||
double m_end;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================gamma_multiply
|
||||
class gamma_multiply
|
||||
{
|
||||
public:
|
||||
gamma_multiply() : m_mul(1.0) {}
|
||||
gamma_multiply(double v) : m_mul(v) {}
|
||||
|
||||
void value(double v) { m_mul = v; }
|
||||
double value() const { return m_mul; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
double y = x * m_mul;
|
||||
if(y > 1.0) y = 1.0;
|
||||
return y;
|
||||
}
|
||||
|
||||
private:
|
||||
double m_mul;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
// Bessel function (besj) was adapted for use in AGG library by Andy Wilk
|
||||
// Contact: castor.vulgaris@gmail.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_MATH_INCLUDED
|
||||
#define AGG_MATH_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------vertex_dist_epsilon
|
||||
// Coinciding points maximal distance (Epsilon)
|
||||
const double vertex_dist_epsilon = 1e-14;
|
||||
|
||||
//-----------------------------------------------------intersection_epsilon
|
||||
// See calc_intersection
|
||||
const double intersection_epsilon = 1.0e-30;
|
||||
|
||||
//------------------------------------------------------------cross_product
|
||||
AGG_INLINE double cross_product(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
return (x - x2) * (y2 - y1) - (y - y2) * (x2 - x1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------point_in_triangle
|
||||
AGG_INLINE bool point_in_triangle(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x, double y)
|
||||
{
|
||||
bool cp1 = cross_product(x1, y1, x2, y2, x, y) < 0.0;
|
||||
bool cp2 = cross_product(x2, y2, x3, y3, x, y) < 0.0;
|
||||
bool cp3 = cross_product(x3, y3, x1, y1, x, y) < 0.0;
|
||||
return cp1 == cp2 && cp2 == cp3 && cp3 == cp1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------calc_distance
|
||||
AGG_INLINE double calc_distance(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
double dx = x2-x1;
|
||||
double dy = y2-y1;
|
||||
return sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------calc_sq_distance
|
||||
AGG_INLINE double calc_sq_distance(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
double dx = x2-x1;
|
||||
double dy = y2-y1;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
//------------------------------------------------calc_line_point_distance
|
||||
AGG_INLINE double calc_line_point_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
double dx = x2-x1;
|
||||
double dy = y2-y1;
|
||||
double d = sqrt(dx * dx + dy * dy);
|
||||
if(d < vertex_dist_epsilon)
|
||||
{
|
||||
return calc_distance(x1, y1, x, y);
|
||||
}
|
||||
return ((x - x2) * dy - (y - y2) * dx) / d;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------calc_line_point_u
|
||||
AGG_INLINE double calc_segment_point_u(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
|
||||
if(dx == 0 && dy == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double pdx = x - x1;
|
||||
double pdy = y - y1;
|
||||
|
||||
return (pdx * dx + pdy * dy) / (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
//---------------------------------------------calc_line_point_sq_distance
|
||||
AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y,
|
||||
double u)
|
||||
{
|
||||
if(u <= 0)
|
||||
{
|
||||
return calc_sq_distance(x, y, x1, y1);
|
||||
}
|
||||
else
|
||||
if(u >= 1)
|
||||
{
|
||||
return calc_sq_distance(x, y, x2, y2);
|
||||
}
|
||||
return calc_sq_distance(x, y, x1 + u * (x2 - x1), y1 + u * (y2 - y1));
|
||||
}
|
||||
|
||||
//---------------------------------------------calc_line_point_sq_distance
|
||||
AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
return
|
||||
calc_segment_point_sq_distance(
|
||||
x1, y1, x2, y2, x, y,
|
||||
calc_segment_point_u(x1, y1, x2, y2, x, y));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------calc_intersection
|
||||
AGG_INLINE bool calc_intersection(double ax, double ay, double bx, double by,
|
||||
double cx, double cy, double dx, double dy,
|
||||
double* x, double* y)
|
||||
{
|
||||
double num = (ay-cy) * (dx-cx) - (ax-cx) * (dy-cy);
|
||||
double den = (bx-ax) * (dy-cy) - (by-ay) * (dx-cx);
|
||||
if(fabs(den) < intersection_epsilon) return false;
|
||||
double r = num / den;
|
||||
*x = ax + r * (bx-ax);
|
||||
*y = ay + r * (by-ay);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------intersection_exists
|
||||
AGG_INLINE bool intersection_exists(double x1, double y1, double x2, double y2,
|
||||
double x3, double y3, double x4, double y4)
|
||||
{
|
||||
// It's less expensive but you can't control the
|
||||
// boundary conditions: Less or LessEqual
|
||||
double dx1 = x2 - x1;
|
||||
double dy1 = y2 - y1;
|
||||
double dx2 = x4 - x3;
|
||||
double dy2 = y4 - y3;
|
||||
return ((x3 - x2) * dy1 - (y3 - y2) * dx1 < 0.0) !=
|
||||
((x4 - x2) * dy1 - (y4 - y2) * dx1 < 0.0) &&
|
||||
((x1 - x4) * dy2 - (y1 - y4) * dx2 < 0.0) !=
|
||||
((x2 - x4) * dy2 - (y2 - y4) * dx2 < 0.0);
|
||||
|
||||
// It's is more expensive but more flexible
|
||||
// in terms of boundary conditions.
|
||||
//--------------------
|
||||
//double den = (x2-x1) * (y4-y3) - (y2-y1) * (x4-x3);
|
||||
//if(fabs(den) < intersection_epsilon) return false;
|
||||
//double nom1 = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3);
|
||||
//double nom2 = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3);
|
||||
//double ua = nom1 / den;
|
||||
//double ub = nom2 / den;
|
||||
//return ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------calc_orthogonal
|
||||
AGG_INLINE void calc_orthogonal(double thickness,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double* x, double* y)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double d = sqrt(dx*dx + dy*dy);
|
||||
*x = thickness * dy / d;
|
||||
*y = -thickness * dx / d;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------dilate_triangle
|
||||
AGG_INLINE void dilate_triangle(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double *x, double* y,
|
||||
double d)
|
||||
{
|
||||
double dx1=0.0;
|
||||
double dy1=0.0;
|
||||
double dx2=0.0;
|
||||
double dy2=0.0;
|
||||
double dx3=0.0;
|
||||
double dy3=0.0;
|
||||
double loc = cross_product(x1, y1, x2, y2, x3, y3);
|
||||
if(fabs(loc) > intersection_epsilon)
|
||||
{
|
||||
if(cross_product(x1, y1, x2, y2, x3, y3) > 0.0)
|
||||
{
|
||||
d = -d;
|
||||
}
|
||||
calc_orthogonal(d, x1, y1, x2, y2, &dx1, &dy1);
|
||||
calc_orthogonal(d, x2, y2, x3, y3, &dx2, &dy2);
|
||||
calc_orthogonal(d, x3, y3, x1, y1, &dx3, &dy3);
|
||||
}
|
||||
*x++ = x1 + dx1; *y++ = y1 + dy1;
|
||||
*x++ = x2 + dx1; *y++ = y2 + dy1;
|
||||
*x++ = x2 + dx2; *y++ = y2 + dy2;
|
||||
*x++ = x3 + dx2; *y++ = y3 + dy2;
|
||||
*x++ = x3 + dx3; *y++ = y3 + dy3;
|
||||
*x++ = x1 + dx3; *y++ = y1 + dy3;
|
||||
}
|
||||
|
||||
//------------------------------------------------------calc_triangle_area
|
||||
AGG_INLINE double calc_triangle_area(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
return (x1*y2 - x2*y1 + x2*y3 - x3*y2 + x3*y1 - x1*y3) * 0.5;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------calc_polygon_area
|
||||
template<class Storage> double calc_polygon_area(const Storage& st)
|
||||
{
|
||||
unsigned i;
|
||||
double sum = 0.0;
|
||||
double x = st[0].x;
|
||||
double y = st[0].y;
|
||||
double xs = x;
|
||||
double ys = y;
|
||||
|
||||
for(i = 1; i < st.size(); i++)
|
||||
{
|
||||
const typename Storage::value_type& v = st[i];
|
||||
sum += x * v.y - y * v.x;
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
}
|
||||
return (sum + x * ys - y * xs) * 0.5;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Tables for fast sqrt
|
||||
extern int16u g_sqrt_table[1024];
|
||||
extern int8 g_elder_bit_table[256];
|
||||
|
||||
|
||||
//---------------------------------------------------------------fast_sqrt
|
||||
//Fast integer Sqrt - really fast: no cycles, divisions or multiplications
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4035) //Disable warning "no return value"
|
||||
#endif
|
||||
AGG_INLINE unsigned fast_sqrt(unsigned val)
|
||||
{
|
||||
#if defined(_M_IX86) && defined(_MSC_VER) && !defined(AGG_NO_ASM)
|
||||
//For Ix86 family processors this assembler code is used.
|
||||
//The key command here is bsr - determination the number of the most
|
||||
//significant bit of the value. For other processors
|
||||
//(and maybe compilers) the pure C "#else" section is used.
|
||||
__asm
|
||||
{
|
||||
mov ebx, val
|
||||
mov edx, 11
|
||||
bsr ecx, ebx
|
||||
sub ecx, 9
|
||||
jle less_than_9_bits
|
||||
shr ecx, 1
|
||||
adc ecx, 0
|
||||
sub edx, ecx
|
||||
shl ecx, 1
|
||||
shr ebx, cl
|
||||
less_than_9_bits:
|
||||
xor eax, eax
|
||||
mov ax, g_sqrt_table[ebx*2]
|
||||
mov ecx, edx
|
||||
shr eax, cl
|
||||
}
|
||||
#else
|
||||
|
||||
//This code is actually pure C and portable to most
|
||||
//arcitectures including 64bit ones.
|
||||
unsigned t = val;
|
||||
int bit=0;
|
||||
unsigned shift = 11;
|
||||
|
||||
//The following piece of code is just an emulation of the
|
||||
//Ix86 assembler command "bsr" (see above). However on old
|
||||
//Intels (like Intel MMX 233MHz) this code is about twice
|
||||
//faster (sic!) then just one "bsr". On PIII and PIV the
|
||||
//bsr is optimized quite well.
|
||||
bit = t >> 24;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = (t >> 16) & 0xFF;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = (t >> 8) & 0xFF;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = g_elder_bit_table[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This code calculates the sqrt.
|
||||
bit -= 9;
|
||||
if(bit > 0)
|
||||
{
|
||||
bit = (bit >> 1) + (bit & 1);
|
||||
shift -= bit;
|
||||
val >>= (bit << 1);
|
||||
}
|
||||
return g_sqrt_table[val] >> shift;
|
||||
#endif
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------besj
|
||||
// Function BESJ calculates Bessel function of first kind of order n
|
||||
// Arguments:
|
||||
// n - an integer (>=0), the order
|
||||
// x - value at which the Bessel function is required
|
||||
//--------------------
|
||||
// C++ Mathematical Library
|
||||
// Convereted from equivalent FORTRAN library
|
||||
// Converetd by Gareth Walker for use by course 392 computational project
|
||||
// All functions tested and yield the same results as the corresponding
|
||||
// FORTRAN versions.
|
||||
//
|
||||
// If you have any problems using these functions please report them to
|
||||
// M.Muldoon@UMIST.ac.uk
|
||||
//
|
||||
// Documentation available on the web
|
||||
// http://www.ma.umist.ac.uk/mrm/Teaching/392/libs/392.html
|
||||
// Version 1.0 8/98
|
||||
// 29 October, 1999
|
||||
//--------------------
|
||||
// Adapted for use in AGG library by Andy Wilk (castor.vulgaris@gmail.com)
|
||||
//------------------------------------------------------------------------
|
||||
inline double besj(double x, int n)
|
||||
{
|
||||
if(n < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
double d = 1E-6;
|
||||
double b = 0;
|
||||
if(fabs(x) <= d)
|
||||
{
|
||||
if(n != 0) return 0;
|
||||
return 1;
|
||||
}
|
||||
double b1 = 0; // b1 is the value from the previous iteration
|
||||
// Set up a starting order for recurrence
|
||||
int m1 = (int)fabs(x) + 6;
|
||||
if(fabs(x) > 5)
|
||||
{
|
||||
m1 = (int)(fabs(1.4 * x + 60 / x));
|
||||
}
|
||||
int m2 = (int)(n + 2 + fabs(x) / 4);
|
||||
if (m1 > m2)
|
||||
{
|
||||
m2 = m1;
|
||||
}
|
||||
|
||||
// Apply recurrence down from curent max order
|
||||
for(;;)
|
||||
{
|
||||
double c3 = 0;
|
||||
double c2 = 1E-30;
|
||||
double c4 = 0;
|
||||
int m8 = 1;
|
||||
if (m2 / 2 * 2 == m2)
|
||||
{
|
||||
m8 = -1;
|
||||
}
|
||||
int imax = m2 - 2;
|
||||
for (int i = 1; i <= imax; i++)
|
||||
{
|
||||
double c6 = 2 * (m2 - i) * c2 / x - c3;
|
||||
c3 = c2;
|
||||
c2 = c6;
|
||||
if(m2 - i - 1 == n)
|
||||
{
|
||||
b = c6;
|
||||
}
|
||||
m8 = -1 * m8;
|
||||
if (m8 > 0)
|
||||
{
|
||||
c4 = c4 + 2 * c6;
|
||||
}
|
||||
}
|
||||
double c6 = 2 * c2 / x - c3;
|
||||
if(n == 0)
|
||||
{
|
||||
b = c6;
|
||||
}
|
||||
c4 += c6;
|
||||
b /= c4;
|
||||
if(fabs(b - b1) < d)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
b1 = b;
|
||||
m2 += 3;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,526 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Stroke math
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_STROKE_MATH_INCLUDED
|
||||
#define AGG_STROKE_MATH_INCLUDED
|
||||
|
||||
#include "agg_math.h"
|
||||
#include "agg_vertex_sequence.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//-------------------------------------------------------------line_cap_e
|
||||
enum line_cap_e
|
||||
{
|
||||
butt_cap,
|
||||
square_cap,
|
||||
round_cap
|
||||
};
|
||||
|
||||
//------------------------------------------------------------line_join_e
|
||||
enum line_join_e
|
||||
{
|
||||
miter_join = 0,
|
||||
miter_join_revert = 1,
|
||||
round_join = 2,
|
||||
bevel_join = 3,
|
||||
miter_join_round = 4
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------inner_join_e
|
||||
enum inner_join_e
|
||||
{
|
||||
inner_bevel,
|
||||
inner_miter,
|
||||
inner_jag,
|
||||
inner_round
|
||||
};
|
||||
|
||||
//------------------------------------------------------------math_stroke
|
||||
template<class VertexConsumer> class math_stroke
|
||||
{
|
||||
public:
|
||||
typedef typename VertexConsumer::value_type coord_type;
|
||||
|
||||
math_stroke();
|
||||
|
||||
void line_cap(line_cap_e lc) { m_line_cap = lc; }
|
||||
void line_join(line_join_e lj) { m_line_join = lj; }
|
||||
void inner_join(inner_join_e ij) { m_inner_join = ij; }
|
||||
|
||||
line_cap_e line_cap() const { return m_line_cap; }
|
||||
line_join_e line_join() const { return m_line_join; }
|
||||
inner_join_e inner_join() const { return m_inner_join; }
|
||||
|
||||
void width(double w);
|
||||
void miter_limit(double ml) { m_miter_limit = ml; }
|
||||
void miter_limit_theta(double t);
|
||||
void inner_miter_limit(double ml) { m_inner_miter_limit = ml; }
|
||||
void approximation_scale(double as) { m_approx_scale = as; }
|
||||
|
||||
double width() const { return m_width * 2.0; }
|
||||
double miter_limit() const { return m_miter_limit; }
|
||||
double inner_miter_limit() const { return m_inner_miter_limit; }
|
||||
double approximation_scale() const { return m_approx_scale; }
|
||||
|
||||
void calc_cap(VertexConsumer& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
double len);
|
||||
|
||||
void calc_join(VertexConsumer& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double len1,
|
||||
double len2);
|
||||
|
||||
private:
|
||||
AGG_INLINE void add_vertex(VertexConsumer& vc, double x, double y)
|
||||
{
|
||||
vc.add(coord_type(x, y));
|
||||
}
|
||||
|
||||
void calc_arc(VertexConsumer& vc,
|
||||
double x, double y,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2);
|
||||
|
||||
void calc_miter(VertexConsumer& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
line_join_e lj,
|
||||
double mlimit,
|
||||
double dbevel);
|
||||
|
||||
double m_width;
|
||||
double m_width_abs;
|
||||
double m_width_eps;
|
||||
int m_width_sign;
|
||||
double m_miter_limit;
|
||||
double m_inner_miter_limit;
|
||||
double m_approx_scale;
|
||||
line_cap_e m_line_cap;
|
||||
line_join_e m_line_join;
|
||||
inner_join_e m_inner_join;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC> math_stroke<VC>::math_stroke() :
|
||||
m_width(0.5),
|
||||
m_width_abs(0.5),
|
||||
m_width_eps(0.5/1024.0),
|
||||
m_width_sign(1),
|
||||
m_miter_limit(4.0),
|
||||
m_inner_miter_limit(1.01),
|
||||
m_approx_scale(1.0),
|
||||
m_line_cap(butt_cap),
|
||||
m_line_join(miter_join),
|
||||
m_inner_join(inner_miter)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC> void math_stroke<VC>::width(double w)
|
||||
{
|
||||
m_width = w * 0.5;
|
||||
if(m_width < 0)
|
||||
{
|
||||
m_width_abs = -m_width;
|
||||
m_width_sign = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_width_abs = m_width;
|
||||
m_width_sign = 1;
|
||||
}
|
||||
m_width_eps = m_width / 1024.0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC> void math_stroke<VC>::miter_limit_theta(double t)
|
||||
{
|
||||
m_miter_limit = 1.0 / sin(t * 0.5) ;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC>
|
||||
void math_stroke<VC>::calc_arc(VC& vc,
|
||||
double x, double y,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2)
|
||||
{
|
||||
double a1 = atan2(dy1 * m_width_sign, dx1 * m_width_sign);
|
||||
double a2 = atan2(dy2 * m_width_sign, dx2 * m_width_sign);
|
||||
double da = a1 - a2;
|
||||
int i, n;
|
||||
|
||||
da = acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2;
|
||||
|
||||
add_vertex(vc, x + dx1, y + dy1);
|
||||
if(m_width_sign > 0)
|
||||
{
|
||||
if(a1 > a2) a2 += 2 * pi;
|
||||
n = int((a2 - a1) / da);
|
||||
da = (a2 - a1) / (n + 1);
|
||||
a1 += da;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
add_vertex(vc, x + cos(a1) * m_width, y + sin(a1) * m_width);
|
||||
a1 += da;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(a1 < a2) a2 -= 2 * pi;
|
||||
n = int((a1 - a2) / da);
|
||||
da = (a1 - a2) / (n + 1);
|
||||
a1 -= da;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
add_vertex(vc, x + cos(a1) * m_width, y + sin(a1) * m_width);
|
||||
a1 -= da;
|
||||
}
|
||||
}
|
||||
add_vertex(vc, x + dx2, y + dy2);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC>
|
||||
void math_stroke<VC>::calc_miter(VC& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
line_join_e lj,
|
||||
double mlimit,
|
||||
double dbevel)
|
||||
{
|
||||
double xi = v1.x;
|
||||
double yi = v1.y;
|
||||
double di = 1;
|
||||
double lim = m_width_abs * mlimit;
|
||||
bool miter_limit_exceeded = true; // Assume the worst
|
||||
bool intersection_failed = true; // Assume the worst
|
||||
|
||||
if(calc_intersection(v0.x + dx1, v0.y - dy1,
|
||||
v1.x + dx1, v1.y - dy1,
|
||||
v1.x + dx2, v1.y - dy2,
|
||||
v2.x + dx2, v2.y - dy2,
|
||||
&xi, &yi))
|
||||
{
|
||||
// Calculation of the intersection succeeded
|
||||
//---------------------
|
||||
di = calc_distance(v1.x, v1.y, xi, yi);
|
||||
if(di <= lim)
|
||||
{
|
||||
// Inside the miter limit
|
||||
//---------------------
|
||||
add_vertex(vc, xi, yi);
|
||||
miter_limit_exceeded = false;
|
||||
}
|
||||
intersection_failed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculation of the intersection failed, most probably
|
||||
// the three points lie one straight line.
|
||||
// First check if v0 and v2 lie on the opposite sides of vector:
|
||||
// (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular
|
||||
// to the line determined by vertices v0 and v1.
|
||||
// This condition determines whether the next line segments continues
|
||||
// the previous one or goes back.
|
||||
//----------------
|
||||
double x2 = v1.x + dx1;
|
||||
double y2 = v1.y - dy1;
|
||||
if((cross_product(v0.x, v0.y, v1.x, v1.y, x2, y2) < 0.0) ==
|
||||
(cross_product(v1.x, v1.y, v2.x, v2.y, x2, y2) < 0.0))
|
||||
{
|
||||
// This case means that the next segment continues
|
||||
// the previous one (straight line)
|
||||
//-----------------
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
miter_limit_exceeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(miter_limit_exceeded)
|
||||
{
|
||||
// Miter limit exceeded
|
||||
//------------------------
|
||||
switch(lj)
|
||||
{
|
||||
case miter_join_revert:
|
||||
// For the compatibility with SVG, PDF, etc,
|
||||
// we use a simple bevel join instead of
|
||||
// "smart" bevel
|
||||
//-------------------
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
break;
|
||||
|
||||
case miter_join_round:
|
||||
calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
|
||||
break;
|
||||
|
||||
default:
|
||||
// If no miter-revert, calculate new dx1, dy1, dx2, dy2
|
||||
//----------------
|
||||
if(intersection_failed)
|
||||
{
|
||||
mlimit *= m_width_sign;
|
||||
add_vertex(vc, v1.x + dx1 + dy1 * mlimit,
|
||||
v1.y - dy1 + dx1 * mlimit);
|
||||
add_vertex(vc, v1.x + dx2 - dy2 * mlimit,
|
||||
v1.y - dy2 - dx2 * mlimit);
|
||||
}
|
||||
else
|
||||
{
|
||||
double x1 = v1.x + dx1;
|
||||
double y1 = v1.y - dy1;
|
||||
double x2 = v1.x + dx2;
|
||||
double y2 = v1.y - dy2;
|
||||
di = (lim - dbevel) / (di - dbevel);
|
||||
add_vertex(vc, x1 + (xi - x1) * di,
|
||||
y1 + (yi - y1) * di);
|
||||
add_vertex(vc, x2 + (xi - x2) * di,
|
||||
y2 + (yi - y2) * di);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------stroke_calc_cap
|
||||
template<class VC>
|
||||
void math_stroke<VC>::calc_cap(VC& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
double len)
|
||||
{
|
||||
vc.remove_all();
|
||||
|
||||
double dx1 = (v1.y - v0.y) / len;
|
||||
double dy1 = (v1.x - v0.x) / len;
|
||||
double dx2 = 0;
|
||||
double dy2 = 0;
|
||||
|
||||
dx1 *= m_width;
|
||||
dy1 *= m_width;
|
||||
|
||||
if(m_line_cap != round_cap)
|
||||
{
|
||||
if(m_line_cap == square_cap)
|
||||
{
|
||||
dx2 = dy1 * m_width_sign;
|
||||
dy2 = dx1 * m_width_sign;
|
||||
}
|
||||
add_vertex(vc, v0.x - dx1 - dx2, v0.y + dy1 - dy2);
|
||||
add_vertex(vc, v0.x + dx1 - dx2, v0.y - dy1 - dy2);
|
||||
}
|
||||
else
|
||||
{
|
||||
double da = acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2;
|
||||
double a1;
|
||||
int i;
|
||||
int n = int(pi / da);
|
||||
|
||||
da = pi / (n + 1);
|
||||
add_vertex(vc, v0.x - dx1, v0.y + dy1);
|
||||
if(m_width_sign > 0)
|
||||
{
|
||||
a1 = atan2(dy1, -dx1);
|
||||
a1 += da;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
add_vertex(vc, v0.x + cos(a1) * m_width,
|
||||
v0.y + sin(a1) * m_width);
|
||||
a1 += da;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
a1 = atan2(-dy1, dx1);
|
||||
a1 -= da;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
add_vertex(vc, v0.x + cos(a1) * m_width,
|
||||
v0.y + sin(a1) * m_width);
|
||||
a1 -= da;
|
||||
}
|
||||
}
|
||||
add_vertex(vc, v0.x + dx1, v0.y - dy1);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC>
|
||||
void math_stroke<VC>::calc_join(VC& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double len1,
|
||||
double len2)
|
||||
{
|
||||
double dx1 = m_width * (v1.y - v0.y) / len1;
|
||||
double dy1 = m_width * (v1.x - v0.x) / len1;
|
||||
double dx2 = m_width * (v2.y - v1.y) / len2;
|
||||
double dy2 = m_width * (v2.x - v1.x) / len2;
|
||||
|
||||
vc.remove_all();
|
||||
|
||||
double cp = cross_product(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);
|
||||
if(cp != 0 && (cp > 0) == (m_width > 0))
|
||||
{
|
||||
// Inner join
|
||||
//---------------
|
||||
double limit = ((len1 < len2) ? len1 : len2) / m_width_abs;
|
||||
if(limit < m_inner_miter_limit)
|
||||
{
|
||||
limit = m_inner_miter_limit;
|
||||
}
|
||||
|
||||
switch(m_inner_join)
|
||||
{
|
||||
default: // inner_bevel
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
break;
|
||||
|
||||
case inner_miter:
|
||||
calc_miter(vc,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
miter_join_revert,
|
||||
limit, 0);
|
||||
break;
|
||||
|
||||
case inner_jag:
|
||||
case inner_round:
|
||||
cp = (dx1-dx2) * (dx1-dx2) + (dy1-dy2) * (dy1-dy2);
|
||||
if(cp < len1 * len1 && cp < len2 * len2)
|
||||
{
|
||||
calc_miter(vc,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
miter_join_revert,
|
||||
limit, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_inner_join == inner_jag)
|
||||
{
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x, v1.y );
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x, v1.y );
|
||||
calc_arc(vc, v1.x, v1.y, dx2, -dy2, dx1, -dy1);
|
||||
add_vertex(vc, v1.x, v1.y );
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Outer join
|
||||
//---------------
|
||||
|
||||
// Calculate the distance between v1 and
|
||||
// the central point of the bevel line segment
|
||||
//---------------
|
||||
double dx = (dx1 + dx2) / 2;
|
||||
double dy = (dy1 + dy2) / 2;
|
||||
double dbevel = sqrt(dx * dx + dy * dy);
|
||||
|
||||
if(m_line_join == round_join || m_line_join == bevel_join)
|
||||
{
|
||||
// This is an optimization that reduces the number of points
|
||||
// in cases of almost collinear segments. If there's no
|
||||
// visible difference between bevel and miter joins we'd rather
|
||||
// use miter join because it adds only one point instead of two.
|
||||
//
|
||||
// Here we calculate the middle point between the bevel points
|
||||
// and then, the distance between v1 and this middle point.
|
||||
// At outer joins this distance always less than stroke width,
|
||||
// because it's actually the height of an isosceles triangle of
|
||||
// v1 and its two bevel points. If the difference between this
|
||||
// width and this value is small (no visible bevel) we can
|
||||
// add just one point.
|
||||
//
|
||||
// The constant in the expression makes the result approximately
|
||||
// the same as in round joins and caps. You can safely comment
|
||||
// out this entire "if".
|
||||
//-------------------
|
||||
if(m_approx_scale * (m_width_abs - dbevel) < m_width_eps)
|
||||
{
|
||||
if(calc_intersection(v0.x + dx1, v0.y - dy1,
|
||||
v1.x + dx1, v1.y - dy1,
|
||||
v1.x + dx2, v1.y - dy2,
|
||||
v2.x + dx2, v2.y - dy2,
|
||||
&dx, &dy))
|
||||
{
|
||||
add_vertex(vc, dx, dy);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch(m_line_join)
|
||||
{
|
||||
case miter_join:
|
||||
case miter_join_revert:
|
||||
case miter_join_round:
|
||||
calc_miter(vc,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
m_line_join,
|
||||
m_miter_limit,
|
||||
dbevel);
|
||||
break;
|
||||
|
||||
case round_join:
|
||||
calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
|
||||
break;
|
||||
|
||||
default: // Bevel join
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,755 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for 32-bit screen coordinates has been sponsored by
|
||||
// Liberty Technology Systems, Inc., visit http://lib-sys.com
|
||||
//
|
||||
// Liberty Technology Systems, Inc. is the provider of
|
||||
// PostScript and PDF technology for software developers.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED
|
||||
#define AGG_RASTERIZER_CELLS_AA_INCLUDED
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "agg_math.h"
|
||||
#include "agg_array.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-----------------------------------------------------rasterizer_cells_aa
|
||||
// An internal class that implements the main rasterization algorithm.
|
||||
// Used in the rasterizer. Should not be used direcly.
|
||||
template<class Cell> class rasterizer_cells_aa
|
||||
{
|
||||
enum cell_block_scale_e
|
||||
{
|
||||
cell_block_shift = 12,
|
||||
cell_block_size = 1 << cell_block_shift,
|
||||
cell_block_mask = cell_block_size - 1,
|
||||
cell_block_pool = 256,
|
||||
cell_block_limit = 1024
|
||||
};
|
||||
|
||||
struct sorted_y
|
||||
{
|
||||
unsigned start;
|
||||
unsigned num;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef Cell cell_type;
|
||||
typedef rasterizer_cells_aa<Cell> self_type;
|
||||
|
||||
~rasterizer_cells_aa();
|
||||
rasterizer_cells_aa();
|
||||
|
||||
void reset();
|
||||
void style(const cell_type& style_cell);
|
||||
void line(int x1, int y1, int x2, int y2);
|
||||
|
||||
int min_x() const { return m_min_x; }
|
||||
int min_y() const { return m_min_y; }
|
||||
int max_x() const { return m_max_x; }
|
||||
int max_y() const { return m_max_y; }
|
||||
|
||||
void sort_cells();
|
||||
|
||||
unsigned total_cells() const
|
||||
{
|
||||
return m_num_cells;
|
||||
}
|
||||
|
||||
unsigned scanline_num_cells(unsigned y) const
|
||||
{
|
||||
return m_sorted_y[y - m_min_y].num;
|
||||
}
|
||||
|
||||
const cell_type* const* scanline_cells(unsigned y) const
|
||||
{
|
||||
return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start;
|
||||
}
|
||||
|
||||
bool sorted() const { return m_sorted; }
|
||||
|
||||
private:
|
||||
rasterizer_cells_aa(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
void set_curr_cell(int x, int y);
|
||||
void add_curr_cell();
|
||||
void render_hline(int ey, int x1, int y1, int x2, int y2);
|
||||
void allocate_block();
|
||||
|
||||
private:
|
||||
unsigned m_num_blocks;
|
||||
unsigned m_max_blocks;
|
||||
unsigned m_curr_block;
|
||||
unsigned m_num_cells;
|
||||
cell_type** m_cells;
|
||||
cell_type* m_curr_cell_ptr;
|
||||
pod_vector<cell_type*> m_sorted_cells;
|
||||
pod_vector<sorted_y> m_sorted_y;
|
||||
cell_type m_curr_cell;
|
||||
cell_type m_style_cell;
|
||||
int m_min_x;
|
||||
int m_min_y;
|
||||
int m_max_x;
|
||||
int m_max_y;
|
||||
bool m_sorted;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
rasterizer_cells_aa<Cell>::~rasterizer_cells_aa()
|
||||
{
|
||||
if(m_num_blocks)
|
||||
{
|
||||
cell_type** ptr = m_cells + m_num_blocks - 1;
|
||||
while(m_num_blocks--)
|
||||
{
|
||||
pod_allocator<cell_type>::deallocate(*ptr, cell_block_size);
|
||||
ptr--;
|
||||
}
|
||||
pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
rasterizer_cells_aa<Cell>::rasterizer_cells_aa() :
|
||||
m_num_blocks(0),
|
||||
m_max_blocks(0),
|
||||
m_curr_block(0),
|
||||
m_num_cells(0),
|
||||
m_cells(0),
|
||||
m_curr_cell_ptr(0),
|
||||
m_sorted_cells(),
|
||||
m_sorted_y(),
|
||||
m_min_x(0x7FFFFFFF),
|
||||
m_min_y(0x7FFFFFFF),
|
||||
m_max_x(-0x7FFFFFFF),
|
||||
m_max_y(-0x7FFFFFFF),
|
||||
m_sorted(false)
|
||||
{
|
||||
m_style_cell.initial();
|
||||
m_curr_cell.initial();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void rasterizer_cells_aa<Cell>::reset()
|
||||
{
|
||||
m_num_cells = 0;
|
||||
m_curr_block = 0;
|
||||
m_curr_cell.initial();
|
||||
m_style_cell.initial();
|
||||
m_sorted = false;
|
||||
m_min_x = 0x7FFFFFFF;
|
||||
m_min_y = 0x7FFFFFFF;
|
||||
m_max_x = -0x7FFFFFFF;
|
||||
m_max_y = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
AGG_INLINE void rasterizer_cells_aa<Cell>::add_curr_cell()
|
||||
{
|
||||
if(m_curr_cell.area | m_curr_cell.cover)
|
||||
{
|
||||
if((m_num_cells & cell_block_mask) == 0)
|
||||
{
|
||||
if(m_num_blocks >= cell_block_limit) return;
|
||||
allocate_block();
|
||||
}
|
||||
*m_curr_cell_ptr++ = m_curr_cell;
|
||||
++m_num_cells;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
AGG_INLINE void rasterizer_cells_aa<Cell>::set_curr_cell(int x, int y)
|
||||
{
|
||||
if(m_curr_cell.not_equal(x, y, m_style_cell))
|
||||
{
|
||||
add_curr_cell();
|
||||
m_curr_cell.style(m_style_cell);
|
||||
m_curr_cell.x = x;
|
||||
m_curr_cell.y = y;
|
||||
m_curr_cell.cover = 0;
|
||||
m_curr_cell.area = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
AGG_INLINE void rasterizer_cells_aa<Cell>::render_hline(int ey,
|
||||
int x1, int y1,
|
||||
int x2, int y2)
|
||||
{
|
||||
int ex1 = x1 >> poly_subpixel_shift;
|
||||
int ex2 = x2 >> poly_subpixel_shift;
|
||||
int fx1 = x1 & poly_subpixel_mask;
|
||||
int fx2 = x2 & poly_subpixel_mask;
|
||||
|
||||
int delta, p, first, dx;
|
||||
int incr, lift, mod, rem;
|
||||
|
||||
//trivial case. Happens often
|
||||
if(y1 == y2)
|
||||
{
|
||||
set_curr_cell(ex2, ey);
|
||||
return;
|
||||
}
|
||||
|
||||
//everything is located in a single cell. That is easy!
|
||||
if(ex1 == ex2)
|
||||
{
|
||||
delta = y2 - y1;
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += (fx1 + fx2) * delta;
|
||||
return;
|
||||
}
|
||||
|
||||
//ok, we'll have to render a run of adjacent cells on the same
|
||||
//hline...
|
||||
p = (poly_subpixel_scale - fx1) * (y2 - y1);
|
||||
first = poly_subpixel_scale;
|
||||
incr = 1;
|
||||
|
||||
dx = x2 - x1;
|
||||
|
||||
if(dx < 0)
|
||||
{
|
||||
p = fx1 * (y2 - y1);
|
||||
first = 0;
|
||||
incr = -1;
|
||||
dx = -dx;
|
||||
}
|
||||
|
||||
delta = p / dx;
|
||||
mod = p % dx;
|
||||
|
||||
if(mod < 0)
|
||||
{
|
||||
delta--;
|
||||
mod += dx;
|
||||
}
|
||||
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += (fx1 + first) * delta;
|
||||
|
||||
ex1 += incr;
|
||||
set_curr_cell(ex1, ey);
|
||||
y1 += delta;
|
||||
|
||||
if(ex1 != ex2)
|
||||
{
|
||||
p = poly_subpixel_scale * (y2 - y1 + delta);
|
||||
lift = p / dx;
|
||||
rem = p % dx;
|
||||
|
||||
if (rem < 0)
|
||||
{
|
||||
lift--;
|
||||
rem += dx;
|
||||
}
|
||||
|
||||
mod -= dx;
|
||||
|
||||
while (ex1 != ex2)
|
||||
{
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0)
|
||||
{
|
||||
mod -= dx;
|
||||
delta++;
|
||||
}
|
||||
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += poly_subpixel_scale * delta;
|
||||
y1 += delta;
|
||||
ex1 += incr;
|
||||
set_curr_cell(ex1, ey);
|
||||
}
|
||||
}
|
||||
delta = y2 - y1;
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += (fx2 + poly_subpixel_scale - first) * delta;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
AGG_INLINE void rasterizer_cells_aa<Cell>::style(const cell_type& style_cell)
|
||||
{
|
||||
m_style_cell.style(style_cell);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void rasterizer_cells_aa<Cell>::line(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
enum dx_limit_e { dx_limit = 16384 << poly_subpixel_shift };
|
||||
|
||||
int dx = x2 - x1;
|
||||
|
||||
if(dx >= dx_limit || dx <= -dx_limit)
|
||||
{
|
||||
int cx = (x1 + x2) >> 1;
|
||||
int cy = (y1 + y2) >> 1;
|
||||
line(x1, y1, cx, cy);
|
||||
line(cx, cy, x2, y2);
|
||||
}
|
||||
|
||||
int dy = y2 - y1;
|
||||
int ex1 = x1 >> poly_subpixel_shift;
|
||||
int ex2 = x2 >> poly_subpixel_shift;
|
||||
int ey1 = y1 >> poly_subpixel_shift;
|
||||
int ey2 = y2 >> poly_subpixel_shift;
|
||||
int fy1 = y1 & poly_subpixel_mask;
|
||||
int fy2 = y2 & poly_subpixel_mask;
|
||||
|
||||
int x_from, x_to;
|
||||
int p, rem, mod, lift, delta, first, incr;
|
||||
|
||||
if(ex1 < m_min_x) m_min_x = ex1;
|
||||
if(ex1 > m_max_x) m_max_x = ex1;
|
||||
if(ey1 < m_min_y) m_min_y = ey1;
|
||||
if(ey1 > m_max_y) m_max_y = ey1;
|
||||
if(ex2 < m_min_x) m_min_x = ex2;
|
||||
if(ex2 > m_max_x) m_max_x = ex2;
|
||||
if(ey2 < m_min_y) m_min_y = ey2;
|
||||
if(ey2 > m_max_y) m_max_y = ey2;
|
||||
|
||||
set_curr_cell(ex1, ey1);
|
||||
|
||||
//everything is on a single hline
|
||||
if(ey1 == ey2)
|
||||
{
|
||||
render_hline(ey1, x1, fy1, x2, fy2);
|
||||
return;
|
||||
}
|
||||
|
||||
//Vertical line - we have to calculate start and end cells,
|
||||
//and then - the common values of the area and coverage for
|
||||
//all cells of the line. We know exactly there's only one
|
||||
//cell, so, we don't have to call render_hline().
|
||||
incr = 1;
|
||||
if(dx == 0)
|
||||
{
|
||||
int ex = x1 >> poly_subpixel_shift;
|
||||
int two_fx = (x1 - (ex << poly_subpixel_shift)) << 1;
|
||||
int area;
|
||||
|
||||
first = poly_subpixel_scale;
|
||||
if(dy < 0)
|
||||
{
|
||||
first = 0;
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
x_from = x1;
|
||||
|
||||
//render_hline(ey1, x_from, fy1, x_from, first);
|
||||
delta = first - fy1;
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += two_fx * delta;
|
||||
|
||||
ey1 += incr;
|
||||
set_curr_cell(ex, ey1);
|
||||
|
||||
delta = first + first - poly_subpixel_scale;
|
||||
area = two_fx * delta;
|
||||
while(ey1 != ey2)
|
||||
{
|
||||
//render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, first);
|
||||
m_curr_cell.cover = delta;
|
||||
m_curr_cell.area = area;
|
||||
ey1 += incr;
|
||||
set_curr_cell(ex, ey1);
|
||||
}
|
||||
//render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, fy2);
|
||||
delta = fy2 - poly_subpixel_scale + first;
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += two_fx * delta;
|
||||
return;
|
||||
}
|
||||
|
||||
//ok, we have to render several hlines
|
||||
p = (poly_subpixel_scale - fy1) * dx;
|
||||
first = poly_subpixel_scale;
|
||||
|
||||
if(dy < 0)
|
||||
{
|
||||
p = fy1 * dx;
|
||||
first = 0;
|
||||
incr = -1;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
delta = p / dy;
|
||||
mod = p % dy;
|
||||
|
||||
if(mod < 0)
|
||||
{
|
||||
delta--;
|
||||
mod += dy;
|
||||
}
|
||||
|
||||
x_from = x1 + delta;
|
||||
render_hline(ey1, x1, fy1, x_from, first);
|
||||
|
||||
ey1 += incr;
|
||||
set_curr_cell(x_from >> poly_subpixel_shift, ey1);
|
||||
|
||||
if(ey1 != ey2)
|
||||
{
|
||||
p = poly_subpixel_scale * dx;
|
||||
lift = p / dy;
|
||||
rem = p % dy;
|
||||
|
||||
if(rem < 0)
|
||||
{
|
||||
lift--;
|
||||
rem += dy;
|
||||
}
|
||||
mod -= dy;
|
||||
|
||||
while(ey1 != ey2)
|
||||
{
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if (mod >= 0)
|
||||
{
|
||||
mod -= dy;
|
||||
delta++;
|
||||
}
|
||||
|
||||
x_to = x_from + delta;
|
||||
render_hline(ey1, x_from, poly_subpixel_scale - first, x_to, first);
|
||||
x_from = x_to;
|
||||
|
||||
ey1 += incr;
|
||||
set_curr_cell(x_from >> poly_subpixel_shift, ey1);
|
||||
}
|
||||
}
|
||||
render_hline(ey1, x_from, poly_subpixel_scale - first, x2, fy2);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void rasterizer_cells_aa<Cell>::allocate_block()
|
||||
{
|
||||
if(m_curr_block >= m_num_blocks)
|
||||
{
|
||||
if(m_num_blocks >= m_max_blocks)
|
||||
{
|
||||
cell_type** new_cells =
|
||||
pod_allocator<cell_type*>::allocate(m_max_blocks +
|
||||
cell_block_pool);
|
||||
|
||||
if(m_cells)
|
||||
{
|
||||
memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_type*));
|
||||
pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
|
||||
}
|
||||
m_cells = new_cells;
|
||||
m_max_blocks += cell_block_pool;
|
||||
}
|
||||
|
||||
m_cells[m_num_blocks++] =
|
||||
pod_allocator<cell_type>::allocate(cell_block_size);
|
||||
|
||||
}
|
||||
m_curr_cell_ptr = m_cells[m_curr_block++];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <class T> static AGG_INLINE void swap_cells(T* a, T* b)
|
||||
{
|
||||
T temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum
|
||||
{
|
||||
qsort_threshold = 9
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void qsort_cells(Cell** start, unsigned num)
|
||||
{
|
||||
Cell** stack[80];
|
||||
Cell*** top;
|
||||
Cell** limit;
|
||||
Cell** base;
|
||||
|
||||
limit = start + num;
|
||||
base = start;
|
||||
top = stack;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int len = int(limit - base);
|
||||
|
||||
Cell** i;
|
||||
Cell** j;
|
||||
Cell** pivot;
|
||||
|
||||
if(len > qsort_threshold)
|
||||
{
|
||||
// we use base + len/2 as the pivot
|
||||
pivot = base + len / 2;
|
||||
swap_cells(base, pivot);
|
||||
|
||||
i = base + 1;
|
||||
j = limit - 1;
|
||||
|
||||
// now ensure that *i <= *base <= *j
|
||||
if((*j)->x < (*i)->x)
|
||||
{
|
||||
swap_cells(i, j);
|
||||
}
|
||||
|
||||
if((*base)->x < (*i)->x)
|
||||
{
|
||||
swap_cells(base, i);
|
||||
}
|
||||
|
||||
if((*j)->x < (*base)->x)
|
||||
{
|
||||
swap_cells(base, j);
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int x = (*base)->x;
|
||||
do i++; while( (*i)->x < x );
|
||||
do j--; while( x < (*j)->x );
|
||||
|
||||
if(i > j)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
swap_cells(i, j);
|
||||
}
|
||||
|
||||
swap_cells(base, j);
|
||||
|
||||
// now, push the largest sub-array
|
||||
if(j - base > limit - i)
|
||||
{
|
||||
top[0] = base;
|
||||
top[1] = j;
|
||||
base = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
top[0] = i;
|
||||
top[1] = limit;
|
||||
limit = j;
|
||||
}
|
||||
top += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the sub-array is small, perform insertion sort
|
||||
j = base;
|
||||
i = j + 1;
|
||||
|
||||
for(; i < limit; j = i, i++)
|
||||
{
|
||||
for(; j[1]->x < (*j)->x; j--)
|
||||
{
|
||||
swap_cells(j + 1, j);
|
||||
if (j == base)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(top > stack)
|
||||
{
|
||||
top -= 2;
|
||||
base = top[0];
|
||||
limit = top[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void rasterizer_cells_aa<Cell>::sort_cells()
|
||||
{
|
||||
PAINTER_TIMING("sort_cells");
|
||||
if(m_sorted) return; //Perform sort only the first time.
|
||||
|
||||
add_curr_cell();
|
||||
m_curr_cell.x = 0x7FFFFFFF;
|
||||
m_curr_cell.y = 0x7FFFFFFF;
|
||||
m_curr_cell.cover = 0;
|
||||
m_curr_cell.area = 0;
|
||||
|
||||
if(m_num_cells == 0) return;
|
||||
|
||||
// DBG: Check to see if min/max works well.
|
||||
//for(unsigned nc = 0; nc < m_num_cells; nc++)
|
||||
//{
|
||||
// cell_type* cell = m_cells[nc >> cell_block_shift] + (nc & cell_block_mask);
|
||||
// if(cell->x < m_min_x ||
|
||||
// cell->y < m_min_y ||
|
||||
// cell->x > m_max_x ||
|
||||
// cell->y > m_max_y)
|
||||
// {
|
||||
// cell = cell; // Breakpoint here
|
||||
// }
|
||||
//}
|
||||
// Allocate the array of cell pointers
|
||||
m_sorted_cells.allocate(m_num_cells, 16);
|
||||
|
||||
// Allocate and zero the Y array
|
||||
m_sorted_y.allocate(m_max_y - m_min_y + 1, 16);
|
||||
m_sorted_y.zero();
|
||||
|
||||
// Create the Y-histogram (count the numbers of cells for each Y)
|
||||
cell_type** block_ptr = m_cells;
|
||||
cell_type* cell_ptr;
|
||||
unsigned nb = m_num_cells >> cell_block_shift;
|
||||
unsigned i;
|
||||
while(nb--)
|
||||
{
|
||||
cell_ptr = *block_ptr++;
|
||||
i = cell_block_size;
|
||||
while(i--)
|
||||
{
|
||||
m_sorted_y[cell_ptr->y - m_min_y].start++;
|
||||
++cell_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
cell_ptr = *block_ptr++;
|
||||
i = m_num_cells & cell_block_mask;
|
||||
while(i--)
|
||||
{
|
||||
m_sorted_y[cell_ptr->y - m_min_y].start++;
|
||||
++cell_ptr;
|
||||
}
|
||||
|
||||
// Convert the Y-histogram into the array of starting indexes
|
||||
unsigned start = 0;
|
||||
for(i = 0; i < m_sorted_y.size(); i++)
|
||||
{
|
||||
unsigned v = m_sorted_y[i].start;
|
||||
m_sorted_y[i].start = start;
|
||||
start += v;
|
||||
}
|
||||
|
||||
// Fill the cell pointer array sorted by Y
|
||||
block_ptr = m_cells;
|
||||
nb = m_num_cells >> cell_block_shift;
|
||||
while(nb--)
|
||||
{
|
||||
cell_ptr = *block_ptr++;
|
||||
i = cell_block_size;
|
||||
while(i--)
|
||||
{
|
||||
sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y];
|
||||
m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr;
|
||||
++curr_y.num;
|
||||
++cell_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
cell_ptr = *block_ptr++;
|
||||
i = m_num_cells & cell_block_mask;
|
||||
while(i--)
|
||||
{
|
||||
sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y];
|
||||
m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr;
|
||||
++curr_y.num;
|
||||
++cell_ptr;
|
||||
}
|
||||
|
||||
// Finally arrange the X-arrays
|
||||
for(i = 0; i < m_sorted_y.size(); i++)
|
||||
{
|
||||
const sorted_y& curr_y = m_sorted_y[i];
|
||||
if(curr_y.num)
|
||||
{
|
||||
qsort_cells(m_sorted_cells.data() + curr_y.start, curr_y.num);
|
||||
}
|
||||
}
|
||||
m_sorted = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------scanline_hit_test
|
||||
class scanline_hit_test
|
||||
{
|
||||
public:
|
||||
scanline_hit_test(int x) : m_x(x), m_hit(false) {}
|
||||
|
||||
void reset_spans() {}
|
||||
void finalize(int) {}
|
||||
void add_cell(int x, int)
|
||||
{
|
||||
if(m_x == x) m_hit = true;
|
||||
}
|
||||
void add_span(int x, int len, int)
|
||||
{
|
||||
if(m_x >= x && m_x < x+len) m_hit = true;
|
||||
}
|
||||
unsigned num_spans() const { return 1; }
|
||||
bool hit() const { return m_hit; }
|
||||
|
||||
private:
|
||||
int m_x;
|
||||
bool m_hit;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,514 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for 32-bit screen coordinates has been sponsored by
|
||||
// Liberty Technology Systems, Inc., visit http://lib-sys.com
|
||||
//
|
||||
// Liberty Technology Systems, Inc. is the provider of
|
||||
// PostScript and PDF technology for software developers.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
|
||||
#define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
|
||||
|
||||
#include "agg_rasterizer_cells_aa.h"
|
||||
#include "agg_rasterizer_sl_clip.h"
|
||||
#include "agg_gamma_functions.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
|
||||
//-----------------------------------------------------------------cell_aa
|
||||
// A pixel cell. There're no constructors defined and it was done
|
||||
// intentionally in order to avoid extra overhead when allocating an
|
||||
// array of cells.
|
||||
struct cell_aa
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int cover;
|
||||
int area;
|
||||
|
||||
void initial()
|
||||
{
|
||||
x = 0x7FFFFFFF;
|
||||
y = 0x7FFFFFFF;
|
||||
cover = 0;
|
||||
area = 0;
|
||||
}
|
||||
|
||||
void style(const cell_aa&) {}
|
||||
|
||||
int not_equal(int ex, int ey, const cell_aa&) const
|
||||
{
|
||||
return (ex - x) | (ey - y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==================================================rasterizer_scanline_aa
|
||||
// Polygon rasterizer that is used to render filled polygons with
|
||||
// high-quality Anti-Aliasing. Internally, by default, the class uses
|
||||
// integer coordinates in format 24.8, i.e. 24 bits for integer part
|
||||
// and 8 bits for fractional - see poly_subpixel_shift. This class can be
|
||||
// used in the following way:
|
||||
//
|
||||
// 1. filling_rule(filling_rule_e ft) - optional.
|
||||
//
|
||||
// 2. gamma() - optional.
|
||||
//
|
||||
// 3. reset()
|
||||
//
|
||||
// 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create
|
||||
// more than one contour, but each contour must consist of at least 3
|
||||
// vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3);
|
||||
// is the absolute minimum of vertices that define a triangle.
|
||||
// The algorithm does not check either the number of vertices nor
|
||||
// coincidence of their coordinates, but in the worst case it just
|
||||
// won't draw anything.
|
||||
// The orger of the vertices (clockwise or counterclockwise)
|
||||
// is important when using the non-zero filling rule (fill_non_zero).
|
||||
// In this case the vertex order of all the contours must be the same
|
||||
// if you want your intersecting polygons to be without "holes".
|
||||
// You actually can use different vertices order. If the contours do not
|
||||
// intersect each other the order is not important anyway. If they do,
|
||||
// contours with the same vertex order will be rendered without "holes"
|
||||
// while the intersecting contours with different orders will have "holes".
|
||||
//
|
||||
// filling_rule() and gamma() can be called anytime before "sweeping".
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip=rasterizer_sl_clip_int> class rasterizer_scanline_aa
|
||||
{
|
||||
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() :
|
||||
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(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;
|
||||
double y;
|
||||
|
||||
unsigned cmd;
|
||||
vs.rewind(path_id);
|
||||
if(m_outline.sorted()) reset();
|
||||
while(!is_stop(cmd = vs.vertex(&x, &y)))
|
||||
{
|
||||
add_vertex(x, y, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int min_x() const { return m_outline.min_x(); }
|
||||
int min_y() const { return m_outline.min_y(); }
|
||||
int max_x() const { return m_outline.max_x(); }
|
||||
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)
|
||||
{
|
||||
PAINTER_TIMING("sweep_scanline");
|
||||
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;
|
||||
|
||||
while(num_cells)
|
||||
{
|
||||
const cell_aa* cur_cell = *cells;
|
||||
int x = cur_cell->x;
|
||||
int area = cur_cell->area;
|
||||
unsigned alpha;
|
||||
|
||||
cover += cur_cell->cover;
|
||||
|
||||
//accumulate all cells with the same X
|
||||
while(--num_cells)
|
||||
{
|
||||
cur_cell = *++cells;
|
||||
if(cur_cell->x != x) break;
|
||||
area += cur_cell->area;
|
||||
cover += cur_cell->cover;
|
||||
}
|
||||
|
||||
if(area)
|
||||
{
|
||||
alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area);
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_cell(x, alpha);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
if(num_cells && cur_cell->x > x)
|
||||
{
|
||||
alpha = calculate_alpha(cover << (poly_subpixel_shift + 1));
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_span(x, cur_cell->x - x, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(const rasterizer_scanline_aa<Clip>&);
|
||||
const rasterizer_scanline_aa<Clip>&
|
||||
operator = (const rasterizer_scanline_aa<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<Clip>::reset()
|
||||
{
|
||||
m_outline.reset();
|
||||
m_status = status_initial;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::filling_rule(filling_rule_e filling_rule)
|
||||
{
|
||||
m_filling_rule = filling_rule;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::clip_box(double x1, double y1,
|
||||
double x2, double y2)
|
||||
{
|
||||
reset();
|
||||
m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1),
|
||||
conv_type::upscale(x2), conv_type::upscale(y2));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::reset_clipping()
|
||||
{
|
||||
reset();
|
||||
m_clipper.reset_clipping();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<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<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<Clip>::line_to(int x, int y)
|
||||
{
|
||||
PAINTER_TIMING("line_to");
|
||||
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<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<Clip>::line_to_d(double x, double y)
|
||||
{
|
||||
PAINTER_TIMING("line_to_d");
|
||||
// extern int agg_line_counter;
|
||||
// agg_line_counter++;
|
||||
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<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<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<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<Clip>::sort()
|
||||
{
|
||||
if(m_auto_close) close_polygon();
|
||||
m_outline.sort_cells();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
AGG_INLINE bool rasterizer_scanline_aa<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<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<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
|
||||
|
||||
|
|
@ -1,351 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_RASTERIZER_SL_CLIP_INCLUDED
|
||||
#define AGG_RASTERIZER_SL_CLIP_INCLUDED
|
||||
|
||||
#include "agg_clip_liang_barsky.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//--------------------------------------------------------poly_max_coord_e
|
||||
enum poly_max_coord_e
|
||||
{
|
||||
poly_max_coord = (1 << 30) - 1 //----poly_max_coord
|
||||
};
|
||||
|
||||
//------------------------------------------------------------ras_conv_int
|
||||
struct ras_conv_int
|
||||
{
|
||||
typedef int coord_type;
|
||||
static AGG_INLINE int mul_div(double a, double b, double c)
|
||||
{
|
||||
return iround(a * b / c);
|
||||
}
|
||||
static int xi(int v) { return v; }
|
||||
static int yi(int v) { return v; }
|
||||
static int upscale(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static int downscale(int v) { return v; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------ras_conv_int_sat
|
||||
struct ras_conv_int_sat
|
||||
{
|
||||
typedef int coord_type;
|
||||
static AGG_INLINE int mul_div(double a, double b, double c)
|
||||
{
|
||||
return saturation<poly_max_coord>::iround(a * b / c);
|
||||
}
|
||||
static int xi(int v) { return v; }
|
||||
static int yi(int v) { return v; }
|
||||
static int upscale(double v)
|
||||
{
|
||||
return saturation<poly_max_coord>::iround(v * poly_subpixel_scale);
|
||||
}
|
||||
static int downscale(int v) { return v; }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------ras_conv_int_3x
|
||||
struct ras_conv_int_3x
|
||||
{
|
||||
typedef int coord_type;
|
||||
static AGG_INLINE int mul_div(double a, double b, double c)
|
||||
{
|
||||
return iround(a * b / c);
|
||||
}
|
||||
static int xi(int v) { return v * 3; }
|
||||
static int yi(int v) { return v; }
|
||||
static int upscale(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static int downscale(int v) { return v; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------ras_conv_dbl
|
||||
struct ras_conv_dbl
|
||||
{
|
||||
typedef double coord_type;
|
||||
static AGG_INLINE double mul_div(double a, double b, double c)
|
||||
{
|
||||
return a * b / c;
|
||||
}
|
||||
static int xi(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static int yi(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static double upscale(double v) { return v; }
|
||||
static double downscale(int v) { return v / double(poly_subpixel_scale); }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------ras_conv_dbl_3x
|
||||
struct ras_conv_dbl_3x
|
||||
{
|
||||
typedef double coord_type;
|
||||
static AGG_INLINE double mul_div(double a, double b, double c)
|
||||
{
|
||||
return a * b / c;
|
||||
}
|
||||
static int xi(double v) { return iround(v * poly_subpixel_scale * 3); }
|
||||
static int yi(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static double upscale(double v) { return v; }
|
||||
static double downscale(int v) { return v / double(poly_subpixel_scale); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------rasterizer_sl_clip
|
||||
template<class Conv> class rasterizer_sl_clip
|
||||
{
|
||||
public:
|
||||
typedef Conv conv_type;
|
||||
typedef typename Conv::coord_type coord_type;
|
||||
typedef rect_base<coord_type> rect_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rasterizer_sl_clip() :
|
||||
m_clip_box(0,0,0,0),
|
||||
m_x1(0),
|
||||
m_y1(0),
|
||||
m_f1(0),
|
||||
m_clipping(false)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_clipping()
|
||||
{
|
||||
m_clipping = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2)
|
||||
{
|
||||
m_clip_box = rect_type(x1, y1, x2, y2);
|
||||
m_clip_box.normalize();
|
||||
m_clipping = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void move_to(coord_type x1, coord_type y1)
|
||||
{
|
||||
m_x1 = x1;
|
||||
m_y1 = y1;
|
||||
if(m_clipping) m_f1 = clipping_flags(x1, y1, m_clip_box);
|
||||
}
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------------
|
||||
template<class Rasterizer>
|
||||
AGG_INLINE void line_clip_y(Rasterizer& ras,
|
||||
coord_type x1, coord_type y1,
|
||||
coord_type x2, coord_type y2,
|
||||
unsigned f1, unsigned f2) const
|
||||
{
|
||||
f1 &= 10;
|
||||
f2 &= 10;
|
||||
if((f1 | f2) == 0)
|
||||
{
|
||||
// Fully visible
|
||||
ras.line(Conv::xi(x1), Conv::yi(y1), Conv::xi(x2), Conv::yi(y2));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(f1 == f2)
|
||||
{
|
||||
// Invisible by Y
|
||||
return;
|
||||
}
|
||||
|
||||
coord_type tx1 = x1;
|
||||
coord_type ty1 = y1;
|
||||
coord_type tx2 = x2;
|
||||
coord_type ty2 = y2;
|
||||
|
||||
if(f1 & 8) // y1 < clip.y1
|
||||
{
|
||||
tx1 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1);
|
||||
ty1 = m_clip_box.y1;
|
||||
}
|
||||
|
||||
if(f1 & 2) // y1 > clip.y2
|
||||
{
|
||||
tx1 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1);
|
||||
ty1 = m_clip_box.y2;
|
||||
}
|
||||
|
||||
if(f2 & 8) // y2 < clip.y1
|
||||
{
|
||||
tx2 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1);
|
||||
ty2 = m_clip_box.y1;
|
||||
}
|
||||
|
||||
if(f2 & 2) // y2 > clip.y2
|
||||
{
|
||||
tx2 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1);
|
||||
ty2 = m_clip_box.y2;
|
||||
}
|
||||
ras.line(Conv::xi(tx1), Conv::yi(ty1),
|
||||
Conv::xi(tx2), Conv::yi(ty2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
template<class Rasterizer>
|
||||
void line_to(Rasterizer& ras, coord_type x2, coord_type y2)
|
||||
{
|
||||
if(m_clipping)
|
||||
{
|
||||
unsigned f2 = clipping_flags(x2, y2, m_clip_box);
|
||||
|
||||
if((m_f1 & 10) == (f2 & 10) && (m_f1 & 10) != 0)
|
||||
{
|
||||
// Invisible by Y
|
||||
m_x1 = x2;
|
||||
m_y1 = y2;
|
||||
m_f1 = f2;
|
||||
return;
|
||||
}
|
||||
|
||||
coord_type x1 = m_x1;
|
||||
coord_type y1 = m_y1;
|
||||
unsigned f1 = m_f1;
|
||||
coord_type y3, y4;
|
||||
unsigned f3, f4;
|
||||
|
||||
switch(((f1 & 5) << 1) | (f2 & 5))
|
||||
{
|
||||
case 0: // Visible by X
|
||||
line_clip_y(ras, x1, y1, x2, y2, f1, f2);
|
||||
break;
|
||||
|
||||
case 1: // x2 > clip.x2
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
line_clip_y(ras, x1, y1, m_clip_box.x2, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x2, y2, f3, f2);
|
||||
break;
|
||||
|
||||
case 2: // x1 > clip.x2
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x2, y3, x2, y2, f3, f2);
|
||||
break;
|
||||
|
||||
case 3: // x1 > clip.x2 && x2 > clip.x2
|
||||
line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y2, f1, f2);
|
||||
break;
|
||||
|
||||
case 4: // x2 < clip.x1
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
line_clip_y(ras, x1, y1, m_clip_box.x1, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x1, y2, f3, f2);
|
||||
break;
|
||||
|
||||
case 6: // x1 > clip.x2 && x2 < clip.x1
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
|
||||
y4 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
f4 = clipping_flags_y(y4, m_clip_box);
|
||||
line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x1, y4, f3, f4);
|
||||
line_clip_y(ras, m_clip_box.x1, y4, m_clip_box.x1, y2, f4, f2);
|
||||
break;
|
||||
|
||||
case 8: // x1 < clip.x1
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x1, y3, x2, y2, f3, f2);
|
||||
break;
|
||||
|
||||
case 9: // x1 < clip.x1 && x2 > clip.x2
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
|
||||
y4 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
f4 = clipping_flags_y(y4, m_clip_box);
|
||||
line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x2, y4, f3, f4);
|
||||
line_clip_y(ras, m_clip_box.x2, y4, m_clip_box.x2, y2, f4, f2);
|
||||
break;
|
||||
|
||||
case 12: // x1 < clip.x1 && x2 < clip.x1
|
||||
line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y2, f1, f2);
|
||||
break;
|
||||
}
|
||||
m_f1 = f2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ras.line(Conv::xi(m_x1), Conv::yi(m_y1),
|
||||
Conv::xi(x2), Conv::yi(y2));
|
||||
}
|
||||
m_x1 = x2;
|
||||
m_y1 = y2;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
rect_type m_clip_box;
|
||||
coord_type m_x1;
|
||||
coord_type m_y1;
|
||||
unsigned m_f1;
|
||||
bool m_clipping;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------rasterizer_sl_no_clip
|
||||
class rasterizer_sl_no_clip
|
||||
{
|
||||
public:
|
||||
typedef ras_conv_int conv_type;
|
||||
typedef int coord_type;
|
||||
|
||||
rasterizer_sl_no_clip() : m_x1(0), m_y1(0) {}
|
||||
|
||||
void reset_clipping() {}
|
||||
void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) {}
|
||||
void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; }
|
||||
|
||||
template<class Rasterizer>
|
||||
void line_to(Rasterizer& ras, coord_type x2, coord_type y2)
|
||||
{
|
||||
ras.line(m_x1, m_y1, x2, y2);
|
||||
m_x1 = x2;
|
||||
m_y1 = y2;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_x1, m_y1;
|
||||
};
|
||||
|
||||
|
||||
// -----rasterizer_sl_clip_int
|
||||
// -----rasterizer_sl_clip_int_sat
|
||||
// -----rasterizer_sl_clip_int_3x
|
||||
// -----rasterizer_sl_clip_dbl
|
||||
// -----rasterizer_sl_clip_dbl_3x
|
||||
//------------------------------------------------------------------------
|
||||
typedef rasterizer_sl_clip<ras_conv_int> rasterizer_sl_clip_int;
|
||||
typedef rasterizer_sl_clip<ras_conv_int_sat> rasterizer_sl_clip_int_sat;
|
||||
typedef rasterizer_sl_clip<ras_conv_int_3x> rasterizer_sl_clip_int_3x;
|
||||
typedef rasterizer_sl_clip<ras_conv_dbl> rasterizer_sl_clip_dbl;
|
||||
typedef rasterizer_sl_clip<ras_conv_dbl_3x> rasterizer_sl_clip_dbl_3x;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,718 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class renderer_base
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_RENDERER_BASE_INCLUDED
|
||||
#define AGG_RENDERER_BASE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------renderer_base
|
||||
template<class PixelFormat> class renderer_base
|
||||
{
|
||||
public:
|
||||
typedef PixelFormat pixfmt_type;
|
||||
typedef typename pixfmt_type::color_type color_type;
|
||||
typedef typename pixfmt_type::row_data row_data;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {}
|
||||
explicit renderer_base(pixfmt_type& ren) :
|
||||
m_ren(&ren),
|
||||
m_clip_box(0, 0, ren.width() - 1, ren.height() - 1)
|
||||
{}
|
||||
void attach(pixfmt_type& ren)
|
||||
{
|
||||
m_ren = &ren;
|
||||
m_clip_box = rect_i(0, 0, ren.width() - 1, ren.height() - 1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const pixfmt_type& ren() const { return *m_ren; }
|
||||
pixfmt_type& ren() { return *m_ren; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
unsigned width() const { return m_ren->width(); }
|
||||
unsigned height() const { return m_ren->height(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool clip_box(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
rect_i cb(x1, y1, x2, y2);
|
||||
cb.normalize();
|
||||
if(cb.clip(rect_i(0, 0, width() - 1, height() - 1)))
|
||||
{
|
||||
m_clip_box = cb;
|
||||
return true;
|
||||
}
|
||||
m_clip_box.x1 = 1;
|
||||
m_clip_box.y1 = 1;
|
||||
m_clip_box.x2 = 0;
|
||||
m_clip_box.y2 = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_clipping(bool visibility)
|
||||
{
|
||||
if(visibility)
|
||||
{
|
||||
m_clip_box.x1 = 0;
|
||||
m_clip_box.y1 = 0;
|
||||
m_clip_box.x2 = width() - 1;
|
||||
m_clip_box.y2 = height() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_clip_box.x1 = 1;
|
||||
m_clip_box.y1 = 1;
|
||||
m_clip_box.x2 = 0;
|
||||
m_clip_box.y2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clip_box_naked(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
m_clip_box.x1 = x1;
|
||||
m_clip_box.y1 = y1;
|
||||
m_clip_box.x2 = x2;
|
||||
m_clip_box.y2 = y2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool inbox(int x, int y) const
|
||||
{
|
||||
return x >= m_clip_box.x1 && y >= m_clip_box.y1 &&
|
||||
x <= m_clip_box.x2 && y <= m_clip_box.y2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rect_i& clip_box() const { return m_clip_box; }
|
||||
int xmin() const { return m_clip_box.x1; }
|
||||
int ymin() const { return m_clip_box.y1; }
|
||||
int xmax() const { return m_clip_box.x2; }
|
||||
int ymax() const { return m_clip_box.y2; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rect_i& bounding_clip_box() const { return m_clip_box; }
|
||||
int bounding_xmin() const { return m_clip_box.x1; }
|
||||
int bounding_ymin() const { return m_clip_box.y1; }
|
||||
int bounding_xmax() const { return m_clip_box.x2; }
|
||||
int bounding_ymax() const { return m_clip_box.y2; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear(const color_type& c)
|
||||
{
|
||||
unsigned y;
|
||||
if(width())
|
||||
{
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
m_ren->copy_hline(0, y, width(), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_pixel(int x, int y, const color_type& c)
|
||||
{
|
||||
if(inbox(x, y))
|
||||
{
|
||||
m_ren->copy_pixel(x, y, c);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_pixel(int x, int y, const color_type& c, cover_type cover)
|
||||
{
|
||||
if(inbox(x, y))
|
||||
{
|
||||
m_ren->blend_pixel(x, y, c, cover);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
color_type pixel(int x, int y) const
|
||||
{
|
||||
return inbox(x, y) ?
|
||||
m_ren->pixel(x, y) :
|
||||
color_type::no_color();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_hline(int x1, int y, int x2, const color_type& c)
|
||||
{
|
||||
if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
if(x1 > xmax()) return;
|
||||
if(x2 < xmin()) return;
|
||||
|
||||
if(x1 < xmin()) x1 = xmin();
|
||||
if(x2 > xmax()) x2 = xmax();
|
||||
|
||||
m_ren->copy_hline(x1, y, x2 - x1 + 1, c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_vline(int x, int y1, int y2, const color_type& c)
|
||||
{
|
||||
if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
if(y1 > ymax()) return;
|
||||
if(y2 < ymin()) return;
|
||||
|
||||
if(y1 < ymin()) y1 = ymin();
|
||||
if(y2 > ymax()) y2 = ymax();
|
||||
|
||||
m_ren->copy_vline(x, y1, y2 - y1 + 1, c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_hline(int x1, int y, int x2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
if(x1 > xmax()) return;
|
||||
if(x2 < xmin()) return;
|
||||
|
||||
if(x1 < xmin()) x1 = xmin();
|
||||
if(x2 > xmax()) x2 = xmax();
|
||||
|
||||
m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_vline(int x, int y1, int y2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
if(y1 > ymax()) return;
|
||||
if(y2 < ymin()) return;
|
||||
|
||||
if(y1 < ymin()) y1 = ymin();
|
||||
if(y2 > ymax()) y2 = ymax();
|
||||
|
||||
m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_bar(int x1, int y1, int x2, int y2, const color_type& c)
|
||||
{
|
||||
rect_i rc(x1, y1, x2, y2);
|
||||
rc.normalize();
|
||||
if(rc.clip(clip_box()))
|
||||
{
|
||||
int y;
|
||||
for(y = rc.y1; y <= rc.y2; y++)
|
||||
{
|
||||
m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_bar(int x1, int y1, int x2, int y2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
rect_i rc(x1, y1, x2, y2);
|
||||
rc.normalize();
|
||||
if(rc.clip(clip_box()))
|
||||
{
|
||||
int y;
|
||||
for(y = rc.y1; y <= rc.y2; y++)
|
||||
{
|
||||
m_ren->blend_hline(rc.x1,
|
||||
y,
|
||||
unsigned(rc.x2 - rc.x1 + 1),
|
||||
c,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_hspan(int x, int y, int len,
|
||||
const color_type& c,
|
||||
const cover_type* covers)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
len -= xmin() - x;
|
||||
if(len <= 0) return;
|
||||
covers += xmin() - x;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_solid_hspan(x, y, len, c, covers);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_vspan(int x, int y, int len,
|
||||
const color_type& c,
|
||||
const cover_type* covers)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
len -= ymin() - y;
|
||||
if(len <= 0) return;
|
||||
covers += ymin() - y;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_solid_vspan(x, y, len, c, covers);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_color_hspan(int x, int y, int len, const color_type* colors)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
int d = xmin() - x;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
colors += d;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->copy_color_hspan(x, y, len, colors);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_color_vspan(int x, int y, int len, const color_type* colors)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
int d = ymin() - y;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
colors += d;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->copy_color_vspan(x, y, len, colors);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_hspan(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
int d = xmin() - x;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
if(covers) covers += d;
|
||||
colors += d;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_color_hspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_vspan(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
int d = ymin() - y;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
if(covers) covers += d;
|
||||
colors += d;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_color_vspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const
|
||||
{
|
||||
rect_i rc(0,0,0,0);
|
||||
rect_i cb = clip_box();
|
||||
++cb.x2;
|
||||
++cb.y2;
|
||||
|
||||
if(src.x1 < 0)
|
||||
{
|
||||
dst.x1 -= src.x1;
|
||||
src.x1 = 0;
|
||||
}
|
||||
if(src.y1 < 0)
|
||||
{
|
||||
dst.y1 -= src.y1;
|
||||
src.y1 = 0;
|
||||
}
|
||||
|
||||
if(src.x2 > wsrc) src.x2 = wsrc;
|
||||
if(src.y2 > hsrc) src.y2 = hsrc;
|
||||
|
||||
if(dst.x1 < cb.x1)
|
||||
{
|
||||
src.x1 += cb.x1 - dst.x1;
|
||||
dst.x1 = cb.x1;
|
||||
}
|
||||
if(dst.y1 < cb.y1)
|
||||
{
|
||||
src.y1 += cb.y1 - dst.y1;
|
||||
dst.y1 = cb.y1;
|
||||
}
|
||||
|
||||
if(dst.x2 > cb.x2) dst.x2 = cb.x2;
|
||||
if(dst.y2 > cb.y2) dst.y2 = cb.y2;
|
||||
|
||||
rc.x2 = dst.x2 - dst.x1;
|
||||
rc.y2 = dst.y2 - dst.y1;
|
||||
|
||||
if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1;
|
||||
if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class RenBuf>
|
||||
void copy_from(const RenBuf& src,
|
||||
const rect_i* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0)
|
||||
{
|
||||
rect_i rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
|
||||
rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
m_ren->copy_from(src,
|
||||
rdst.x1, rdst.y1,
|
||||
rsrc.x1, rsrc.y1,
|
||||
rc.x2);
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from(const SrcPixelFormatRenderer& src,
|
||||
const rect_i* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
rect_i rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
|
||||
if(rw.ptr)
|
||||
{
|
||||
int x1src = rsrc.x1;
|
||||
int x1dst = rdst.x1;
|
||||
int len = rc.x2;
|
||||
if(rw.x1 > x1src)
|
||||
{
|
||||
x1dst += rw.x1 - x1src;
|
||||
len -= rw.x1 - x1src;
|
||||
x1src = rw.x1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x1src + len-1 > rw.x2)
|
||||
{
|
||||
len -= x1src + len - rw.x2 - 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_from(src,
|
||||
x1dst, rdst.y1,
|
||||
x1src, rsrc.y1,
|
||||
len,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from_color(const SrcPixelFormatRenderer& src,
|
||||
const color_type& color,
|
||||
const rect_i* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
rect_i rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
|
||||
if(rw.ptr)
|
||||
{
|
||||
int x1src = rsrc.x1;
|
||||
int x1dst = rdst.x1;
|
||||
int len = rc.x2;
|
||||
if(rw.x1 > x1src)
|
||||
{
|
||||
x1dst += rw.x1 - x1src;
|
||||
len -= rw.x1 - x1src;
|
||||
x1src = rw.x1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x1src + len-1 > rw.x2)
|
||||
{
|
||||
len -= x1src + len - rw.x2 - 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_from_color(src,
|
||||
color,
|
||||
x1dst, rdst.y1,
|
||||
x1src, rsrc.y1,
|
||||
len,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from_lut(const SrcPixelFormatRenderer& src,
|
||||
const color_type* color_lut,
|
||||
const rect_i* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
rect_i rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
|
||||
if(rw.ptr)
|
||||
{
|
||||
int x1src = rsrc.x1;
|
||||
int x1dst = rdst.x1;
|
||||
int len = rc.x2;
|
||||
if(rw.x1 > x1src)
|
||||
{
|
||||
x1dst += rw.x1 - x1src;
|
||||
len -= rw.x1 - x1src;
|
||||
x1src = rw.x1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x1src + len-1 > rw.x2)
|
||||
{
|
||||
len -= x1src + len - rw.x2 - 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_from_lut(src,
|
||||
color_lut,
|
||||
x1dst, rdst.y1,
|
||||
x1src, rsrc.y1,
|
||||
len,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
pixfmt_type* m_ren;
|
||||
rect_i m_clip_box;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,854 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_RENDERER_SCANLINE_INCLUDED
|
||||
#define AGG_RENDERER_SCANLINE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_renderer_base.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//================================================render_scanline_aa_solid
|
||||
template<class Scanline, class BaseRenderer, class ColorT>
|
||||
void render_scanline_aa_solid(const Scanline& sl,
|
||||
BaseRenderer& ren,
|
||||
const ColorT& color)
|
||||
{
|
||||
int y = sl.y();
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int x = span->x;
|
||||
if(span->len > 0)
|
||||
{
|
||||
ren.blend_solid_hspan(x, y, (unsigned)span->len,
|
||||
color,
|
||||
span->covers);
|
||||
}
|
||||
else
|
||||
{
|
||||
ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
|
||||
color,
|
||||
*(span->covers));
|
||||
}
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
|
||||
//===============================================render_scanlines_aa_solid
|
||||
template<class Rasterizer, class Scanline,
|
||||
class BaseRenderer, class ColorT>
|
||||
void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl,
|
||||
BaseRenderer& ren, const ColorT& color)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
// Explicitly convert "color" to the BaseRenderer color type.
|
||||
// For example, it can be called with color type "rgba", while
|
||||
// "rgba8" is needed. Otherwise it will be implicitly
|
||||
// converted in the loop many times.
|
||||
//----------------------
|
||||
typename BaseRenderer::color_type ren_color(color);
|
||||
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
//render_scanline_aa_solid(sl, ren, ren_color);
|
||||
|
||||
// This code is equivalent to the above call (copy/paste).
|
||||
// It's just a "manual" optimization for old compilers,
|
||||
// like Microsoft Visual C++ v6.0
|
||||
//-------------------------------
|
||||
int y = sl.y();
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int x = span->x;
|
||||
if(span->len > 0)
|
||||
{
|
||||
ren.blend_solid_hspan(x, y, (unsigned)span->len,
|
||||
ren_color,
|
||||
span->covers);
|
||||
}
|
||||
else
|
||||
{
|
||||
ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
|
||||
ren_color,
|
||||
*(span->covers));
|
||||
}
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================renderer_scanline_aa_solid
|
||||
template<class BaseRenderer> class renderer_scanline_aa_solid
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef typename base_ren_type::color_type color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_aa_solid() : m_ren(0) {}
|
||||
explicit renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {}
|
||||
void attach(base_ren_type& ren)
|
||||
{
|
||||
m_ren = &ren;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void color(const color_type& c) { m_color = c; }
|
||||
const color_type& color() const { return m_color; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
render_scanline_aa_solid(sl, *m_ren, m_color);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
color_type m_color;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//======================================================render_scanline_aa
|
||||
template<class Scanline, class BaseRenderer,
|
||||
class SpanAllocator, class SpanGenerator>
|
||||
void render_scanline_aa(const Scanline& sl, BaseRenderer& ren,
|
||||
SpanAllocator& alloc, SpanGenerator& span_gen)
|
||||
{
|
||||
PAINTER_TIMING("render_scanline_aa");
|
||||
int y = sl.y();
|
||||
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
for(;;)
|
||||
{
|
||||
int x = span->x;
|
||||
int len = span->len;
|
||||
const typename Scanline::cover_type* covers = span->covers;
|
||||
|
||||
if(len < 0) len = -len;
|
||||
typename BaseRenderer::color_type* colors = alloc.allocate(len);
|
||||
span_gen.generate(colors, x, y, len);
|
||||
ren.blend_color_hspan(x, y, len, colors,
|
||||
(span->len < 0) ? 0 : covers, *covers);
|
||||
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================render_scanlines_aa
|
||||
template<class Rasterizer, class Scanline, class BaseRenderer,
|
||||
class SpanAllocator, class SpanGenerator>
|
||||
void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
|
||||
SpanAllocator& alloc, SpanGenerator& span_gen)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
span_gen.prepare();
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
render_scanline_aa(sl, ren, alloc, span_gen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================renderer_scanline_aa
|
||||
template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
|
||||
class renderer_scanline_aa
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef SpanAllocator alloc_type;
|
||||
typedef SpanGenerator span_gen_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {}
|
||||
renderer_scanline_aa(base_ren_type& ren,
|
||||
alloc_type& alloc,
|
||||
span_gen_type& span_gen) :
|
||||
m_ren(&ren),
|
||||
m_alloc(&alloc),
|
||||
m_span_gen(&span_gen)
|
||||
{}
|
||||
void attach(base_ren_type& ren,
|
||||
alloc_type& alloc,
|
||||
span_gen_type& span_gen)
|
||||
{
|
||||
m_ren = &ren;
|
||||
m_alloc = &alloc;
|
||||
m_span_gen = &span_gen;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() { m_span_gen->prepare(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
render_scanline_aa(sl, *m_ren, *m_alloc, *m_span_gen);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
alloc_type* m_alloc;
|
||||
span_gen_type* m_span_gen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===============================================render_scanline_bin_solid
|
||||
template<class Scanline, class BaseRenderer, class ColorT>
|
||||
void render_scanline_bin_solid(const Scanline& sl,
|
||||
BaseRenderer& ren,
|
||||
const ColorT& color)
|
||||
{
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
for(;;)
|
||||
{
|
||||
ren.blend_hline(span->x,
|
||||
sl.y(),
|
||||
span->x - 1 + ((span->len < 0) ?
|
||||
-span->len :
|
||||
span->len),
|
||||
color,
|
||||
cover_full);
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================render_scanlines_bin_solid
|
||||
template<class Rasterizer, class Scanline,
|
||||
class BaseRenderer, class ColorT>
|
||||
void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl,
|
||||
BaseRenderer& ren, const ColorT& color)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
// Explicitly convert "color" to the BaseRenderer color type.
|
||||
// For example, it can be called with color type "rgba", while
|
||||
// "rgba8" is needed. Otherwise it will be implicitly
|
||||
// converted in the loop many times.
|
||||
//----------------------
|
||||
typename BaseRenderer::color_type ren_color(color);
|
||||
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
//render_scanline_bin_solid(sl, ren, ren_color);
|
||||
|
||||
// This code is equivalent to the above call (copy/paste).
|
||||
// It's just a "manual" optimization for old compilers,
|
||||
// like Microsoft Visual C++ v6.0
|
||||
//-------------------------------
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
for(;;)
|
||||
{
|
||||
ren.blend_hline(span->x,
|
||||
sl.y(),
|
||||
span->x - 1 + ((span->len < 0) ?
|
||||
-span->len :
|
||||
span->len),
|
||||
ren_color,
|
||||
cover_full);
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================renderer_scanline_bin_solid
|
||||
template<class BaseRenderer> class renderer_scanline_bin_solid
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef typename base_ren_type::color_type color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_bin_solid() : m_ren(0) {}
|
||||
explicit renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {}
|
||||
void attach(base_ren_type& ren)
|
||||
{
|
||||
m_ren = &ren;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void color(const color_type& c) { m_color = c; }
|
||||
const color_type& color() const { return m_color; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
render_scanline_bin_solid(sl, *m_ren, m_color);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
color_type m_color;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//======================================================render_scanline_bin
|
||||
template<class Scanline, class BaseRenderer,
|
||||
class SpanAllocator, class SpanGenerator>
|
||||
void render_scanline_bin(const Scanline& sl, BaseRenderer& ren,
|
||||
SpanAllocator& alloc, SpanGenerator& span_gen)
|
||||
{
|
||||
int y = sl.y();
|
||||
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
for(;;)
|
||||
{
|
||||
int x = span->x;
|
||||
int len = span->len;
|
||||
if(len < 0) len = -len;
|
||||
typename BaseRenderer::color_type* colors = alloc.allocate(len);
|
||||
span_gen.generate(colors, x, y, len);
|
||||
ren.blend_color_hspan(x, y, len, colors, 0, cover_full);
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================render_scanlines_bin
|
||||
template<class Rasterizer, class Scanline, class BaseRenderer,
|
||||
class SpanAllocator, class SpanGenerator>
|
||||
void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
|
||||
SpanAllocator& alloc, SpanGenerator& span_gen)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
span_gen.prepare();
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
render_scanline_bin(sl, ren, alloc, span_gen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================renderer_scanline_bin
|
||||
template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
|
||||
class renderer_scanline_bin
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef SpanAllocator alloc_type;
|
||||
typedef SpanGenerator span_gen_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {}
|
||||
renderer_scanline_bin(base_ren_type& ren,
|
||||
alloc_type& alloc,
|
||||
span_gen_type& span_gen) :
|
||||
m_ren(&ren),
|
||||
m_alloc(&alloc),
|
||||
m_span_gen(&span_gen)
|
||||
{}
|
||||
void attach(base_ren_type& ren,
|
||||
alloc_type& alloc,
|
||||
span_gen_type& span_gen)
|
||||
{
|
||||
m_ren = &ren;
|
||||
m_alloc = &alloc;
|
||||
m_span_gen = &span_gen;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() { m_span_gen->prepare(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
render_scanline_bin(sl, *m_ren, *m_alloc, *m_span_gen);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
alloc_type* m_alloc;
|
||||
span_gen_type* m_span_gen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//========================================================render_scanlines
|
||||
template<class Rasterizer, class Scanline, class Renderer>
|
||||
void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren)
|
||||
{
|
||||
PAINTER_TIMING("render_scanlines");
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
ren.prepare();
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
ren.render(sl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//========================================================render_all_paths
|
||||
template<class Rasterizer, class Scanline, class Renderer,
|
||||
class VertexSource, class ColorStorage, class PathId>
|
||||
void render_all_paths(Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
Renderer& r,
|
||||
VertexSource& vs,
|
||||
const ColorStorage& as,
|
||||
const PathId& path_id,
|
||||
unsigned num_paths)
|
||||
{
|
||||
for(unsigned i = 0; i < num_paths; i++)
|
||||
{
|
||||
ras.reset();
|
||||
ras.add_path(vs, path_id[i]);
|
||||
r.color(as[i]);
|
||||
render_scanlines(ras, sl, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=============================================render_scanlines_compound
|
||||
template<class Rasterizer,
|
||||
class ScanlineAA,
|
||||
class ScanlineBin,
|
||||
class BaseRenderer,
|
||||
class SpanAllocator,
|
||||
class StyleHandler>
|
||||
void render_scanlines_compound(Rasterizer& ras,
|
||||
ScanlineAA& sl_aa,
|
||||
ScanlineBin& sl_bin,
|
||||
BaseRenderer& ren,
|
||||
SpanAllocator& alloc,
|
||||
StyleHandler& sh)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
int min_x = ras.min_x();
|
||||
int len = ras.max_x() - min_x + 2;
|
||||
sl_aa.reset(min_x, ras.max_x());
|
||||
sl_bin.reset(min_x, ras.max_x());
|
||||
|
||||
typedef typename BaseRenderer::color_type color_type;
|
||||
color_type* color_span = alloc.allocate(len * 2);
|
||||
color_type* mix_buffer = color_span + len;
|
||||
unsigned num_spans;
|
||||
|
||||
unsigned num_styles;
|
||||
unsigned style;
|
||||
bool solid;
|
||||
while((num_styles = ras.sweep_styles()) > 0)
|
||||
{
|
||||
typename ScanlineAA::const_iterator span_aa;
|
||||
if(num_styles == 1)
|
||||
{
|
||||
// Optimization for a single style. Happens often
|
||||
//-------------------------
|
||||
if(ras.sweep_scanline(sl_aa, 0))
|
||||
{
|
||||
style = ras.style(0);
|
||||
if(sh.is_solid(style))
|
||||
{
|
||||
// Just solid fill
|
||||
//-----------------------
|
||||
render_scanline_aa_solid(sl_aa, ren, sh.color(style));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arbitrary span generator
|
||||
//-----------------------
|
||||
span_aa = sl_aa.begin();
|
||||
num_spans = sl_aa.num_spans();
|
||||
for(;;)
|
||||
{
|
||||
len = span_aa->len;
|
||||
sh.generate_span(color_span,
|
||||
span_aa->x,
|
||||
sl_aa.y(),
|
||||
len,
|
||||
style);
|
||||
|
||||
ren.blend_color_hspan(span_aa->x,
|
||||
sl_aa.y(),
|
||||
span_aa->len,
|
||||
color_span,
|
||||
span_aa->covers);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ras.sweep_scanline(sl_bin, -1))
|
||||
{
|
||||
// Clear the spans of the mix_buffer
|
||||
//--------------------
|
||||
typename ScanlineBin::const_iterator span_bin = sl_bin.begin();
|
||||
num_spans = sl_bin.num_spans();
|
||||
for(;;)
|
||||
{
|
||||
memset(mix_buffer + span_bin->x - min_x,
|
||||
0,
|
||||
span_bin->len * sizeof(color_type));
|
||||
|
||||
if(--num_spans == 0) break;
|
||||
++span_bin;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
for(i = 0; i < num_styles; i++)
|
||||
{
|
||||
style = ras.style(i);
|
||||
solid = sh.is_solid(style);
|
||||
|
||||
if(ras.sweep_scanline(sl_aa, i))
|
||||
{
|
||||
color_type* colors;
|
||||
color_type* cspan;
|
||||
typename ScanlineAA::cover_type* covers;
|
||||
span_aa = sl_aa.begin();
|
||||
num_spans = sl_aa.num_spans();
|
||||
if(solid)
|
||||
{
|
||||
// Just solid fill
|
||||
//-----------------------
|
||||
for(;;)
|
||||
{
|
||||
color_type c = sh.color(style);
|
||||
len = span_aa->len;
|
||||
colors = mix_buffer + span_aa->x - min_x;
|
||||
covers = span_aa->covers;
|
||||
do
|
||||
{
|
||||
if(*covers == cover_full)
|
||||
{
|
||||
*colors = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
colors->add(c, *covers);
|
||||
}
|
||||
++colors;
|
||||
++covers;
|
||||
}
|
||||
while(--len);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arbitrary span generator
|
||||
//-----------------------
|
||||
for(;;)
|
||||
{
|
||||
len = span_aa->len;
|
||||
colors = mix_buffer + span_aa->x - min_x;
|
||||
cspan = color_span;
|
||||
sh.generate_span(cspan,
|
||||
span_aa->x,
|
||||
sl_aa.y(),
|
||||
len,
|
||||
style);
|
||||
covers = span_aa->covers;
|
||||
do
|
||||
{
|
||||
if(*covers == cover_full)
|
||||
{
|
||||
*colors = *cspan;
|
||||
}
|
||||
else
|
||||
{
|
||||
colors->add(*cspan, *covers);
|
||||
}
|
||||
++cspan;
|
||||
++colors;
|
||||
++covers;
|
||||
}
|
||||
while(--len);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the blended result as a color hspan
|
||||
//-------------------------
|
||||
span_bin = sl_bin.begin();
|
||||
num_spans = sl_bin.num_spans();
|
||||
for(;;)
|
||||
{
|
||||
ren.blend_color_hspan(span_bin->x,
|
||||
sl_bin.y(),
|
||||
span_bin->len,
|
||||
mix_buffer + span_bin->x - min_x,
|
||||
0,
|
||||
cover_full);
|
||||
if(--num_spans == 0) break;
|
||||
++span_bin;
|
||||
}
|
||||
} // if(ras.sweep_scanline(sl_bin, -1))
|
||||
} // if(num_styles == 1) ... else
|
||||
} // while((num_styles = ras.sweep_styles()) > 0)
|
||||
} // if(ras.rewind_scanlines())
|
||||
}
|
||||
|
||||
//=======================================render_scanlines_compound_layered
|
||||
template<class Rasterizer,
|
||||
class ScanlineAA,
|
||||
class BaseRenderer,
|
||||
class SpanAllocator,
|
||||
class StyleHandler>
|
||||
void render_scanlines_compound_layered(Rasterizer& ras,
|
||||
ScanlineAA& sl_aa,
|
||||
BaseRenderer& ren,
|
||||
SpanAllocator& alloc,
|
||||
StyleHandler& sh)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
int min_x = ras.min_x();
|
||||
int len = ras.max_x() - min_x + 2;
|
||||
sl_aa.reset(min_x, ras.max_x());
|
||||
|
||||
typedef typename BaseRenderer::color_type color_type;
|
||||
color_type* color_span = alloc.allocate(len * 2);
|
||||
color_type* mix_buffer = color_span + len;
|
||||
cover_type* cover_buffer = ras.allocate_cover_buffer(len);
|
||||
unsigned num_spans;
|
||||
|
||||
unsigned num_styles;
|
||||
unsigned style;
|
||||
bool solid;
|
||||
while((num_styles = ras.sweep_styles()) > 0)
|
||||
{
|
||||
typename ScanlineAA::const_iterator span_aa;
|
||||
if(num_styles == 1)
|
||||
{
|
||||
// Optimization for a single style. Happens often
|
||||
//-------------------------
|
||||
if(ras.sweep_scanline(sl_aa, 0))
|
||||
{
|
||||
style = ras.style(0);
|
||||
if(sh.is_solid(style))
|
||||
{
|
||||
// Just solid fill
|
||||
//-----------------------
|
||||
render_scanline_aa_solid(sl_aa, ren, sh.color(style));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arbitrary span generator
|
||||
//-----------------------
|
||||
span_aa = sl_aa.begin();
|
||||
num_spans = sl_aa.num_spans();
|
||||
for(;;)
|
||||
{
|
||||
len = span_aa->len;
|
||||
sh.generate_span(color_span,
|
||||
span_aa->x,
|
||||
sl_aa.y(),
|
||||
len,
|
||||
style);
|
||||
|
||||
ren.blend_color_hspan(span_aa->x,
|
||||
sl_aa.y(),
|
||||
span_aa->len,
|
||||
color_span,
|
||||
span_aa->covers);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int sl_start = ras.scanline_start();
|
||||
unsigned sl_len = ras.scanline_length();
|
||||
|
||||
if(sl_len)
|
||||
{
|
||||
memset(mix_buffer + sl_start - min_x,
|
||||
0,
|
||||
sl_len * sizeof(color_type));
|
||||
|
||||
memset(cover_buffer + sl_start - min_x,
|
||||
0,
|
||||
sl_len * sizeof(cover_type));
|
||||
|
||||
int sl_y = 0x7FFFFFFF;
|
||||
unsigned i;
|
||||
for(i = 0; i < num_styles; i++)
|
||||
{
|
||||
style = ras.style(i);
|
||||
solid = sh.is_solid(style);
|
||||
|
||||
if(ras.sweep_scanline(sl_aa, i))
|
||||
{
|
||||
unsigned cover;
|
||||
color_type* colors;
|
||||
color_type* cspan;
|
||||
cover_type* src_covers;
|
||||
cover_type* dst_covers;
|
||||
span_aa = sl_aa.begin();
|
||||
num_spans = sl_aa.num_spans();
|
||||
sl_y = sl_aa.y();
|
||||
if(solid)
|
||||
{
|
||||
// Just solid fill
|
||||
//-----------------------
|
||||
for(;;)
|
||||
{
|
||||
color_type c = sh.color(style);
|
||||
len = span_aa->len;
|
||||
colors = mix_buffer + span_aa->x - min_x;
|
||||
src_covers = span_aa->covers;
|
||||
dst_covers = cover_buffer + span_aa->x - min_x;
|
||||
do
|
||||
{
|
||||
cover = *src_covers;
|
||||
if(*dst_covers + cover > cover_full)
|
||||
{
|
||||
cover = cover_full - *dst_covers;
|
||||
}
|
||||
if(cover)
|
||||
{
|
||||
colors->add(c, cover);
|
||||
*dst_covers += cover;
|
||||
}
|
||||
++colors;
|
||||
++src_covers;
|
||||
++dst_covers;
|
||||
}
|
||||
while(--len);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arbitrary span generator
|
||||
//-----------------------
|
||||
for(;;)
|
||||
{
|
||||
len = span_aa->len;
|
||||
colors = mix_buffer + span_aa->x - min_x;
|
||||
cspan = color_span;
|
||||
sh.generate_span(cspan,
|
||||
span_aa->x,
|
||||
sl_aa.y(),
|
||||
len,
|
||||
style);
|
||||
src_covers = span_aa->covers;
|
||||
dst_covers = cover_buffer + span_aa->x - min_x;
|
||||
do
|
||||
{
|
||||
cover = *src_covers;
|
||||
if(*dst_covers + cover > cover_full)
|
||||
{
|
||||
cover = cover_full - *dst_covers;
|
||||
}
|
||||
if(cover)
|
||||
{
|
||||
colors->add(*cspan, cover);
|
||||
*dst_covers += cover;
|
||||
}
|
||||
++cspan;
|
||||
++colors;
|
||||
++src_covers;
|
||||
++dst_covers;
|
||||
}
|
||||
while(--len);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ren.blend_color_hspan(sl_start,
|
||||
sl_y,
|
||||
sl_len,
|
||||
mix_buffer + sl_start - min_x,
|
||||
0,
|
||||
cover_full);
|
||||
} //if(sl_len)
|
||||
} //if(num_styles == 1) ... else
|
||||
} //while((num_styles = ras.sweep_styles()) > 0)
|
||||
} //if(ras.rewind_scanlines())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,300 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class rendering_buffer
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_RENDERING_BUFFER_INCLUDED
|
||||
#define AGG_RENDERING_BUFFER_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//===========================================================row_accessor
|
||||
template<class T> class row_accessor
|
||||
{
|
||||
public:
|
||||
typedef const_row_info<T> row_data;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
row_accessor() :
|
||||
m_buf(0),
|
||||
m_start(0),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
row_accessor(T* buf, unsigned width, unsigned height, int stride) :
|
||||
m_buf(0),
|
||||
m_start(0),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0)
|
||||
{
|
||||
attach(buf, width, height, stride);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void attach(T* buf, unsigned width, unsigned height, int stride)
|
||||
{
|
||||
m_buf = m_start = buf;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_stride = stride;
|
||||
if(stride < 0)
|
||||
{
|
||||
m_start = m_buf - int(height - 1) * stride;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE T* buf() { return m_buf; }
|
||||
AGG_INLINE const T* buf() const { return m_buf; }
|
||||
AGG_INLINE unsigned width() const { return m_width; }
|
||||
AGG_INLINE unsigned height() const { return m_height; }
|
||||
AGG_INLINE int stride() const { return m_stride; }
|
||||
AGG_INLINE unsigned stride_abs() const
|
||||
{
|
||||
return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE T* row_ptr(int, int y, unsigned)
|
||||
{
|
||||
return m_start + y * m_stride;
|
||||
}
|
||||
AGG_INLINE T* row_ptr(int y) { return m_start + y * m_stride; }
|
||||
AGG_INLINE const T* row_ptr(int y) const { return m_start + y * m_stride; }
|
||||
AGG_INLINE row_data row (int y) const
|
||||
{
|
||||
return row_data(0, m_width-1, row_ptr(y));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class RenBuf>
|
||||
void copy_from(const RenBuf& src)
|
||||
{
|
||||
unsigned h = height();
|
||||
if(src.height() < h) h = src.height();
|
||||
|
||||
unsigned l = stride_abs();
|
||||
if(src.stride_abs() < l) l = src.stride_abs();
|
||||
|
||||
l *= sizeof(T);
|
||||
|
||||
unsigned y;
|
||||
unsigned w = width();
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(row_ptr(0, y, w), src.row_ptr(y), l);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear(T value)
|
||||
{
|
||||
unsigned y;
|
||||
unsigned w = width();
|
||||
unsigned stride = stride_abs();
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
T* p = row_ptr(0, y, w);
|
||||
unsigned x;
|
||||
for(x = 0; x < stride; x++)
|
||||
{
|
||||
*p++ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
T* m_buf; // Pointer to renrdering buffer
|
||||
T* m_start; // Pointer to first pixel depending on stride
|
||||
unsigned m_width; // Width in pixels
|
||||
unsigned m_height; // Height in pixels
|
||||
int m_stride; // Number of bytes per row. Can be < 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================row_ptr_cache
|
||||
template<class T> class row_ptr_cache
|
||||
{
|
||||
public:
|
||||
typedef const_row_info<T> row_data;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
row_ptr_cache() :
|
||||
m_buf(0),
|
||||
m_rows(),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
row_ptr_cache(T* buf, unsigned width, unsigned height, int stride) :
|
||||
m_buf(0),
|
||||
m_rows(),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0)
|
||||
{
|
||||
attach(buf, width, height, stride);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void attach(T* buf, unsigned width, unsigned height, int stride)
|
||||
{
|
||||
m_buf = buf;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_stride = stride;
|
||||
if(height > m_rows.size())
|
||||
{
|
||||
m_rows.resize(height);
|
||||
}
|
||||
|
||||
T* row_ptr = m_buf;
|
||||
|
||||
if(stride < 0)
|
||||
{
|
||||
row_ptr = m_buf - int(height - 1) * stride;
|
||||
}
|
||||
|
||||
T** rows = &m_rows[0];
|
||||
|
||||
while(height--)
|
||||
{
|
||||
*rows++ = row_ptr;
|
||||
row_ptr += stride;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE T* buf() { return m_buf; }
|
||||
AGG_INLINE const T* buf() const { return m_buf; }
|
||||
AGG_INLINE unsigned width() const { return m_width; }
|
||||
AGG_INLINE unsigned height() const { return m_height; }
|
||||
AGG_INLINE int stride() const { return m_stride; }
|
||||
AGG_INLINE unsigned stride_abs() const
|
||||
{
|
||||
return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE T* row_ptr(int, int y, unsigned)
|
||||
{
|
||||
return m_rows[y];
|
||||
}
|
||||
AGG_INLINE T* row_ptr(int y) { return m_rows[y]; }
|
||||
AGG_INLINE const T* row_ptr(int y) const { return m_rows[y]; }
|
||||
AGG_INLINE row_data row (int y) const
|
||||
{
|
||||
return row_data(0, m_width-1, m_rows[y]);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
T const* const* rows() const { return &m_rows[0]; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class RenBuf>
|
||||
void copy_from(const RenBuf& src)
|
||||
{
|
||||
unsigned h = height();
|
||||
if(src.height() < h) h = src.height();
|
||||
|
||||
unsigned l = stride_abs();
|
||||
if(src.stride_abs() < l) l = src.stride_abs();
|
||||
|
||||
l *= sizeof(T);
|
||||
|
||||
unsigned y;
|
||||
unsigned w = width();
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(row_ptr(0, y, w), src.row_ptr(y), l);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear(T value)
|
||||
{
|
||||
unsigned y;
|
||||
unsigned w = width();
|
||||
unsigned stride = stride_abs();
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
T* p = row_ptr(0, y, w);
|
||||
unsigned x;
|
||||
for(x = 0; x < stride; x++)
|
||||
{
|
||||
*p++ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
T* m_buf; // Pointer to renrdering buffer
|
||||
pod_array<T*> m_rows; // Pointers to each row of the buffer
|
||||
unsigned m_width; // Width in pixels
|
||||
unsigned m_height; // Height in pixels
|
||||
int m_stride; // Number of bytes per row. Can be < 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//========================================================rendering_buffer
|
||||
//
|
||||
// The definition of the main type for accessing the rows in the frame
|
||||
// buffer. It provides functionality to navigate to the rows in a
|
||||
// rectangular matrix, from top to bottom or from bottom to top depending
|
||||
// on stride.
|
||||
//
|
||||
// row_accessor is cheap to create/destroy, but performs one multiplication
|
||||
// when calling row_ptr().
|
||||
//
|
||||
// row_ptr_cache creates an array of pointers to rows, so, the access
|
||||
// via row_ptr() may be faster. But it requires memory allocation
|
||||
// when creating. For example, on typical Intel Pentium hardware
|
||||
// row_ptr_cache speeds span_image_filter_rgb_nn up to 10%
|
||||
//
|
||||
// It's used only in short hand typedefs like pixfmt_rgba32 and can be
|
||||
// redefined in agg_config.h
|
||||
// In real applications you can use both, depending on your needs
|
||||
//------------------------------------------------------------------------
|
||||
#ifdef AGG_RENDERING_BUFFER
|
||||
typedef AGG_RENDERING_BUFFER rendering_buffer;
|
||||
#else
|
||||
// typedef row_ptr_cache<int8u> rendering_buffer;
|
||||
typedef row_accessor<int8u> rendering_buffer;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,329 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Class scanline_p - a general purpose scanline container with packed spans.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for 32-bit screen coordinates (scanline32_p) has been sponsored by
|
||||
// Liberty Technology Systems, Inc., visit http://lib-sys.com
|
||||
//
|
||||
// Liberty Technology Systems, Inc. is the provider of
|
||||
// PostScript and PDF technology for software developers.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_SCANLINE_P_INCLUDED
|
||||
#define AGG_SCANLINE_P_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//=============================================================scanline_p8
|
||||
//
|
||||
// This is a general purpose scaline container which supports the interface
|
||||
// used in the rasterizer::render(). See description of scanline_u8
|
||||
// for details.
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
class scanline_p8
|
||||
{
|
||||
public:
|
||||
typedef scanline_p8 self_type;
|
||||
typedef int8u cover_type;
|
||||
typedef int16 coord_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
struct span
|
||||
{
|
||||
coord_type x;
|
||||
coord_type len; // If negative, it's a solid span, covers is valid
|
||||
const cover_type* covers;
|
||||
};
|
||||
|
||||
typedef span* iterator;
|
||||
typedef const span* const_iterator;
|
||||
|
||||
scanline_p8() :
|
||||
m_last_x(0x7FFFFFF0),
|
||||
m_covers(),
|
||||
m_cover_ptr(0),
|
||||
m_spans(),
|
||||
m_cur_span(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset(int min_x, int max_x)
|
||||
{
|
||||
unsigned max_len = max_x - min_x + 3;
|
||||
if(max_len > m_spans.size())
|
||||
{
|
||||
m_spans.resize(max_len);
|
||||
m_covers.resize(max_len);
|
||||
}
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_cover_ptr = &m_covers[0];
|
||||
m_cur_span = &m_spans[0];
|
||||
m_cur_span->len = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cell(int x, unsigned cover)
|
||||
{
|
||||
*m_cover_ptr = (cover_type)cover;
|
||||
if(x == m_last_x+1 && m_cur_span->len > 0)
|
||||
{
|
||||
m_cur_span->len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->covers = m_cover_ptr;
|
||||
m_cur_span->x = (int16)x;
|
||||
m_cur_span->len = 1;
|
||||
}
|
||||
m_last_x = x;
|
||||
m_cover_ptr++;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
/*void add_cells(int x, unsigned len, const cover_type* covers)
|
||||
{
|
||||
memcpy(m_cover_ptr, covers, len * sizeof(cover_type));
|
||||
if(x == m_last_x+1 && m_cur_span->len > 0)
|
||||
{
|
||||
m_cur_span->len += (int16)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->covers = m_cover_ptr;
|
||||
m_cur_span->x = (int16)x;
|
||||
m_cur_span->len = (int16)len;
|
||||
}
|
||||
m_cover_ptr += len;
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
*/
|
||||
//--------------------------------------------------------------------
|
||||
void add_span(int x, unsigned len, unsigned cover)
|
||||
{
|
||||
if(x == m_last_x+1 &&
|
||||
m_cur_span->len < 0 &&
|
||||
cover == *m_cur_span->covers)
|
||||
{
|
||||
m_cur_span->len -= (int16)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*m_cover_ptr = (cover_type)cover;
|
||||
m_cur_span++;
|
||||
m_cur_span->covers = m_cover_ptr++;
|
||||
m_cur_span->x = (int16)x;
|
||||
m_cur_span->len = (int16)(-int(len));
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int y)
|
||||
{
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_spans()
|
||||
{
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_cover_ptr = &m_covers[0];
|
||||
m_cur_span = &m_spans[0];
|
||||
m_cur_span->len = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y; }
|
||||
unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); }
|
||||
const_iterator begin() const { return &m_spans[1]; }
|
||||
|
||||
private:
|
||||
scanline_p8(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
int m_last_x;
|
||||
int m_y;
|
||||
pod_array<cover_type> m_covers;
|
||||
cover_type* m_cover_ptr;
|
||||
pod_array<span> m_spans;
|
||||
span* m_cur_span;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================scanline32_p8
|
||||
class scanline32_p8
|
||||
{
|
||||
public:
|
||||
typedef scanline32_p8 self_type;
|
||||
typedef int8u cover_type;
|
||||
typedef int32 coord_type;
|
||||
|
||||
struct span
|
||||
{
|
||||
span() {}
|
||||
span(coord_type x_, coord_type len_, const cover_type* covers_) :
|
||||
x(x_), len(len_), covers(covers_) {}
|
||||
|
||||
coord_type x;
|
||||
coord_type len; // If negative, it's a solid span, covers is valid
|
||||
const cover_type* covers;
|
||||
};
|
||||
typedef pod_bvector<span, 4> span_array_type;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
class const_iterator
|
||||
{
|
||||
public:
|
||||
const_iterator(const span_array_type& spans) :
|
||||
m_spans(spans),
|
||||
m_span_idx(0)
|
||||
{}
|
||||
|
||||
const span& operator*() const { return m_spans[m_span_idx]; }
|
||||
const span* operator->() const { return &m_spans[m_span_idx]; }
|
||||
|
||||
void operator ++ () { ++m_span_idx; }
|
||||
|
||||
private:
|
||||
const span_array_type& m_spans;
|
||||
unsigned m_span_idx;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
scanline32_p8() :
|
||||
m_max_len(0),
|
||||
m_last_x(0x7FFFFFF0),
|
||||
m_covers(),
|
||||
m_cover_ptr(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset(int min_x, int max_x)
|
||||
{
|
||||
unsigned max_len = max_x - min_x + 3;
|
||||
if(max_len > m_covers.size())
|
||||
{
|
||||
m_covers.resize(max_len);
|
||||
}
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_cover_ptr = &m_covers[0];
|
||||
m_spans.remove_all();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cell(int x, unsigned cover)
|
||||
{
|
||||
*m_cover_ptr = cover_type(cover);
|
||||
if(x == m_last_x+1 && m_spans.size() && m_spans.last().len > 0)
|
||||
{
|
||||
m_spans.last().len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spans.add(span(coord_type(x), 1, m_cover_ptr));
|
||||
}
|
||||
m_last_x = x;
|
||||
m_cover_ptr++;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cells(int x, unsigned len, const cover_type* covers)
|
||||
{
|
||||
memcpy(m_cover_ptr, covers, len * sizeof(cover_type));
|
||||
if(x == m_last_x+1 && m_spans.size() && m_spans.last().len > 0)
|
||||
{
|
||||
m_spans.last().len += coord_type(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spans.add(span(coord_type(x), coord_type(len), m_cover_ptr));
|
||||
}
|
||||
m_cover_ptr += len;
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_span(int x, unsigned len, unsigned cover)
|
||||
{
|
||||
if(x == m_last_x+1 &&
|
||||
m_spans.size() &&
|
||||
m_spans.last().len < 0 &&
|
||||
cover == *m_spans.last().covers)
|
||||
{
|
||||
m_spans.last().len -= coord_type(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
*m_cover_ptr = cover_type(cover);
|
||||
m_spans.add(span(coord_type(x), -coord_type(len), m_cover_ptr++));
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int y)
|
||||
{
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_spans()
|
||||
{
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_cover_ptr = &m_covers[0];
|
||||
m_spans.remove_all();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y; }
|
||||
unsigned num_spans() const { return m_spans.size(); }
|
||||
const_iterator begin() const { return const_iterator(m_spans); }
|
||||
|
||||
private:
|
||||
scanline32_p8(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
unsigned m_max_len;
|
||||
int m_last_x;
|
||||
int m_y;
|
||||
pod_array<cover_type> m_covers;
|
||||
cover_type* m_cover_ptr;
|
||||
span_array_type m_spans;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,499 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for 32-bit screen coordinates (scanline32_u) has been sponsored by
|
||||
// Liberty Technology Systems, Inc., visit http://lib-sys.com
|
||||
//
|
||||
// Liberty Technology Systems, Inc. is the provider of
|
||||
// PostScript and PDF technology for software developers.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_SCANLINE_U_INCLUDED
|
||||
#define AGG_SCANLINE_U_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//=============================================================scanline_u8
|
||||
//
|
||||
// Unpacked scanline container class
|
||||
//
|
||||
// This class is used to transfer data from a scanline rasterizer
|
||||
// to the rendering buffer. It's organized very simple. The class stores
|
||||
// information of horizontal spans to render it into a pixel-map buffer.
|
||||
// Each span has staring X, length, and an array of bytes that determine the
|
||||
// cover-values for each pixel.
|
||||
// Before using this class you should know the minimal and maximal pixel
|
||||
// coordinates of your scanline. The protocol of using is:
|
||||
// 1. reset(min_x, max_x)
|
||||
// 2. add_cell() / add_span() - accumulate scanline.
|
||||
// When forming one scanline the next X coordinate must be always greater
|
||||
// than the last stored one, i.e. it works only with ordered coordinates.
|
||||
// 3. Call finalize(y) and render the scanline.
|
||||
// 3. Call reset_spans() to prepare for the new scanline.
|
||||
//
|
||||
// 4. Rendering:
|
||||
//
|
||||
// Scanline provides an iterator class that allows you to extract
|
||||
// the spans and the cover values for each pixel. Be aware that clipping
|
||||
// has not been done yet, so you should perform it yourself.
|
||||
// Use scanline_u8::iterator to render spans:
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// int y = sl.y(); // Y-coordinate of the scanline
|
||||
//
|
||||
// ************************************
|
||||
// ...Perform vertical clipping here...
|
||||
// ************************************
|
||||
//
|
||||
// scanline_u8::const_iterator span = sl.begin();
|
||||
//
|
||||
// unsigned char* row = m_rbuf->row(y); // The the address of the beginning
|
||||
// // of the current row
|
||||
//
|
||||
// unsigned num_spans = sl.num_spans(); // Number of spans. It's guaranteed that
|
||||
// // num_spans is always greater than 0.
|
||||
//
|
||||
// do
|
||||
// {
|
||||
// const scanline_u8::cover_type* covers =
|
||||
// span->covers; // The array of the cover values
|
||||
//
|
||||
// int num_pix = span->len; // Number of pixels of the span.
|
||||
// // Always greater than 0, still it's
|
||||
// // better to use "int" instead of
|
||||
// // "unsigned" because it's more
|
||||
// // convenient for clipping
|
||||
// int x = span->x;
|
||||
//
|
||||
// **************************************
|
||||
// ...Perform horizontal clipping here...
|
||||
// ...you have x, covers, and pix_count..
|
||||
// **************************************
|
||||
//
|
||||
// unsigned char* dst = row + x; // Calculate the start address of the row.
|
||||
// // In this case we assume a simple
|
||||
// // grayscale image 1-byte per pixel.
|
||||
// do
|
||||
// {
|
||||
// *dst++ = *covers++; // Hypotetical rendering.
|
||||
// }
|
||||
// while(--num_pix);
|
||||
//
|
||||
// ++span;
|
||||
// }
|
||||
// while(--num_spans); // num_spans cannot be 0, so this loop is quite safe
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// The question is: why should we accumulate the whole scanline when we
|
||||
// could render just separate spans when they're ready?
|
||||
// That's because using the scanline is generally faster. When is consists
|
||||
// of more than one span the conditions for the processor cash system
|
||||
// are better, because switching between two different areas of memory
|
||||
// (that can be very large) occurs less frequently.
|
||||
//------------------------------------------------------------------------
|
||||
class scanline_u8
|
||||
{
|
||||
public:
|
||||
typedef scanline_u8 self_type;
|
||||
typedef int8u cover_type;
|
||||
typedef int16 coord_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
struct span
|
||||
{
|
||||
coord_type x;
|
||||
coord_type len;
|
||||
cover_type* covers;
|
||||
};
|
||||
|
||||
typedef span* iterator;
|
||||
typedef const span* const_iterator;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
scanline_u8() :
|
||||
m_min_x(0),
|
||||
m_last_x(0x7FFFFFF0),
|
||||
m_cur_span(0)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset(int min_x, int max_x)
|
||||
{
|
||||
unsigned max_len = max_x - min_x + 2;
|
||||
if(max_len > m_spans.size())
|
||||
{
|
||||
m_spans.resize(max_len);
|
||||
m_covers.resize(max_len);
|
||||
}
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_min_x = min_x;
|
||||
m_cur_span = &m_spans[0];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cell(int x, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
m_covers[x] = (cover_type)cover;
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (coord_type)(x + m_min_x);
|
||||
m_cur_span->len = 1;
|
||||
m_cur_span->covers = &m_covers[x];
|
||||
}
|
||||
m_last_x = x;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cells(int x, unsigned len, const cover_type* covers)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memcpy(&m_covers[x], covers, len * sizeof(cover_type));
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len += (coord_type)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (coord_type)(x + m_min_x);
|
||||
m_cur_span->len = (coord_type)len;
|
||||
m_cur_span->covers = &m_covers[x];
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_span(int x, unsigned len, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memset(&m_covers[x], cover, len);
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len += (coord_type)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (coord_type)(x + m_min_x);
|
||||
m_cur_span->len = (coord_type)len;
|
||||
m_cur_span->covers = &m_covers[x];
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int y)
|
||||
{
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_spans()
|
||||
{
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_cur_span = &m_spans[0];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y; }
|
||||
unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); }
|
||||
const_iterator begin() const { return &m_spans[1]; }
|
||||
iterator begin() { return &m_spans[1]; }
|
||||
|
||||
private:
|
||||
scanline_u8(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
private:
|
||||
int m_min_x;
|
||||
int m_last_x;
|
||||
int m_y;
|
||||
pod_array<cover_type> m_covers;
|
||||
pod_array<span> m_spans;
|
||||
span* m_cur_span;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================scanline_u8_am
|
||||
//
|
||||
// The scanline container with alpha-masking
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
template<class AlphaMask>
|
||||
class scanline_u8_am : public scanline_u8
|
||||
{
|
||||
public:
|
||||
typedef scanline_u8 base_type;
|
||||
typedef AlphaMask alpha_mask_type;
|
||||
typedef base_type::cover_type cover_type;
|
||||
typedef base_type::coord_type coord_type;
|
||||
|
||||
scanline_u8_am() : base_type(), m_alpha_mask(0) {}
|
||||
scanline_u8_am(const AlphaMask& am) : base_type(), m_alpha_mask(&am) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int span_y)
|
||||
{
|
||||
base_type::finalize(span_y);
|
||||
if(m_alpha_mask)
|
||||
{
|
||||
typename base_type::iterator span = base_type::begin();
|
||||
unsigned count = base_type::num_spans();
|
||||
do
|
||||
{
|
||||
m_alpha_mask->combine_hspan(span->x,
|
||||
base_type::y(),
|
||||
span->covers,
|
||||
span->len);
|
||||
++span;
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const AlphaMask* m_alpha_mask;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//===========================================================scanline32_u8
|
||||
class scanline32_u8
|
||||
{
|
||||
public:
|
||||
typedef scanline32_u8 self_type;
|
||||
typedef int8u cover_type;
|
||||
typedef int32 coord_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
struct span
|
||||
{
|
||||
span() {}
|
||||
span(coord_type x_, coord_type len_, cover_type* covers_) :
|
||||
x(x_), len(len_), covers(covers_) {}
|
||||
|
||||
coord_type x;
|
||||
coord_type len;
|
||||
cover_type* covers;
|
||||
};
|
||||
|
||||
typedef pod_bvector<span, 4> span_array_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
class const_iterator
|
||||
{
|
||||
public:
|
||||
const_iterator(const span_array_type& spans) :
|
||||
m_spans(spans),
|
||||
m_span_idx(0)
|
||||
{}
|
||||
|
||||
const span& operator*() const { return m_spans[m_span_idx]; }
|
||||
const span* operator->() const { return &m_spans[m_span_idx]; }
|
||||
|
||||
void operator ++ () { ++m_span_idx; }
|
||||
|
||||
private:
|
||||
const span_array_type& m_spans;
|
||||
unsigned m_span_idx;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator(span_array_type& spans) :
|
||||
m_spans(spans),
|
||||
m_span_idx(0)
|
||||
{}
|
||||
|
||||
span& operator*() { return m_spans[m_span_idx]; }
|
||||
span* operator->() { return &m_spans[m_span_idx]; }
|
||||
|
||||
void operator ++ () { ++m_span_idx; }
|
||||
|
||||
private:
|
||||
span_array_type& m_spans;
|
||||
unsigned m_span_idx;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
scanline32_u8() :
|
||||
m_min_x(0),
|
||||
m_last_x(0x7FFFFFF0),
|
||||
m_covers()
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset(int min_x, int max_x)
|
||||
{
|
||||
unsigned max_len = max_x - min_x + 2;
|
||||
if(max_len > m_covers.size())
|
||||
{
|
||||
m_covers.resize(max_len);
|
||||
}
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_min_x = min_x;
|
||||
m_spans.remove_all();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cell(int x, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
m_covers[x] = cover_type(cover);
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_spans.last().len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spans.add(span(coord_type(x + m_min_x), 1, &m_covers[x]));
|
||||
}
|
||||
m_last_x = x;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cells(int x, unsigned len, const cover_type* covers)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memcpy(&m_covers[x], covers, len * sizeof(cover_type));
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_spans.last().len += coord_type(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spans.add(span(coord_type(x + m_min_x),
|
||||
coord_type(len),
|
||||
&m_covers[x]));
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_span(int x, unsigned len, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memset(&m_covers[x], cover, len);
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_spans.last().len += coord_type(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spans.add(span(coord_type(x + m_min_x),
|
||||
coord_type(len),
|
||||
&m_covers[x]));
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int y)
|
||||
{
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_spans()
|
||||
{
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_spans.remove_all();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y; }
|
||||
unsigned num_spans() const { return m_spans.size(); }
|
||||
const_iterator begin() const { return const_iterator(m_spans); }
|
||||
iterator begin() { return iterator(m_spans); }
|
||||
|
||||
private:
|
||||
scanline32_u8(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
private:
|
||||
int m_min_x;
|
||||
int m_last_x;
|
||||
int m_y;
|
||||
pod_array<cover_type> m_covers;
|
||||
span_array_type m_spans;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//========================================================scanline32_u8_am
|
||||
//
|
||||
// The scanline container with alpha-masking
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
template<class AlphaMask>
|
||||
class scanline32_u8_am : public scanline32_u8
|
||||
{
|
||||
public:
|
||||
typedef scanline_u8 base_type;
|
||||
typedef AlphaMask alpha_mask_type;
|
||||
typedef base_type::cover_type cover_type;
|
||||
typedef base_type::coord_type coord_type;
|
||||
|
||||
|
||||
scanline32_u8_am() : base_type(), m_alpha_mask(0) {}
|
||||
scanline32_u8_am(const AlphaMask& am) : base_type(), m_alpha_mask(&am) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int span_y)
|
||||
{
|
||||
base_type::finalize(span_y);
|
||||
if(m_alpha_mask)
|
||||
{
|
||||
typename base_type::iterator span = base_type::begin();
|
||||
unsigned count = base_type::num_spans();
|
||||
do
|
||||
{
|
||||
m_alpha_mask->combine_hspan(span->x,
|
||||
base_type::y(),
|
||||
span->covers,
|
||||
span->len);
|
||||
++span;
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const AlphaMask* m_alpha_mask;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_SHORTEN_PATH_INCLUDED
|
||||
#define AGG_SHORTEN_PATH_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vertex_sequence.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//===========================================================shorten_path
|
||||
template<class VertexSequence>
|
||||
void shorten_path(VertexSequence& vs, double s, unsigned closed = 0)
|
||||
{
|
||||
typedef typename VertexSequence::value_type vertex_type;
|
||||
|
||||
if(s > 0.0 && vs.size() > 1)
|
||||
{
|
||||
double d;
|
||||
int n = int(vs.size() - 2);
|
||||
while(n)
|
||||
{
|
||||
d = vs[n].dist;
|
||||
if(d > s) break;
|
||||
vs.remove_last();
|
||||
s -= d;
|
||||
--n;
|
||||
}
|
||||
if(vs.size() < 2)
|
||||
{
|
||||
vs.remove_all();
|
||||
}
|
||||
else
|
||||
{
|
||||
n = vs.size() - 1;
|
||||
vertex_type& prev = vs[n-1];
|
||||
vertex_type& last = vs[n];
|
||||
d = (prev.dist - s) / prev.dist;
|
||||
double x = prev.x + (last.x - prev.x) * d;
|
||||
double y = prev.y + (last.y - prev.y) * d;
|
||||
last.x = x;
|
||||
last.y = y;
|
||||
if(!prev(last)) vs.remove_last();
|
||||
vs.close(closed != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_SPAN_ALLOCATOR_INCLUDED
|
||||
#define AGG_SPAN_ALLOCATOR_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//----------------------------------------------------------span_allocator
|
||||
template<class ColorT> class span_allocator
|
||||
{
|
||||
public:
|
||||
typedef ColorT color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE color_type* allocate(unsigned span_len)
|
||||
{
|
||||
if(span_len > m_span.size())
|
||||
{
|
||||
// To reduce the number of reallocs we align the
|
||||
// span_len to 256 color elements.
|
||||
// Well, I just like this number and it looks reasonable.
|
||||
//-----------------------
|
||||
m_span.resize(((span_len + 255) >> 8) << 8);
|
||||
}
|
||||
return &m_span[0];
|
||||
}
|
||||
|
||||
AGG_INLINE color_type* span() { return &m_span[0]; }
|
||||
AGG_INLINE unsigned max_span_len() const { return m_span.size(); }
|
||||
|
||||
private:
|
||||
pod_array<color_type> m_span;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_SPAN_INTERPOLATOR_LINEAR_INCLUDED
|
||||
#define AGG_SPAN_INTERPOLATOR_LINEAR_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_dda_line.h"
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//================================================span_interpolator_linear
|
||||
template<class Transformer = trans_affine, unsigned SubpixelShift = 8>
|
||||
class span_interpolator_linear
|
||||
{
|
||||
public:
|
||||
typedef Transformer trans_type;
|
||||
|
||||
enum subpixel_scale_e
|
||||
{
|
||||
subpixel_shift = SubpixelShift,
|
||||
subpixel_scale = 1 << subpixel_shift
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_interpolator_linear() {}
|
||||
span_interpolator_linear(const trans_type& trans) : m_trans(&trans) {}
|
||||
span_interpolator_linear(const trans_type& trans,
|
||||
double x, double y, unsigned len) :
|
||||
m_trans(&trans)
|
||||
{
|
||||
begin(x, y, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
const trans_type& transformer() const { return *m_trans; }
|
||||
void transformer(const trans_type& trans) { m_trans = &trans; }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void begin(double x, double y, unsigned len)
|
||||
{
|
||||
double tx;
|
||||
double ty;
|
||||
|
||||
tx = x;
|
||||
ty = y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
int x1 = iround(tx * subpixel_scale);
|
||||
int y1 = iround(ty * subpixel_scale);
|
||||
|
||||
tx = x + len;
|
||||
ty = y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
int x2 = iround(tx * subpixel_scale);
|
||||
int y2 = iround(ty * subpixel_scale);
|
||||
|
||||
m_li_x = dda2_line_interpolator(x1, x2, len);
|
||||
m_li_y = dda2_line_interpolator(y1, y2, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void resynchronize(double xe, double ye, unsigned len)
|
||||
{
|
||||
m_trans->transform(&xe, &ye);
|
||||
m_li_x = dda2_line_interpolator(m_li_x.y(), iround(xe * subpixel_scale), len);
|
||||
m_li_y = dda2_line_interpolator(m_li_y.y(), iround(ye * subpixel_scale), len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void operator++()
|
||||
{
|
||||
++m_li_x;
|
||||
++m_li_y;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void coordinates(int* x, int* y) const
|
||||
{
|
||||
*x = m_li_x.y();
|
||||
*y = m_li_y.y();
|
||||
}
|
||||
|
||||
private:
|
||||
const trans_type* m_trans;
|
||||
dda2_line_interpolator m_li_x;
|
||||
dda2_line_interpolator m_li_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=====================================span_interpolator_linear_subdiv
|
||||
template<class Transformer = trans_affine, unsigned SubpixelShift = 8>
|
||||
class span_interpolator_linear_subdiv
|
||||
{
|
||||
public:
|
||||
typedef Transformer trans_type;
|
||||
|
||||
enum subpixel_scale_e
|
||||
{
|
||||
subpixel_shift = SubpixelShift,
|
||||
subpixel_scale = 1 << subpixel_shift
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
span_interpolator_linear_subdiv() :
|
||||
m_subdiv_shift(4),
|
||||
m_subdiv_size(1 << m_subdiv_shift),
|
||||
m_subdiv_mask(m_subdiv_size - 1) {}
|
||||
|
||||
span_interpolator_linear_subdiv(const trans_type& trans,
|
||||
unsigned subdiv_shift = 4) :
|
||||
m_subdiv_shift(subdiv_shift),
|
||||
m_subdiv_size(1 << m_subdiv_shift),
|
||||
m_subdiv_mask(m_subdiv_size - 1),
|
||||
m_trans(&trans) {}
|
||||
|
||||
span_interpolator_linear_subdiv(const trans_type& trans,
|
||||
double x, double y, unsigned len,
|
||||
unsigned subdiv_shift = 4) :
|
||||
m_subdiv_shift(subdiv_shift),
|
||||
m_subdiv_size(1 << m_subdiv_shift),
|
||||
m_subdiv_mask(m_subdiv_size - 1),
|
||||
m_trans(&trans)
|
||||
{
|
||||
begin(x, y, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
const trans_type& transformer() const { return *m_trans; }
|
||||
void transformer(const trans_type& trans) { m_trans = &trans; }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
unsigned subdiv_shift() const { return m_subdiv_shift; }
|
||||
void subdiv_shift(unsigned shift)
|
||||
{
|
||||
m_subdiv_shift = shift;
|
||||
m_subdiv_size = 1 << m_subdiv_shift;
|
||||
m_subdiv_mask = m_subdiv_size - 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void begin(double x, double y, unsigned len)
|
||||
{
|
||||
double tx;
|
||||
double ty;
|
||||
m_pos = 1;
|
||||
m_src_x = iround(x * subpixel_scale) + subpixel_scale;
|
||||
m_src_y = y;
|
||||
m_len = len;
|
||||
|
||||
if(len > m_subdiv_size) len = m_subdiv_size;
|
||||
tx = x;
|
||||
ty = y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
int x1 = iround(tx * subpixel_scale);
|
||||
int y1 = iround(ty * subpixel_scale);
|
||||
|
||||
tx = x + len;
|
||||
ty = y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
|
||||
m_li_x = dda2_line_interpolator(x1, iround(tx * subpixel_scale), len);
|
||||
m_li_y = dda2_line_interpolator(y1, iround(ty * subpixel_scale), len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void operator++()
|
||||
{
|
||||
++m_li_x;
|
||||
++m_li_y;
|
||||
if(m_pos >= m_subdiv_size)
|
||||
{
|
||||
unsigned len = m_len;
|
||||
if(len > m_subdiv_size) len = m_subdiv_size;
|
||||
double tx = double(m_src_x) / double(subpixel_scale) + len;
|
||||
double ty = m_src_y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
m_li_x = dda2_line_interpolator(m_li_x.y(), iround(tx * subpixel_scale), len);
|
||||
m_li_y = dda2_line_interpolator(m_li_y.y(), iround(ty * subpixel_scale), len);
|
||||
m_pos = 0;
|
||||
}
|
||||
m_src_x += subpixel_scale;
|
||||
++m_pos;
|
||||
--m_len;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void coordinates(int* x, int* y) const
|
||||
{
|
||||
*x = m_li_x.y();
|
||||
*y = m_li_y.y();
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned m_subdiv_shift;
|
||||
unsigned m_subdiv_size;
|
||||
unsigned m_subdiv_mask;
|
||||
const trans_type* m_trans;
|
||||
dda2_line_interpolator m_li_x;
|
||||
dda2_line_interpolator m_li_y;
|
||||
int m_src_x;
|
||||
double m_src_y;
|
||||
unsigned m_pos;
|
||||
unsigned m_len;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1,194 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Affine transformations
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::parl_to_parl(const double* src,
|
||||
const double* dst)
|
||||
{
|
||||
sx = src[2] - src[0];
|
||||
shy = src[3] - src[1];
|
||||
shx = src[4] - src[0];
|
||||
sy = src[5] - src[1];
|
||||
tx = src[0];
|
||||
ty = src[1];
|
||||
invert();
|
||||
multiply(trans_affine(dst[2] - dst[0], dst[3] - dst[1],
|
||||
dst[4] - dst[0], dst[5] - dst[1],
|
||||
dst[0], dst[1]));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::rect_to_parl(double x1, double y1,
|
||||
double x2, double y2,
|
||||
const double* parl)
|
||||
{
|
||||
double src[6];
|
||||
src[0] = x1; src[1] = y1;
|
||||
src[2] = x2; src[3] = y1;
|
||||
src[4] = x2; src[5] = y2;
|
||||
parl_to_parl(src, parl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::parl_to_rect(const double* parl,
|
||||
double x1, double y1,
|
||||
double x2, double y2)
|
||||
{
|
||||
double dst[6];
|
||||
dst[0] = x1; dst[1] = y1;
|
||||
dst[2] = x2; dst[3] = y1;
|
||||
dst[4] = x2; dst[5] = y2;
|
||||
parl_to_parl(parl, dst);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::multiply(const trans_affine& m)
|
||||
{
|
||||
double t0 = sx * m.sx + shy * m.shx;
|
||||
double t2 = shx * m.sx + sy * m.shx;
|
||||
double t4 = tx * m.sx + ty * m.shx + m.tx;
|
||||
shy = sx * m.shy + shy * m.sy;
|
||||
sy = shx * m.shy + sy * m.sy;
|
||||
ty = tx * m.shy + ty * m.sy + m.ty;
|
||||
sx = t0;
|
||||
shx = t2;
|
||||
tx = t4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::invert()
|
||||
{
|
||||
double d = determinant_reciprocal();
|
||||
|
||||
double t0 = sy * d;
|
||||
sy = sx * d;
|
||||
shy = -shy * d;
|
||||
shx = -shx * d;
|
||||
|
||||
double t4 = -tx * t0 - ty * shx;
|
||||
ty = -tx * shy - ty * sy;
|
||||
|
||||
sx = t0;
|
||||
tx = t4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::flip_x()
|
||||
{
|
||||
sx = -sx;
|
||||
shy = -shy;
|
||||
tx = -tx;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::flip_y()
|
||||
{
|
||||
shx = -shx;
|
||||
sy = -sy;
|
||||
ty = -ty;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::reset()
|
||||
{
|
||||
sx = sy = 1.0;
|
||||
shy = shx = tx = ty = 0.0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool trans_affine::is_identity(double epsilon) const
|
||||
{
|
||||
return is_equal_eps(sx, 1.0, epsilon) &&
|
||||
is_equal_eps(shy, 0.0, epsilon) &&
|
||||
is_equal_eps(shx, 0.0, epsilon) &&
|
||||
is_equal_eps(sy, 1.0, epsilon) &&
|
||||
is_equal_eps(tx, 0.0, epsilon) &&
|
||||
is_equal_eps(ty, 0.0, epsilon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool trans_affine::is_valid(double epsilon) const
|
||||
{
|
||||
return fabs(sx) > epsilon && fabs(sy) > epsilon;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool trans_affine::is_equal(const trans_affine& m, double epsilon) const
|
||||
{
|
||||
return is_equal_eps(sx, m.sx, epsilon) &&
|
||||
is_equal_eps(shy, m.shy, epsilon) &&
|
||||
is_equal_eps(shx, m.shx, epsilon) &&
|
||||
is_equal_eps(sy, m.sy, epsilon) &&
|
||||
is_equal_eps(tx, m.tx, epsilon) &&
|
||||
is_equal_eps(ty, m.ty, epsilon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double trans_affine::rotation() const
|
||||
{
|
||||
double x1 = 0.0;
|
||||
double y1 = 0.0;
|
||||
double x2 = 1.0;
|
||||
double y2 = 0.0;
|
||||
transform(&x1, &y1);
|
||||
transform(&x2, &y2);
|
||||
return atan2(y2-y1, x2-x1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void trans_affine::translation(double* dx, double* dy) const
|
||||
{
|
||||
*dx = tx;
|
||||
*dy = ty;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void trans_affine::scaling(double* x, double* y) const
|
||||
{
|
||||
double x1 = 0.0;
|
||||
double y1 = 0.0;
|
||||
double x2 = 1.0;
|
||||
double y2 = 1.0;
|
||||
trans_affine t(*this);
|
||||
t *= trans_affine_rotation(-rotation());
|
||||
t.transform(&x1, &y1);
|
||||
t.transform(&x2, &y2);
|
||||
*x = x2 - x1;
|
||||
*y = y2 - y1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,518 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Affine transformation classes.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_TRANS_AFFINE_INCLUDED
|
||||
#define AGG_TRANS_AFFINE_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
const double affine_epsilon = 1e-14;
|
||||
|
||||
//============================================================trans_affine
|
||||
//
|
||||
// See Implementation agg_trans_affine.cpp
|
||||
//
|
||||
// Affine transformation are linear transformations in Cartesian coordinates
|
||||
// (strictly speaking not only in Cartesian, but for the beginning we will
|
||||
// think so). They are rotation, scaling, translation and skewing.
|
||||
// After any affine transformation a line segment remains a line segment
|
||||
// and it will never become a curve.
|
||||
//
|
||||
// There will be no math about matrix calculations, since it has been
|
||||
// described many times. Ask yourself a very simple question:
|
||||
// "why do we need to understand and use some matrix stuff instead of just
|
||||
// rotating, scaling and so on". The answers are:
|
||||
//
|
||||
// 1. Any combination of transformations can be done by only 4 multiplications
|
||||
// and 4 additions in floating point.
|
||||
// 2. One matrix transformation is equivalent to the number of consecutive
|
||||
// discrete transformations, i.e. the matrix "accumulates" all transformations
|
||||
// in the order of their settings. Suppose we have 4 transformations:
|
||||
// * rotate by 30 degrees,
|
||||
// * scale X to 2.0,
|
||||
// * scale Y to 1.5,
|
||||
// * move to (100, 100).
|
||||
// The result will depend on the order of these transformations,
|
||||
// and the advantage of matrix is that the sequence of discret calls:
|
||||
// rotate(30), scaleX(2.0), scaleY(1.5), move(100,100)
|
||||
// will have exactly the same result as the following matrix transformations:
|
||||
//
|
||||
// affine_matrix m;
|
||||
// m *= rotate_matrix(30);
|
||||
// m *= scaleX_matrix(2.0);
|
||||
// m *= scaleY_matrix(1.5);
|
||||
// m *= move_matrix(100,100);
|
||||
//
|
||||
// m.transform_my_point_at_last(x, y);
|
||||
//
|
||||
// What is the good of it? In real life we will set-up the matrix only once
|
||||
// and then transform many points, let alone the convenience to set any
|
||||
// combination of transformations.
|
||||
//
|
||||
// So, how to use it? Very easy - literally as it's shown above. Not quite,
|
||||
// let us write a correct example:
|
||||
//
|
||||
// agg::trans_affine m;
|
||||
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0);
|
||||
// m *= agg::trans_affine_scaling(2.0, 1.5);
|
||||
// m *= agg::trans_affine_translation(100.0, 100.0);
|
||||
// m.transform(&x, &y);
|
||||
//
|
||||
// The affine matrix is all you need to perform any linear transformation,
|
||||
// but all transformations have origin point (0,0). It means that we need to
|
||||
// use 2 translations if we want to rotate someting around (100,100):
|
||||
//
|
||||
// m *= agg::trans_affine_translation(-100.0, -100.0); // move to (0,0)
|
||||
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate
|
||||
// m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100)
|
||||
//----------------------------------------------------------------------
|
||||
struct trans_affine
|
||||
{
|
||||
double sx, shy, shx, sy, tx, ty;
|
||||
|
||||
//------------------------------------------ Construction
|
||||
// Identity matrix
|
||||
trans_affine() :
|
||||
sx(1.0), shy(0.0), shx(0.0), sy(1.0), tx(0.0), ty(0.0)
|
||||
{}
|
||||
|
||||
// Custom matrix. Usually used in derived classes
|
||||
trans_affine(double v0, double v1, double v2,
|
||||
double v3, double v4, double v5) :
|
||||
sx(v0), shy(v1), shx(v2), sy(v3), tx(v4), ty(v5)
|
||||
{}
|
||||
|
||||
// Custom matrix from m[6]
|
||||
explicit trans_affine(const double* m) :
|
||||
sx(m[0]), shy(m[1]), shx(m[2]), sy(m[3]), tx(m[4]), ty(m[5])
|
||||
{}
|
||||
|
||||
// Rectangle to a parallelogram.
|
||||
trans_affine(double x1, double y1, double x2, double y2,
|
||||
const double* parl)
|
||||
{
|
||||
rect_to_parl(x1, y1, x2, y2, parl);
|
||||
}
|
||||
|
||||
// Parallelogram to a rectangle.
|
||||
trans_affine(const double* parl,
|
||||
double x1, double y1, double x2, double y2)
|
||||
{
|
||||
parl_to_rect(parl, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
// Arbitrary parallelogram transformation.
|
||||
trans_affine(const double* src, const double* dst)
|
||||
{
|
||||
parl_to_parl(src, dst);
|
||||
}
|
||||
|
||||
//---------------------------------- Parellelogram transformations
|
||||
// transform a parallelogram to another one. Src and dst are
|
||||
// pointers to arrays of three points (double[6], x1,y1,...) that
|
||||
// identify three corners of the parallelograms assuming implicit
|
||||
// fourth point. The arguments are arrays of double[6] mapped
|
||||
// to x1,y1, x2,y2, x3,y3 where the coordinates are:
|
||||
// *-----------------*
|
||||
// / (x3,y3)/
|
||||
// / /
|
||||
// /(x1,y1) (x2,y2)/
|
||||
// *-----------------*
|
||||
const trans_affine& parl_to_parl(const double* src,
|
||||
const double* dst);
|
||||
|
||||
const trans_affine& rect_to_parl(double x1, double y1,
|
||||
double x2, double y2,
|
||||
const double* parl);
|
||||
|
||||
const trans_affine& parl_to_rect(const double* parl,
|
||||
double x1, double y1,
|
||||
double x2, double y2);
|
||||
|
||||
|
||||
//------------------------------------------ Operations
|
||||
// Reset - load an identity matrix
|
||||
const trans_affine& reset();
|
||||
|
||||
// Direct transformations operations
|
||||
const trans_affine& translate(double x, double y);
|
||||
const trans_affine& rotate(double a);
|
||||
const trans_affine& scale(double s);
|
||||
const trans_affine& scale(double x, double y);
|
||||
|
||||
// Multiply matrix to another one
|
||||
const trans_affine& multiply(const trans_affine& m);
|
||||
|
||||
// Multiply "m" to "this" and assign the result to "this"
|
||||
const trans_affine& premultiply(const trans_affine& m);
|
||||
|
||||
// Multiply matrix to inverse of another one
|
||||
const trans_affine& multiply_inv(const trans_affine& m);
|
||||
|
||||
// Multiply inverse of "m" to "this" and assign the result to "this"
|
||||
const trans_affine& premultiply_inv(const trans_affine& m);
|
||||
|
||||
// Invert matrix. Do not try to invert degenerate matrices,
|
||||
// there's no check for validity. If you set scale to 0 and
|
||||
// then try to invert matrix, expect unpredictable result.
|
||||
const trans_affine& invert();
|
||||
|
||||
// Mirroring around X
|
||||
const trans_affine& flip_x();
|
||||
|
||||
// Mirroring around Y
|
||||
const trans_affine& flip_y();
|
||||
|
||||
//------------------------------------------- Load/Store
|
||||
// Store matrix to an array [6] of double
|
||||
void store_to(double* m) const
|
||||
{
|
||||
*m++ = sx; *m++ = shy; *m++ = shx; *m++ = sy; *m++ = tx; *m++ = ty;
|
||||
}
|
||||
|
||||
// Load matrix from an array [6] of double
|
||||
const trans_affine& load_from(const double* m)
|
||||
{
|
||||
sx = *m++; shy = *m++; shx = *m++; sy = *m++; tx = *m++; ty = *m++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------- Operators
|
||||
|
||||
// Multiply the matrix by another one
|
||||
const trans_affine& operator *= (const trans_affine& m)
|
||||
{
|
||||
return multiply(m);
|
||||
}
|
||||
|
||||
// Multiply the matrix by inverse of another one
|
||||
const trans_affine& operator /= (const trans_affine& m)
|
||||
{
|
||||
return multiply_inv(m);
|
||||
}
|
||||
|
||||
// Multiply the matrix by another one and return
|
||||
// the result in a separete matrix.
|
||||
trans_affine operator * (const trans_affine& m)
|
||||
{
|
||||
return trans_affine(*this).multiply(m);
|
||||
}
|
||||
|
||||
// Multiply the matrix by inverse of another one
|
||||
// and return the result in a separete matrix.
|
||||
trans_affine operator / (const trans_affine& m)
|
||||
{
|
||||
return trans_affine(*this).multiply_inv(m);
|
||||
}
|
||||
|
||||
// Calculate and return the inverse matrix
|
||||
trans_affine operator ~ () const
|
||||
{
|
||||
trans_affine ret = *this;
|
||||
return ret.invert();
|
||||
}
|
||||
|
||||
// Equal operator with default epsilon
|
||||
bool operator == (const trans_affine& m) const
|
||||
{
|
||||
return is_equal(m, affine_epsilon);
|
||||
}
|
||||
|
||||
// Not Equal operator with default epsilon
|
||||
bool operator != (const trans_affine& m) const
|
||||
{
|
||||
return !is_equal(m, affine_epsilon);
|
||||
}
|
||||
|
||||
//-------------------------------------------- Transformations
|
||||
// Direct transformation of x and y
|
||||
void transform(double* x, double* y) const;
|
||||
|
||||
// Direct transformation of x and y, 2x2 matrix only, no translation
|
||||
void transform_2x2(double* x, double* y) const;
|
||||
|
||||
// Inverse transformation of x and y. It works slower than the
|
||||
// direct transformation. For massive operations it's better to
|
||||
// invert() the matrix and then use direct transformations.
|
||||
void inverse_transform(double* x, double* y) const;
|
||||
|
||||
//-------------------------------------------- Auxiliary
|
||||
// Calculate the determinant of matrix
|
||||
double determinant() const
|
||||
{
|
||||
return sx * sy - shy * shx;
|
||||
}
|
||||
|
||||
// Calculate the reciprocal of the determinant
|
||||
double determinant_reciprocal() const
|
||||
{
|
||||
return 1.0 / (sx * sy - shy * shx);
|
||||
}
|
||||
|
||||
// Get the average scale (by X and Y).
|
||||
// Basically used to calculate the approximation_scale when
|
||||
// decomposinting curves into line segments.
|
||||
double scale() const;
|
||||
|
||||
// Check to see if the matrix is not degenerate
|
||||
bool is_valid(double epsilon = affine_epsilon) const;
|
||||
|
||||
// Check to see if it's an identity matrix
|
||||
bool is_identity(double epsilon = affine_epsilon) const;
|
||||
|
||||
// Check to see if two matrices are equal
|
||||
bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const;
|
||||
|
||||
// Determine the major parameters. Use with caution considering
|
||||
// possible degenerate cases.
|
||||
double rotation() const;
|
||||
void translation(double* dx, double* dy) const;
|
||||
void scaling(double* x, double* y) const;
|
||||
void scaling_abs(double* x, double* y) const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::transform(double* x, double* y) const
|
||||
{
|
||||
register double tmp = *x;
|
||||
*x = tmp * sx + *y * shx + tx;
|
||||
*y = tmp * shy + *y * sy + ty;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::transform_2x2(double* x, double* y) const
|
||||
{
|
||||
register double tmp = *x;
|
||||
*x = tmp * sx + *y * shx;
|
||||
*y = tmp * shy + *y * sy;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::inverse_transform(double* x, double* y) const
|
||||
{
|
||||
register double d = determinant_reciprocal();
|
||||
register double a = (*x - tx) * d;
|
||||
register double b = (*y - ty) * d;
|
||||
*x = a * sy - b * shx;
|
||||
*y = b * sx - a * shy;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline double trans_affine::scale() const
|
||||
{
|
||||
double x = 0.707106781 * sx + 0.707106781 * shx;
|
||||
double y = 0.707106781 * shy + 0.707106781 * sy;
|
||||
return sqrt(x*x + y*y);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::translate(double x, double y)
|
||||
{
|
||||
tx += x;
|
||||
ty += y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::rotate(double a)
|
||||
{
|
||||
double ca = cos(a);
|
||||
double sa = sin(a);
|
||||
double t0 = sx * ca - shy * sa;
|
||||
double t2 = shx * ca - sy * sa;
|
||||
double t4 = tx * ca - ty * sa;
|
||||
shy = sx * sa + shy * ca;
|
||||
sy = shx * sa + sy * ca;
|
||||
ty = tx * sa + ty * ca;
|
||||
sx = t0;
|
||||
shx = t2;
|
||||
tx = t4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::scale(double x, double y)
|
||||
{
|
||||
double mm0 = x; // Possible hint for the optimizer
|
||||
double mm3 = y;
|
||||
sx *= mm0;
|
||||
shx *= mm0;
|
||||
tx *= mm0;
|
||||
shy *= mm3;
|
||||
sy *= mm3;
|
||||
ty *= mm3;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::scale(double s)
|
||||
{
|
||||
double m = s; // Possible hint for the optimizer
|
||||
sx *= m;
|
||||
shx *= m;
|
||||
tx *= m;
|
||||
shy *= m;
|
||||
sy *= m;
|
||||
ty *= m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::premultiply(const trans_affine& m)
|
||||
{
|
||||
trans_affine t = m;
|
||||
return *this = t.multiply(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::multiply_inv(const trans_affine& m)
|
||||
{
|
||||
trans_affine t = m;
|
||||
t.invert();
|
||||
return multiply(t);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::premultiply_inv(const trans_affine& m)
|
||||
{
|
||||
trans_affine t = m;
|
||||
t.invert();
|
||||
return *this = t.multiply(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::scaling_abs(double* x, double* y) const
|
||||
{
|
||||
// Used to calculate scaling coefficients in image resampling.
|
||||
// When there is considerable shear this method gives us much
|
||||
// better estimation than just sx, sy.
|
||||
*x = sqrt(sx * sx + shx * shx);
|
||||
*y = sqrt(shy * shy + sy * sy);
|
||||
}
|
||||
|
||||
//====================================================trans_affine_rotation
|
||||
// Rotation matrix. sin() and cos() are calculated twice for the same angle.
|
||||
// There's no harm because the performance of sin()/cos() is very good on all
|
||||
// modern processors. Besides, this operation is not going to be invoked too
|
||||
// often.
|
||||
class trans_affine_rotation : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_rotation(double a) :
|
||||
trans_affine(cos(a), sin(a), -sin(a), cos(a), 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
//====================================================trans_affine_scaling
|
||||
// Scaling matrix. x, y - scale coefficients by X and Y respectively
|
||||
class trans_affine_scaling : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_scaling(double x, double y) :
|
||||
trans_affine(x, 0.0, 0.0, y, 0.0, 0.0)
|
||||
{}
|
||||
|
||||
trans_affine_scaling(double s) :
|
||||
trans_affine(s, 0.0, 0.0, s, 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
//================================================trans_affine_translation
|
||||
// Translation matrix
|
||||
class trans_affine_translation : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_translation(double x, double y) :
|
||||
trans_affine(1.0, 0.0, 0.0, 1.0, x, y)
|
||||
{}
|
||||
};
|
||||
|
||||
//====================================================trans_affine_skewing
|
||||
// Sckewing (shear) matrix
|
||||
class trans_affine_skewing : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_skewing(double x, double y) :
|
||||
trans_affine(1.0, tan(y), tan(x), 1.0, 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
//===============================================trans_affine_line_segment
|
||||
// Rotate, Scale and Translate, associating 0...dist with line segment
|
||||
// x1,y1,x2,y2
|
||||
class trans_affine_line_segment : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_line_segment(double x1, double y1, double x2, double y2,
|
||||
double dist)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
if(dist > 0.0)
|
||||
{
|
||||
multiply(trans_affine_scaling(sqrt(dx * dx + dy * dy) / dist));
|
||||
}
|
||||
multiply(trans_affine_rotation(atan2(dy, dx)));
|
||||
multiply(trans_affine_translation(x1, y1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//============================================trans_affine_reflection_unit
|
||||
// Reflection matrix. Reflect coordinates across the line through
|
||||
// the origin containing the unit vector (ux, uy).
|
||||
// Contributed by John Horigan
|
||||
class trans_affine_reflection_unit : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_reflection_unit(double ux, double uy) :
|
||||
trans_affine(2.0 * ux * ux - 1.0,
|
||||
2.0 * ux * uy,
|
||||
2.0 * ux * uy,
|
||||
2.0 * uy * uy - 1.0,
|
||||
0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
//=================================================trans_affine_reflection
|
||||
// Reflection matrix. Reflect coordinates across the line through
|
||||
// the origin at the angle a or containing the non-unit vector (x, y).
|
||||
// Contributed by John Horigan
|
||||
class trans_affine_reflection : public trans_affine_reflection_unit
|
||||
{
|
||||
public:
|
||||
trans_affine_reflection(double a) :
|
||||
trans_affine_reflection_unit(cos(a), sin(a))
|
||||
{}
|
||||
|
||||
|
||||
trans_affine_reflection(double x, double y) :
|
||||
trans_affine_reflection_unit(x / sqrt(x * x + y * y), y / sqrt(x * x + y * y))
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Line dash generator
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_vcgen_dash.h"
|
||||
#include "agg_shorten_path.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
vcgen_dash::vcgen_dash() :
|
||||
m_total_dash_len(0.0),
|
||||
m_dash_start(0.0),
|
||||
m_shorten(0.0),
|
||||
m_curr_dash_start(0.0),
|
||||
m_curr_dash(0),
|
||||
m_src_vertices(),
|
||||
m_closed(0),
|
||||
m_status(initial),
|
||||
m_src_vertex(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*void vcgen_dash::remove_all_dashes()
|
||||
{
|
||||
m_dashes.Clear();
|
||||
m_total_dash_len = 0.0;
|
||||
m_curr_dash_start = 0.0;
|
||||
m_curr_dash = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_dash::Set(const Upp::Vector<double> *dash, double start)
|
||||
{
|
||||
m_dashes = dash;
|
||||
m_total_dash_len += Sum0(*dash);
|
||||
|
||||
m_dash_start = start;
|
||||
calc_dash_start(fabs(start));
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_dash::calc_dash_start(double ds)
|
||||
{
|
||||
m_curr_dash = 0;
|
||||
m_curr_dash_start = 0.0;
|
||||
while(ds > 0.0)
|
||||
{
|
||||
if(ds > (*m_dashes)[(int)m_curr_dash])
|
||||
{
|
||||
ds -= (*m_dashes)[(int)m_curr_dash];
|
||||
++m_curr_dash;
|
||||
m_curr_dash_start = 0.0;
|
||||
if((int)m_curr_dash >= (*m_dashes).GetCount()) m_curr_dash = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_curr_dash_start = ds;
|
||||
ds = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_dash::remove_all()
|
||||
{
|
||||
m_status = initial;
|
||||
m_src_vertices.remove_all();
|
||||
m_closed = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_dash::add_vertex(double x, double y, unsigned cmd)
|
||||
{
|
||||
m_status = initial;
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
m_src_vertices.modify_last(vertex_dist(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_src_vertices.add(vertex_dist(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_closed = get_close_flag(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_dash::rewind(unsigned)
|
||||
{
|
||||
if(m_status == initial)
|
||||
{
|
||||
m_src_vertices.close(m_closed != 0);
|
||||
shorten_path(m_src_vertices, m_shorten, m_closed);
|
||||
}
|
||||
m_status = ready;
|
||||
m_src_vertex = 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned vcgen_dash::vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_move_to;
|
||||
while(!is_stop(cmd))
|
||||
{
|
||||
switch(m_status)
|
||||
{
|
||||
case initial:
|
||||
rewind(0);
|
||||
|
||||
case ready:
|
||||
if((*m_dashes).GetCount() < 2 || m_src_vertices.size() < 2)
|
||||
{
|
||||
cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
m_status = polyline;
|
||||
m_src_vertex = 1;
|
||||
m_v1 = &m_src_vertices[0];
|
||||
m_v2 = &m_src_vertices[1];
|
||||
m_curr_rest = m_v1->dist;
|
||||
*x = m_v1->x;
|
||||
*y = m_v1->y;
|
||||
if(m_dash_start >= 0.0) calc_dash_start(m_dash_start);
|
||||
return path_cmd_move_to;
|
||||
|
||||
case polyline:
|
||||
{
|
||||
double dash_rest = (*m_dashes)[(int)m_curr_dash] - m_curr_dash_start;
|
||||
|
||||
unsigned cmd = (m_curr_dash & 1) ?
|
||||
path_cmd_move_to :
|
||||
path_cmd_line_to;
|
||||
|
||||
if(m_curr_rest > dash_rest)
|
||||
{
|
||||
m_curr_rest -= dash_rest;
|
||||
++m_curr_dash;
|
||||
if((int)m_curr_dash >= (*m_dashes).GetCount()) m_curr_dash = 0;
|
||||
m_curr_dash_start = 0.0;
|
||||
*x = m_v2->x - (m_v2->x - m_v1->x) * m_curr_rest / m_v1->dist;
|
||||
*y = m_v2->y - (m_v2->y - m_v1->y) * m_curr_rest / m_v1->dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_curr_dash_start += m_curr_rest;
|
||||
*x = m_v2->x;
|
||||
*y = m_v2->y;
|
||||
++m_src_vertex;
|
||||
m_v1 = m_v2;
|
||||
m_curr_rest = m_v1->dist;
|
||||
if(m_closed)
|
||||
{
|
||||
if(m_src_vertex > m_src_vertices.size())
|
||||
{
|
||||
m_status = stop;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_v2 = &m_src_vertices
|
||||
[
|
||||
(m_src_vertex >= m_src_vertices.size()) ? 0 :
|
||||
m_src_vertex
|
||||
];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_src_vertex >= m_src_vertices.size())
|
||||
{
|
||||
m_status = stop;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_v2 = &m_src_vertices[m_src_vertex];
|
||||
}
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
break;
|
||||
|
||||
case stop:
|
||||
cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return path_cmd_stop;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Line dash generator
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_VCGEN_DASH_INCLUDED
|
||||
#define AGG_VCGEN_DASH_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vertex_sequence.h"
|
||||
|
||||
#include <Core/Core.h>
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//---------------------------------------------------------------vcgen_dash
|
||||
//
|
||||
// See Implementation agg_vcgen_dash.cpp
|
||||
//
|
||||
class vcgen_dash
|
||||
{
|
||||
enum status_e
|
||||
{
|
||||
initial,
|
||||
ready,
|
||||
polyline,
|
||||
stop
|
||||
};
|
||||
|
||||
public:
|
||||
typedef vertex_sequence<vertex_dist, 6> vertex_storage;
|
||||
|
||||
vcgen_dash();
|
||||
|
||||
void Set(const Upp::Vector<double> *dash, double start);
|
||||
|
||||
void shorten(double s) { m_shorten = s; }
|
||||
double shorten() const { return m_shorten; }
|
||||
|
||||
// Vertex Generator Interface
|
||||
void remove_all();
|
||||
void add_vertex(double x, double y, unsigned cmd);
|
||||
|
||||
// Vertex Source Interface
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
private:
|
||||
vcgen_dash(const vcgen_dash&);
|
||||
const vcgen_dash& operator = (const vcgen_dash&);
|
||||
|
||||
void calc_dash_start(double ds);
|
||||
|
||||
const UPP::Vector<double> *m_dashes; //AGGUPP
|
||||
double m_dash_start;
|
||||
double m_total_dash_len;
|
||||
double m_shorten;
|
||||
double m_curr_dash_start;
|
||||
unsigned m_curr_dash;
|
||||
double m_curr_rest;
|
||||
const vertex_dist* m_v1;
|
||||
const vertex_dist* m_v2;
|
||||
|
||||
vertex_storage m_src_vertices;
|
||||
unsigned m_closed;
|
||||
status_e m_status;
|
||||
unsigned m_src_vertex;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Stroke generator
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#include <math.h>
|
||||
#include "agg_vcgen_stroke.h"
|
||||
#include "agg_shorten_path.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
vcgen_stroke::vcgen_stroke() :
|
||||
m_stroker(),
|
||||
m_src_vertices(),
|
||||
m_out_vertices(),
|
||||
m_shorten(0.0),
|
||||
m_closed(0),
|
||||
m_status(initial),
|
||||
m_src_vertex(0),
|
||||
m_out_vertex(0)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::remove_all()
|
||||
{
|
||||
m_src_vertices.remove_all();
|
||||
m_closed = 0;
|
||||
m_status = initial;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::add_vertex(double x, double y, unsigned cmd)
|
||||
{
|
||||
m_status = initial;
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
m_src_vertices.modify_last(vertex_dist(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_src_vertices.add(vertex_dist(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_closed = get_close_flag(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::rewind(unsigned)
|
||||
{
|
||||
if(m_status == initial)
|
||||
{
|
||||
m_src_vertices.close(m_closed != 0);
|
||||
shorten_path(m_src_vertices, m_shorten, m_closed);
|
||||
if(m_src_vertices.size() < 3) m_closed = 0;
|
||||
}
|
||||
m_status = ready;
|
||||
m_src_vertex = 0;
|
||||
m_out_vertex = 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned vcgen_stroke::vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_line_to;
|
||||
while(!is_stop(cmd))
|
||||
{
|
||||
switch(m_status)
|
||||
{
|
||||
case initial:
|
||||
rewind(0);
|
||||
|
||||
case ready:
|
||||
if(m_src_vertices.size() < 2 + unsigned(m_closed != 0))
|
||||
{
|
||||
cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
m_status = m_closed ? outline1 : cap1;
|
||||
cmd = path_cmd_move_to;
|
||||
m_src_vertex = 0;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case cap1:
|
||||
m_stroker.calc_cap(m_out_vertices,
|
||||
m_src_vertices[0],
|
||||
m_src_vertices[1],
|
||||
m_src_vertices[0].dist);
|
||||
m_src_vertex = 1;
|
||||
m_prev_status = outline1;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case cap2:
|
||||
m_stroker.calc_cap(m_out_vertices,
|
||||
m_src_vertices[m_src_vertices.size() - 1],
|
||||
m_src_vertices[m_src_vertices.size() - 2],
|
||||
m_src_vertices[m_src_vertices.size() - 2].dist);
|
||||
m_prev_status = outline2;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case outline1:
|
||||
if(m_closed)
|
||||
{
|
||||
if(m_src_vertex >= m_src_vertices.size())
|
||||
{
|
||||
m_prev_status = close_first;
|
||||
m_status = end_poly1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_src_vertex >= m_src_vertices.size() - 1)
|
||||
{
|
||||
m_status = cap2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_stroker.calc_join(m_out_vertices,
|
||||
m_src_vertices.prev(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex),
|
||||
m_src_vertices.next(m_src_vertex),
|
||||
m_src_vertices.prev(m_src_vertex).dist,
|
||||
m_src_vertices.curr(m_src_vertex).dist);
|
||||
++m_src_vertex;
|
||||
m_prev_status = m_status;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case close_first:
|
||||
m_status = outline2;
|
||||
cmd = path_cmd_move_to;
|
||||
|
||||
case outline2:
|
||||
if(m_src_vertex <= unsigned(m_closed == 0))
|
||||
{
|
||||
m_status = end_poly2;
|
||||
m_prev_status = stop;
|
||||
break;
|
||||
}
|
||||
|
||||
--m_src_vertex;
|
||||
m_stroker.calc_join(m_out_vertices,
|
||||
m_src_vertices.next(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex),
|
||||
m_src_vertices.prev(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex).dist,
|
||||
m_src_vertices.prev(m_src_vertex).dist);
|
||||
|
||||
m_prev_status = m_status;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case out_vertices:
|
||||
if(m_out_vertex >= m_out_vertices.size())
|
||||
{
|
||||
m_status = m_prev_status;
|
||||
}
|
||||
else
|
||||
{
|
||||
const point_d& c = m_out_vertices[m_out_vertex++];
|
||||
*x = c.x;
|
||||
*y = c.y;
|
||||
return cmd;
|
||||
}
|
||||
break;
|
||||
|
||||
case end_poly1:
|
||||
m_status = m_prev_status;
|
||||
return path_cmd_end_poly | path_flags_close | path_flags_ccw;
|
||||
|
||||
case end_poly2:
|
||||
m_status = m_prev_status;
|
||||
return path_cmd_end_poly | path_flags_close | path_flags_cw;
|
||||
|
||||
case stop:
|
||||
cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_VCGEN_STROKE_INCLUDED
|
||||
#define AGG_VCGEN_STROKE_INCLUDED
|
||||
|
||||
#include "agg_math_stroke.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//============================================================vcgen_stroke
|
||||
//
|
||||
// See Implementation agg_vcgen_stroke.cpp
|
||||
// Stroke generator
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
class vcgen_stroke
|
||||
{
|
||||
enum status_e
|
||||
{
|
||||
initial,
|
||||
ready,
|
||||
cap1,
|
||||
cap2,
|
||||
outline1,
|
||||
close_first,
|
||||
outline2,
|
||||
out_vertices,
|
||||
end_poly1,
|
||||
end_poly2,
|
||||
stop
|
||||
};
|
||||
|
||||
public:
|
||||
typedef vertex_sequence<vertex_dist, 6> vertex_storage;
|
||||
typedef pod_bvector<point_d, 6> coord_storage;
|
||||
|
||||
vcgen_stroke();
|
||||
|
||||
void line_cap(line_cap_e lc) { m_stroker.line_cap(lc); }
|
||||
void line_join(line_join_e lj) { m_stroker.line_join(lj); }
|
||||
void inner_join(inner_join_e ij) { m_stroker.inner_join(ij); }
|
||||
|
||||
line_cap_e line_cap() const { return m_stroker.line_cap(); }
|
||||
line_join_e line_join() const { return m_stroker.line_join(); }
|
||||
inner_join_e inner_join() const { return m_stroker.inner_join(); }
|
||||
|
||||
void width(double w) { m_stroker.width(w); }
|
||||
void miter_limit(double ml) { m_stroker.miter_limit(ml); }
|
||||
void miter_limit_theta(double t) { m_stroker.miter_limit_theta(t); }
|
||||
void inner_miter_limit(double ml) { m_stroker.inner_miter_limit(ml); }
|
||||
void approximation_scale(double as) { m_stroker.approximation_scale(as); }
|
||||
|
||||
double width() const { return m_stroker.width(); }
|
||||
double miter_limit() const { return m_stroker.miter_limit(); }
|
||||
double inner_miter_limit() const { return m_stroker.inner_miter_limit(); }
|
||||
double approximation_scale() const { return m_stroker.approximation_scale(); }
|
||||
|
||||
void shorten(double s) { m_shorten = s; }
|
||||
double shorten() const { return m_shorten; }
|
||||
|
||||
// Vertex Generator Interface
|
||||
void remove_all();
|
||||
void add_vertex(double x, double y, unsigned cmd);
|
||||
|
||||
// Vertex Source Interface
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
private:
|
||||
vcgen_stroke(const vcgen_stroke&);
|
||||
const vcgen_stroke& operator = (const vcgen_stroke&);
|
||||
|
||||
math_stroke<coord_storage> m_stroker;
|
||||
vertex_storage m_src_vertices;
|
||||
coord_storage m_out_vertices;
|
||||
double m_shorten;
|
||||
unsigned m_closed;
|
||||
status_e m_status;
|
||||
status_e m_prev_status;
|
||||
unsigned m_src_vertex;
|
||||
unsigned m_out_vertex;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// vertex_sequence container and vertex_dist struct
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_VERTEX_SEQUENCE_INCLUDED
|
||||
#define AGG_VERTEX_SEQUENCE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_array.h"
|
||||
#include "agg_math.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//----------------------------------------------------------vertex_sequence
|
||||
// Modified agg::pod_bvector. The data is interpreted as a sequence
|
||||
// of vertices. It means that the type T must expose:
|
||||
//
|
||||
// bool T::operator() (const T& val)
|
||||
//
|
||||
// that is called every time new vertex is being added. The main purpose
|
||||
// of this operator is the possibility to calculate some values during
|
||||
// adding and to return true if the vertex fits some criteria or false if
|
||||
// it doesn't. In the last case the new vertex is not added.
|
||||
//
|
||||
// The simple example is filtering coinciding vertices with calculation
|
||||
// of the distance between the current and previous ones:
|
||||
//
|
||||
// struct vertex_dist
|
||||
// {
|
||||
// double x;
|
||||
// double y;
|
||||
// double dist;
|
||||
//
|
||||
// vertex_dist() {}
|
||||
// vertex_dist(double x_, double y_) :
|
||||
// x(x_),
|
||||
// y(y_),
|
||||
// dist(0.0)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// bool operator () (const vertex_dist& val)
|
||||
// {
|
||||
// return (dist = calc_distance(x, y, val.x, val.y)) > EPSILON;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// Function close() calls this operator and removes the last vertex if
|
||||
// necessary.
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S=6>
|
||||
class vertex_sequence : public pod_bvector<T, S>
|
||||
{
|
||||
public:
|
||||
typedef pod_bvector<T, S> base_type;
|
||||
|
||||
void add(const T& val);
|
||||
void modify_last(const T& val);
|
||||
void close(bool remove_flag);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::add(const T& val)
|
||||
{
|
||||
if(base_type::size() > 1)
|
||||
{
|
||||
if(!(*this)[base_type::size() - 2]((*this)[base_type::size() - 1]))
|
||||
{
|
||||
base_type::remove_last();
|
||||
}
|
||||
}
|
||||
base_type::add(val);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::modify_last(const T& val)
|
||||
{
|
||||
base_type::remove_last();
|
||||
add(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::close(bool closed)
|
||||
{
|
||||
while(base_type::size() > 1)
|
||||
{
|
||||
if((*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) break;
|
||||
T t = (*this)[base_type::size() - 1];
|
||||
base_type::remove_last();
|
||||
modify_last(t);
|
||||
}
|
||||
|
||||
if(closed)
|
||||
{
|
||||
while(base_type::size() > 1)
|
||||
{
|
||||
if((*this)[base_type::size() - 1]((*this)[0])) break;
|
||||
base_type::remove_last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------vertex_dist
|
||||
// Vertex (x, y) with the distance to the next one. The last vertex has
|
||||
// distance between the last and the first points if the polygon is closed
|
||||
// and 0.0 if it's a polyline.
|
||||
struct vertex_dist
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double dist;
|
||||
|
||||
vertex_dist() {}
|
||||
vertex_dist(double x_, double y_) :
|
||||
x(x_),
|
||||
y(y_),
|
||||
dist(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator () (const vertex_dist& val)
|
||||
{
|
||||
bool ret = (dist = calc_distance(x, y, val.x, val.y)) > vertex_dist_epsilon;
|
||||
if(!ret) dist = 1.0 / vertex_dist_epsilon;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------vertex_dist_cmd
|
||||
// Save as the above but with additional "command" value
|
||||
struct vertex_dist_cmd : public vertex_dist
|
||||
{
|
||||
unsigned cmd;
|
||||
|
||||
vertex_dist_cmd() {}
|
||||
vertex_dist_cmd(double x_, double y_, unsigned cmd_) :
|
||||
vertex_dist(x_, y_),
|
||||
cmd(cmd_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef _Painter_icpp_init_stub
|
||||
#define _Painter_icpp_init_stub
|
||||
#define BLITZ_INDEX__ F5429F8BD2A695DD5DB4F5198EB5CB4BD
|
||||
#include "PaintPainting.icpp"
|
||||
#undef BLITZ_INDEX__
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue