1 /*
2  * Copyright (c) 2017 Wolthera van Hövell tot Westerflier <griffinvalley@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 #include "kis_convert_height_to_normal_map_filter.h"
19 #include "kis_wdg_convert_height_to_normal_map.h"
20 #include <kpluginfactory.h>
21 #include <klocalizedstring.h>
22 #include <filter/kis_filter_category_ids.h>
23 #include <filter/kis_filter_registry.h>
24 #include <filter/kis_filter_configuration.h>
25 #include "kis_lod_transform.h"
26 #include <kis_edge_detection_kernel.h>
27 
28 
29 K_PLUGIN_FACTORY_WITH_JSON(KritaConvertHeightToNormalMapFilterFactory, "kritaconvertheighttonormalmap.json", registerPlugin<KritaConvertHeightToNormalMapFilter>();)
30 
KritaConvertHeightToNormalMapFilter(QObject * parent,const QVariantList &)31 KritaConvertHeightToNormalMapFilter::KritaConvertHeightToNormalMapFilter(QObject *parent, const QVariantList &)
32 : QObject(parent)
33 {
34     KisFilterRegistry::instance()->add(KisFilterSP(new KisConvertHeightToNormalMapFilter()));
35 }
36 
~KritaConvertHeightToNormalMapFilter()37 KritaConvertHeightToNormalMapFilter::~KritaConvertHeightToNormalMapFilter()
38 {
39 }
40 
KisConvertHeightToNormalMapFilter()41 KisConvertHeightToNormalMapFilter::KisConvertHeightToNormalMapFilter(): KisFilter(id(), FiltersCategoryEdgeDetectionId, i18n("&Height to Normal Map..."))
42 {
43     setSupportsPainting(true);
44     setSupportsAdjustmentLayers(true);
45     setSupportsLevelOfDetail(true);
46     setColorSpaceIndependence(FULLY_INDEPENDENT);
47     setShowConfigurationWidget(true);
48 }
49 
processImpl(KisPaintDeviceSP device,const QRect & rect,const KisFilterConfigurationSP config,KoUpdater * progressUpdater) const50 void KisConvertHeightToNormalMapFilter::processImpl(KisPaintDeviceSP device, const QRect &rect, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const
51 {
52     Q_ASSERT(device);
53 
54     KisFilterConfigurationSP configuration = config ? config : new KisFilterConfiguration(id().id(), 1);
55 
56     KisLodTransformScalar t(device);
57 
58     QVariant value;
59     float horizontalRadius = 1.0;
60     if (configuration->getProperty("horizRadius", value)) {
61         horizontalRadius = t.scale(value.toFloat());
62     }
63     float verticalRadius = 1.0;
64     if (configuration->getProperty("vertRadius", value)) {
65         verticalRadius = t.scale(value.toFloat());
66     }
67 
68     QBitArray channelFlags;
69     if (configuration) {
70         channelFlags = configuration->channelFlags();
71     }
72 
73     KisEdgeDetectionKernel::FilterType type = KisEdgeDetectionKernel::SobelVector;
74     if (configuration->getString("type") == "prewitt") {
75         type = KisEdgeDetectionKernel::Prewit;
76     } else if (configuration->getString("type") == "simple") {
77         type = KisEdgeDetectionKernel::Simple;
78     }
79 
80     int channelToConvert = configuration->getInt("channelToConvert", 0);
81 
82     QVector<int> channelOrder(3);
83     QVector<bool> channelFlip(3);
84     channelFlip.fill(false);
85 
86 
87     int i = config->getInt("redSwizzle", 0);
88     if (i%2==1 || i==2) {
89         channelFlip[0] = true;
90     }
91     if (i==3) {
92         channelFlip[0] = false;
93     }
94     channelOrder[device->colorSpace()->channels().at(0)->displayPosition()] = qMax(i/2,0);
95 
96     i = config->getInt("greenSwizzle", 2);
97     if (i%2==1 || i==2) {
98         channelFlip[1] = true;
99     }
100     if (i==3) {
101         channelFlip[1] = false;
102     }
103     channelOrder[device->colorSpace()->channels().at(1)->displayPosition()] = qMax(i/2,0);
104     i = config->getInt("blueSwizzle", 4);
105     if (i%2==1 || i==2) {
106         channelFlip[2] = true;
107     }
108     if (i==3) {
109         channelFlip[2] = false;
110     }
111     channelOrder[device->colorSpace()->channels().at(2)->displayPosition()] = qMax(i/2,0);
112     KisEdgeDetectionKernel::convertToNormalMap(device,
113                                               rect,
114                                               horizontalRadius,
115                                               verticalRadius,
116                                               type,
117                                               channelToConvert,
118                                               channelOrder,
119                                               channelFlip,
120                                               channelFlags,
121                                               progressUpdater);
122 }
123 
defaultConfiguration() const124 KisFilterConfigurationSP KisConvertHeightToNormalMapFilter::defaultConfiguration() const
125 {
126     KisFilterConfigurationSP config = factoryConfiguration();
127     config->setProperty("horizRadius", 1);
128     config->setProperty("vertRadius", 1);
129     config->setProperty("type", "sobol");
130     config->setProperty("channelToConvert", 0);
131     config->setProperty("lockAspect", true);
132     config->setProperty("redSwizzle", KisWdgConvertHeightToNormalMap::xPlus);
133     config->setProperty("greenSwizzle", KisWdgConvertHeightToNormalMap::yPlus);
134     config->setProperty("blueSwizzle", KisWdgConvertHeightToNormalMap::zPlus);
135 
136     return config;
137 }
138 
createConfigurationWidget(QWidget * parent,const KisPaintDeviceSP dev,bool) const139 KisConfigWidget *KisConvertHeightToNormalMapFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev, bool) const
140 {
141     return new KisWdgConvertHeightToNormalMap(parent, dev->colorSpace());
142 }
143 
neededRect(const QRect & rect,const KisFilterConfigurationSP _config,int lod) const144 QRect KisConvertHeightToNormalMapFilter::neededRect(const QRect &rect, const KisFilterConfigurationSP _config, int lod) const
145 {
146     KisLodTransformScalar t(lod);
147 
148     QVariant value;
149     /**
150      * NOTE: integer division by two is done on purpose,
151      *       because the kernel size is always odd
152      */
153     const int halfWidth = _config->getProperty("horizRadius", value) ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5;
154     const int halfHeight = _config->getProperty("vertRadius", value) ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5;
155 
156     return rect.adjusted(-halfWidth * 2, -halfHeight * 2, halfWidth * 2, halfHeight * 2);
157 }
158 
changedRect(const QRect & rect,const KisFilterConfigurationSP _config,int lod) const159 QRect KisConvertHeightToNormalMapFilter::changedRect(const QRect &rect, const KisFilterConfigurationSP _config, int lod) const
160 {
161     KisLodTransformScalar t(lod);
162 
163     QVariant value;
164 
165     const int halfWidth = _config->getProperty("horizRadius", value) ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5;
166     const int halfHeight = _config->getProperty("vertRadius", value) ? KisEdgeDetectionKernel::kernelSizeFromRadius(t.scale(value.toFloat())) / 2 : 5;
167 
168     return rect.adjusted( -halfWidth, -halfHeight, halfWidth, halfHeight);
169 }
170 
171 #include "kis_convert_height_to_normal_map_filter.moc"
172