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