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