1 /*
2 * Copyright (c) 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <compositeops/KoVcMultiArchBuildSupport.h> //MSVC requires that Vc come first
20 #include <cmath>
21
22 #include <config-vc.h>
23 #ifdef HAVE_VC
24 #if defined(__clang__)
25 #pragma GCC diagnostic ignored "-Wundef"
26 #pragma GCC diagnostic ignored "-Wlocal-type-template-args"
27 #endif
28 #if defined _MSC_VER
29 // Lets shut up the "possible loss of data" and "forcing value to bool 'true' or 'false'
30 #pragma warning ( push )
31 #pragma warning ( disable : 4244 )
32 #pragma warning ( disable : 4800 )
33 #endif
34 #include <Vc/Vc>
35 #include <Vc/IO>
36 #if defined _MSC_VER
37 #pragma warning ( pop )
38 #endif
39 #endif
40
41 #include <QDomDocument>
42 #include <QVector>
43 #include <QPointF>
44
45 #include <KoColorSpaceConstants.h>
46
47 #include "kis_fast_math.h"
48
49 #include "kis_base_mask_generator.h"
50 #include "kis_antialiasing_fade_maker.h"
51 #include "kis_brush_mask_applicator_factories.h"
52
53 #include "kis_curve_circle_mask_generator.h"
54 #include "kis_curve_circle_mask_generator_p.h"
55 #include "kis_cubic_curve.h"
56
57
KisCurveCircleMaskGenerator(qreal diameter,qreal ratio,qreal fh,qreal fv,int spikes,const KisCubicCurve & curve,bool antialiasEdges)58 KisCurveCircleMaskGenerator::KisCurveCircleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, const KisCubicCurve &curve, bool antialiasEdges)
59 : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, CIRCLE, SoftId), d(new Private(antialiasEdges))
60 {
61 // here we set resolution for the maximum size of the brush!
62 d->curveResolution = qRound(qMax(width(), height()) * OVERSAMPLING);
63 d->curveData = curve.floatTransfer(d->curveResolution + 2);
64 d->curvePoints = curve.points();
65 setCurveString(curve.toString());
66 d->dirty = false;
67
68 setScale(1.0, 1.0);
69
70 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this));
71 }
72
KisCurveCircleMaskGenerator(const KisCurveCircleMaskGenerator & rhs)73 KisCurveCircleMaskGenerator::KisCurveCircleMaskGenerator(const KisCurveCircleMaskGenerator &rhs)
74 : KisMaskGenerator(rhs),
75 d(new Private(*rhs.d))
76 {
77 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this));
78 }
79
~KisCurveCircleMaskGenerator()80 KisCurveCircleMaskGenerator::~KisCurveCircleMaskGenerator()
81 {
82 }
83
clone() const84 KisMaskGenerator* KisCurveCircleMaskGenerator::clone() const
85 {
86 return new KisCurveCircleMaskGenerator(*this);
87 }
88
setScale(qreal scaleX,qreal scaleY)89 void KisCurveCircleMaskGenerator::setScale(qreal scaleX, qreal scaleY)
90 {
91 KisMaskGenerator::setScale(scaleX, scaleY);
92
93 qreal width = effectiveSrcWidth();
94 qreal height = effectiveSrcHeight();
95
96 d->xcoef = 2.0 / width;
97 d->ycoef = 2.0 / height;
98
99 d->fadeMaker.setSquareNormCoeffs(d->xcoef, d->ycoef);
100 }
101
shouldVectorize() const102 bool KisCurveCircleMaskGenerator::shouldVectorize() const
103 {
104 return !shouldSupersample() && spikes() == 2;
105 }
106
applicator()107 KisBrushMaskApplicatorBase* KisCurveCircleMaskGenerator::applicator()
108 {
109 return d->applicator.data();
110 }
111
value(qreal dist) const112 inline quint8 KisCurveCircleMaskGenerator::Private::value(qreal dist) const
113 {
114 qreal distance = dist * curveResolution;
115
116 quint16 alphaValue = distance;
117 qreal alphaValueF = distance - alphaValue;
118
119 qreal alpha = (
120 (1.0 - alphaValueF) * curveData.at(alphaValue) +
121 alphaValueF * curveData.at(alphaValue+1));
122
123 return (1.0 - alpha) * 255;
124 }
125
valueAt(qreal x,qreal y) const126 quint8 KisCurveCircleMaskGenerator::valueAt(qreal x, qreal y) const
127 {
128 if (isEmpty()) return 255;
129 qreal xr = x;
130 qreal yr = qAbs(y);
131 fixRotation(xr, yr);
132
133 qreal dist = norme(xr * d->xcoef, yr * d->ycoef);
134
135 quint8 value;
136 if (d->fadeMaker.needFade(dist, &value)) {
137 return value;
138 }
139
140 return d->value(dist);
141 }
142
toXML(QDomDocument & doc,QDomElement & e) const143 void KisCurveCircleMaskGenerator::toXML(QDomDocument& doc, QDomElement& e) const
144 {
145 KisMaskGenerator::toXML(doc, e);
146 e.setAttribute("softness_curve", curveString());
147 }
148
setSoftness(qreal softness)149 void KisCurveCircleMaskGenerator::setSoftness(qreal softness)
150 {
151 // performance
152 if (!d->dirty && softness == 1.0) return;
153
154 d->dirty = true;
155 KisMaskGenerator::setSoftness(softness);
156 KisCurveCircleMaskGenerator::transformCurveForSoftness(softness,d->curvePoints, d->curveResolution+2, d->curveData);
157 d->dirty = false;
158 }
159
transformCurveForSoftness(qreal softness,const QList<QPointF> & points,int curveResolution,QVector<qreal> & result)160 void KisCurveCircleMaskGenerator::transformCurveForSoftness(qreal softness,const QList<QPointF> &points, int curveResolution, QVector< qreal >& result)
161 {
162 QList<QPointF> newList = points;
163 newList.detach();
164
165 int size = newList.size();
166 if (size == 2){
167 // make place for new point in the centre
168 newList.append(newList.at(1));
169 newList[1] = (newList.at(0) + newList.at(2)) * 0.5;
170 // transoform it
171 newList[1].setY(qBound<qreal>(0.0,newList.at(1).y() * softness,1.0));
172 }else{
173 // transform all points except first and last
174 for (int i = 1; i < size-1; i++){
175 newList[i].setY(qBound<qreal>(0.0,newList.at(i).y() * softness,1.0));
176 }
177 }
178
179 // compute the data
180 KisCubicCurve curve(newList);
181 result = curve.floatTransfer( curveResolution );
182 }
183
resetMaskApplicator(bool forceScalar)184 void KisCurveCircleMaskGenerator::resetMaskApplicator(bool forceScalar)
185 {
186 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this,forceScalar));
187 }
188