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 
21 #include <cmath>
22 
23 #include <config-vc.h>
24 #ifdef HAVE_VC
25 #if defined(__clang__)
26 #pragma GCC diagnostic ignored "-Wundef"
27 #pragma GCC diagnostic ignored "-Wlocal-type-template-args"
28 #endif
29 #if defined _MSC_VER
30 // Lets shut up the "possible loss of data" and "forcing value to bool 'true' or 'false'
31 #pragma warning ( push )
32 #pragma warning ( disable : 4244 )
33 #pragma warning ( disable : 4800 )
34 #endif
35 #include <Vc/Vc>
36 #include <Vc/IO>
37 #if defined _MSC_VER
38 #pragma warning ( pop )
39 #endif
40 #endif
41 
42 #include <QDomDocument>
43 #include <QVector>
44 #include <QPointF>
45 
46 #include <kis_fast_math.h>
47 #include "kis_antialiasing_fade_maker.h"
48 #include "kis_brush_mask_applicator_factories.h"
49 #include "kis_brush_mask_applicator_base.h"
50 
51 #include "kis_curve_rect_mask_generator.h"
52 #include "kis_curve_rect_mask_generator_p.h"
53 #include "kis_cubic_curve.h"
54 
55 
KisCurveRectangleMaskGenerator(qreal diameter,qreal ratio,qreal fh,qreal fv,int spikes,const KisCubicCurve & curve,bool antialiasEdges)56 KisCurveRectangleMaskGenerator::KisCurveRectangleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, const KisCubicCurve &curve, bool antialiasEdges)
57     : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, RECTANGLE, SoftId), d(new Private(antialiasEdges))
58 {
59     d->curveResolution = qRound( qMax(width(),height()) * OVERSAMPLING);
60     d->curveData = curve.floatTransfer( d->curveResolution + 1);
61     d->curvePoints = curve.points();
62     setCurveString(curve.toString());
63     d->dirty = false;
64 
65     setScale(1.0, 1.0);
66 
67     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveRectangleMaskGenerator, KisBrushMaskVectorApplicator> >(this));
68 }
69 
KisCurveRectangleMaskGenerator(const KisCurveRectangleMaskGenerator & rhs)70 KisCurveRectangleMaskGenerator::KisCurveRectangleMaskGenerator(const KisCurveRectangleMaskGenerator &rhs)
71     : KisMaskGenerator(rhs),
72       d(new Private(*rhs.d))
73 {
74     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveRectangleMaskGenerator, KisBrushMaskVectorApplicator> >(this));
75 }
76 
clone() const77 KisMaskGenerator* KisCurveRectangleMaskGenerator::clone() const
78 {
79     return new KisCurveRectangleMaskGenerator(*this);
80 }
81 
setScale(qreal scaleX,qreal scaleY)82 void KisCurveRectangleMaskGenerator::setScale(qreal scaleX, qreal scaleY)
83 {
84     KisMaskGenerator::setScale(scaleX, scaleY);
85 
86     qreal halfWidth = 0.5 * effectiveSrcWidth();
87     qreal halfHeight = 0.5 * effectiveSrcHeight();
88 
89     d->xcoeff = 1.0 / halfWidth;
90     d->ycoeff = 1.0 / halfHeight;
91 
92     d->fadeMaker.setLimits(halfWidth, halfHeight);
93 }
94 
~KisCurveRectangleMaskGenerator()95 KisCurveRectangleMaskGenerator::~KisCurveRectangleMaskGenerator()
96 {
97 }
98 
value(qreal xr,qreal yr) const99 quint8 KisCurveRectangleMaskGenerator::Private::value(qreal xr, qreal yr) const
100 {
101     xr = qAbs(xr) * xcoeff;
102     yr = qAbs(yr) * ycoeff;
103 
104     int sIndex = qRound(xr * (curveResolution));
105     int tIndex = qRound(yr * (curveResolution));
106 
107     int sIndexInverted = curveResolution - sIndex;
108     int tIndexInverted = curveResolution - tIndex;
109 
110     qreal blend = (curveData.at(sIndex) * (1.0 - curveData.at(sIndexInverted)) *
111                    curveData.at(tIndex) * (1.0 - curveData.at(tIndexInverted)));
112 
113     return (1.0 - blend) * 255;
114 }
115 
valueAt(qreal x,qreal y) const116 quint8 KisCurveRectangleMaskGenerator::valueAt(qreal x, qreal y) const
117 {
118     if (isEmpty()) return 255;
119     qreal xr = x;
120     qreal yr = qAbs(y);
121     fixRotation(xr, yr);
122 
123     quint8 value;
124     if (d->fadeMaker.needFade(xr, yr, &value)) {
125         return value;
126     }
127 
128     return d->value(xr, yr);
129 }
130 
toXML(QDomDocument & doc,QDomElement & e) const131 void KisCurveRectangleMaskGenerator::toXML(QDomDocument& doc, QDomElement& e) const
132 {
133     KisMaskGenerator::toXML(doc, e);
134     e.setAttribute("softness_curve", curveString());
135 }
136 
setSoftness(qreal softness)137 void KisCurveRectangleMaskGenerator::setSoftness(qreal softness)
138 {
139     // performance
140     if (!d->dirty && softness == 1.0) return;
141     d->dirty = true;
142     KisMaskGenerator::setSoftness(softness);
143     KisCurveCircleMaskGenerator::transformCurveForSoftness(softness,d->curvePoints, d->curveResolution + 1, d->curveData);
144     d->dirty = false;
145 }
146 
shouldVectorize() const147 bool KisCurveRectangleMaskGenerator::shouldVectorize() const
148 {
149     return !shouldSupersample() && spikes() == 2;
150 }
151 
applicator()152 KisBrushMaskApplicatorBase* KisCurveRectangleMaskGenerator::applicator()
153 {
154     return d->applicator.data();
155 }
156 
resetMaskApplicator(bool forceScalar)157 void KisCurveRectangleMaskGenerator::resetMaskApplicator(bool forceScalar)
158 {
159     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveRectangleMaskGenerator, KisBrushMaskVectorApplicator> >(this,forceScalar));
160 }
161 
162