-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Expand file tree
/
Copy pathagg_workaround.h
More file actions
138 lines (119 loc) · 4.57 KB
/
agg_workaround.h
File metadata and controls
138 lines (119 loc) · 4.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#ifndef MPL_AGG_WORKAROUND_H
#define MPL_AGG_WORKAROUND_H
#include "agg_pixfmt_rgba.h"
#include "agg_trans_affine.h"
/**********************************************************************
WORKAROUND: This class is to workaround a bug in Agg SVN where the
blending of RGBA32 pixels does not preserve enough precision
*/
template<class ColorT, class Order>
struct fixed_blender_rgba_plain : agg::conv_rgba_plain<ColorT, Order>
{
typedef ColorT color_type;
typedef Order order_type;
typedef typename color_type::value_type value_type;
typedef typename color_type::calc_type calc_type;
typedef typename color_type::long_type long_type;
enum base_scale_e { base_shift = color_type::base_shift };
//--------------------------------------------------------------------
static AGG_INLINE void blend_pix(value_type* p,
value_type cr, value_type cg, value_type cb, value_type alpha, agg::cover_type cover)
{
blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover));
}
//--------------------------------------------------------------------
static AGG_INLINE void blend_pix(value_type* p,
value_type cr, value_type cg, value_type cb, value_type alpha)
{
if(alpha == 0) return;
calc_type a = p[Order::A];
calc_type r = p[Order::R] * a;
calc_type g = p[Order::G] * a;
calc_type b = p[Order::B] * a;
a = ((alpha + a) << base_shift) - alpha * a;
p[Order::A] = (value_type)(a >> base_shift);
p[Order::R] = (value_type)((((cr << base_shift) - r) * alpha + (r << base_shift)) / a);
p[Order::G] = (value_type)((((cg << base_shift) - g) * alpha + (g << base_shift)) / a);
p[Order::B] = (value_type)((((cb << base_shift) - b) * alpha + (b << base_shift)) / a);
}
};
/**********************************************************************
This class provides higher-accuracy nearest-neighbor interpolation for
affine transforms than span_interpolator_linear by using
floating-point-based interpolation instead of integer-based
*/
template<class Transformer = agg::trans_affine, unsigned SubpixelShift = 8>
class accurate_interpolator_affine_nn
{
public:
typedef Transformer trans_type;
enum subpixel_scale_e
{
subpixel_shift = SubpixelShift,
subpixel_scale = 1 << subpixel_shift
};
//--------------------------------------------------------------------
accurate_interpolator_affine_nn() {}
accurate_interpolator_affine_nn(trans_type& trans) : m_trans(&trans) {}
accurate_interpolator_affine_nn(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(trans_type& trans) { m_trans = &trans; }
//----------------------------------------------------------------
void begin(double x, double y, unsigned len)
{
m_len = len - 1;
m_cur = 0;
m_stx1 = x;
m_sty1 = y;
m_trans->transform(&m_stx1, &m_sty1);
m_stx1 *= subpixel_scale;
m_sty1 *= subpixel_scale;
m_stx2 = x + m_len;
m_sty2 = y;
m_trans->transform(&m_stx2, &m_sty2);
m_stx2 *= subpixel_scale;
m_sty2 *= subpixel_scale;
}
//----------------------------------------------------------------
void resynchronize(double xe, double ye, unsigned len)
{
m_len = len - 1;
m_cur = 0;
m_trans->transform(&xe, &ye);
m_stx2 = xe * subpixel_scale;
m_sty2 = ye * subpixel_scale;
}
//----------------------------------------------------------------
void operator++()
{
m_cur++;
}
//----------------------------------------------------------------
void coordinates(int* x, int* y) const
{
// Truncate instead of round because this interpolator needs to
// match the definitions for nearest-neighbor interpolation
if (m_cur == m_len)
{
*x = int(m_stx2);
*y = int(m_sty2);
}
else
{
// Add a tiny fudge amount to account for numerical precision loss
*x = int(m_stx1 + (m_stx2 - m_stx1) * m_cur / m_len + 1e-8);
*y = int(m_sty1 + (m_sty2 - m_sty1) * m_cur / m_len + 1e-8);
}
}
private:
trans_type* m_trans;
unsigned m_len, m_cur;
double m_stx1, m_sty1, m_stx2, m_sty2;
};
#endif