Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_filter_weights_buffer.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#ifndef __KIS_FILTER_WEIGHTS_BUFFER_H
8#define __KIS_FILTER_WEIGHTS_BUFFER_H
9
11#include "kis_filter_strategy.h"
12#include "kis_debug.h"
13
14#ifdef SANITY_CHECKS_ENABLED
15static bool checkForAsymmetricZeros = false;
16
17#define SANITY_CENTER_POSITION() \
18 do { \
19 Q_ASSERT(scaledIter >= beginDst); \
20 Q_ASSERT(scaledIter <= endDst); \
21 \
22 if (j == centerIndex) { \
23 Q_ASSERT(scaledIter == centerSrc); \
24 } \
25 } while(0)
26
27#define SANITY_ZEROS() \
28 do { \
29 if (checkForAsymmetricZeros) { \
30 for (int j = 0; j < span; j++) { \
31 int idx2 = span - j - 1; \
32 \
33 if ((m_filterWeights[i].weight[j] && !m_filterWeights[i].weight[idx2]) || \
34 (!m_filterWeights[i].weight[j] && m_filterWeights[i].weight[idx2])) { \
35 \
36 dbgKrita << "*******"; \
37 dbgKrita << "Non-symmetric zero found:" << centerSrc; \
38 dbgKrita << "Weight" << j << ":" << m_filterWeights[i].weight[j]; \
39 dbgKrita << "Weight" << idx2 << ":" << m_filterWeights[i].weight[idx2]; \
40 qFatal("Non-symmetric zero -> fail"); \
41 } \
42 } \
43 } \
44 } while (0)
45
46#define SANITY_CHECKSUM() \
47 do { \
48 Q_ASSERT(sum == 255); \
49 } while (0)
50
51#else
52#define SANITY_CENTER_POSITION()
53#define SANITY_ZEROS()
54#define SANITY_CHECKSUM()
55#endif
56
57#ifdef DEBUG_ENABLED
58#define DEBUG_ALL() \
59 do { \
60 dbgKrita << "************** i =" << i; \
61 dbgKrita << ppVar(centerSrc); \
62 dbgKrita << ppVar(centerIndex); \
63 dbgKrita << ppVar(beginSrc) << ppVar(endSrc); \
64 dbgKrita << ppVar(beginDst) << ppVar(endDst); \
65 dbgKrita << ppVar(scaledIter) << ppVar(scaledInc); \
66 dbgKrita << ppVar(span); \
67 dbgKrita << "==="; \
68 } while (0)
69
70#define DEBUG_SAMPLE() \
71 do { \
72 dbgKrita << ppVar(scaledIter) << ppVar(t); \
73 } while (0)
74#else
75#define DEBUG_ALL() Q_UNUSED(beginDst); Q_UNUSED(endDst);
76#define DEBUG_SAMPLE()
77#endif
78
79
80
134{
135public:
138 delete[] weight;
139 }
140
141 qint16 *weight;
142 int span;
144 };
145
146public:
147 KisFilterWeightsBuffer(KisFilterStrategy *filterStrategy, qreal realScale) {
148 Q_ASSERT(realScale > 0);
149
151 m_maxSpan = 0;
153
154 KisFixedPoint supportSrc;
155 KisFixedPoint supportDst;
156
157 if (realScale < 1.0 && realScale > (1.0 / (1 << 8))) {
159 supportSrc.from256Frac(filterStrategy->intSupport(m_weightsPositionScale.toFloat()) / realScale);
160 supportDst.from256Frac(filterStrategy->intSupport(m_weightsPositionScale.toFloat()));
161
162 } else {
163 supportSrc.from256Frac(filterStrategy->intSupport(m_weightsPositionScale.toFloat()));
164 supportDst.from256Frac(filterStrategy->intSupport(m_weightsPositionScale.toFloat()));
165 }
166
167 for (int i = 0; i < 256; i++) {
168 KisFixedPoint centerSrc;
169 centerSrc.from256Frac(i);
170
171 KisFixedPoint beginDst = -supportDst;
172 KisFixedPoint endDst = supportDst;
173
174 KisFixedPoint beginSrc = -supportSrc - centerSrc / m_weightsPositionScale;
175 KisFixedPoint endSrc = supportSrc - centerSrc / m_weightsPositionScale;
176
177 int span = (2 * supportSrc).toInt() +
178 (beginSrc.isInteger() && endSrc.isInteger());
179
180 int centerIndex = -beginSrc.toInt();
181
182 m_filterWeights[i].centerIndex = centerIndex;
183 m_filterWeights[i].span = span;
184 m_filterWeights[i].weight = new qint16[span];
185 m_maxSpan = qMax(m_maxSpan, span);
186
187 // in dst coordinate system:
188 KisFixedPoint scaledIter = centerSrc + beginSrc.toInt() * m_weightsPositionScale;
190
191 DEBUG_ALL();
192
193 int sum = 0;
194 for (int j = 0; j < span; j++) {
195 int t = filterStrategy->intValueAt(scaledIter.to256Frac(), m_weightsPositionScale.toFloat());
196 m_filterWeights[i].weight[j] = t;
197 sum += t;
198
199 DEBUG_SAMPLE();
201
202 scaledIter += scaledInc;
203 }
204
205 SANITY_ZEROS();
206
207 if (sum != 255 && sum > 0) {
208 qreal fixFactor = 255.0 / sum;
209 sum = 0;
210
211 for (int j = 0; j < span; j++) {
212 int t = qRound(m_filterWeights[i].weight[j] * fixFactor);
213
214 m_filterWeights[i].weight[j] = t;
215 sum += t;
216 }
217 }
218
219 while (sum != 255) {
220 int diff = sum < 255 ? 1 : -1;
221 int index = findMaxIndex(m_filterWeights[i].weight, span);
222 m_filterWeights[i].weight[index] += diff;
223 sum += diff;
224 }
225
227 }
228 }
229
233
238 return m_filterWeights + pos.to256Frac();
239 }
240
247 int maxSpan() const {
248 return m_maxSpan;
249 }
250
259
260private:
261 int findMaxIndex(qint16 *buf, int size) {
262 int maxValue = buf[0];
263 int maxIndex = 0;
264
265 for (int i = 1; i < size; i++) {
266 if (buf[i] > maxValue) {
267 maxValue = buf[i];
268 maxIndex = i;
269 }
270 }
271
272 return maxIndex;
273 }
274
275private:
279};
280
281#endif /* __KIS_FILTER_WEIGHTS_BUFFER_H */
virtual qint32 intSupport(qreal weightsPositionScale)
virtual qint32 intValueAt(qint32 t, qreal weightsPositionScale) const
KisFilterWeightsBuffer(KisFilterStrategy *filterStrategy, qreal realScale)
int findMaxIndex(qint16 *buf, int size)
FilterWeights * weights(KisFixedPoint pos) const
KisFixedPoint weightsPositionScale() const
qreal toFloat() const
KisFixedPoint & from256Frac(qint32 v)
qint32 toInt() const
qint32 to256Frac() const
#define SANITY_ZEROS()
#define DEBUG_SAMPLE()
#define SANITY_CHECKSUM()
#define DEBUG_ALL()
#define SANITY_CENTER_POSITION()