Krita Source Code Documentation
Loading...
Searching...
No Matches
gimp_bump_map.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * gimp_bump_map contains code taken from gimp-bumpmap.c, original copyright:
5 *
6 * SPDX-FileCopyrightText: 1997 Federico Mena Quintero <federico@nuclecu.unam.mx>
7 * SPDX-FileCopyrightText: 1997-2000 Jens Lautenbacher <jtl@gimp.org>
8 * SPDX-FileCopyrightText: 2000 Sven Neumann <sven@gimp.org>
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13#include "gimp_bump_map.h"
14
15#include <QRect>
16#include "kis_pixel_selection.h"
17#include "kis_image.h"
18
19
20typedef int gint;
21typedef qint32 gint32;
22typedef bool gboolean;
23typedef quint8 guchar;
24typedef double gdouble;
25
26#define G_PI M_PI
27#define MOD(x, y) ((x) % (y))
28#define CLAMP(x, l, h) qBound(l, x, h)
29#define MAX(x,y) qMax(x,y)
30#define MIN(x,y) qMin(x,y)
31
32typedef struct
33{
34 gint lx, ly; /* X and Y components of light vector */
35 gint nz2, nzlz; /* nz^2, nz*lz */
36 gint background; /* Shade for vertical normals */
37 gdouble compensation; /* Background compensation */
38 guchar lut[256]; /* Look-up table for modes */
40
41void bumpmap_init_params (bumpmap_params_t *params, const bumpmap_vals_t &bmvals);
42
43void
44bumpmap_row (const bumpmap_vals_t &bmvals,
45 guchar *dest,
46 gint width,
47 const guchar *bm_row1,
48 const guchar *bm_row2,
49 const guchar *bm_row3,
50 bumpmap_params_t *params);
51
53
54void convertRow(quint8 *data, int width, const quint8 *lut)
55{
56 for (int i = 0; i < width; i++) {
57 *data = lut[*data];
58 data++;
59 }
60}
61
63 const QRect &selectionRect,
64 const bumpmap_vals_t &bmvals)
65{
68
69 bumpmap_params_t params;
70 bumpmap_init_params (&params, bmvals);
71
72 const QRect dataRect = kisGrowRect(selectionRect, 1);
73
74 const int dataRowSize = dataRect.width() * sizeof(quint8);
75 const int selectionRowSize = selectionRect.width() * sizeof(quint8);
76 QScopedArrayPointer<quint8> dstRow(new quint8[selectionRowSize]);
77
78 QScopedArrayPointer<quint8> bmRow1(new quint8[dataRowSize]);
79 QScopedArrayPointer<quint8> bmRow2(new quint8[dataRowSize]);
80 QScopedArrayPointer<quint8> bmRow3(new quint8[dataRowSize]);
81
82 device->readBytes(bmRow1.data(), dataRect.left(), dataRect.top(), dataRect.width(), 1);
83 device->readBytes(bmRow2.data(), dataRect.left(), dataRect.top() + 1, dataRect.width(), 1);
84 device->readBytes(bmRow3.data(), dataRect.left(), dataRect.top() + 2, dataRect.width(), 1);
85
86 convertRow(bmRow1.data(), dataRect.width(), params.lut);
87 convertRow(bmRow2.data(), dataRect.width(), params.lut);
88 convertRow(bmRow3.data(), dataRect.width(), params.lut);
89
90 for (int row = selectionRect.top();
91 row < selectionRect.top() + selectionRect.height(); row++) {
92
93 bumpmap_row (bmvals, dstRow.data(), selectionRect.width(),
94 bmRow1.data() + 1, bmRow2.data() + 1, bmRow3.data() + 1,
95 &params);
96
97 device->writeBytes(dstRow.data(), selectionRect.left(), row, selectionRect.width(), 1);
98
99 bmRow1.swap(bmRow2);
100 bmRow2.swap(bmRow3);
101
102 device->readBytes(bmRow3.data(), dataRect.left(), row + 1, dataRect.width(), 1);
103 convertRow(bmRow3.data(), dataRect.width(), params.lut);
104 }
105}
106
108{
109 /* Convert to radians */
110 const gdouble azimuth = G_PI * bmvals.azimuth / 180.0;
111 const gdouble elevation = G_PI * bmvals.elevation / 180.0;
112
113 gint lz, nz;
114 gint i;
115
116 /* Calculate the light vector */
117 params->lx = cos (azimuth) * cos (elevation) * 255.0;
118 params->ly = sin (azimuth) * cos (elevation) * 255.0;
119 lz = sin (elevation) * 255.0;
120
121 /* Calculate constant Z component of surface normal */
122 /* (depth may be 0 if non-interactive) */
123 nz = (6 * 255) / qMax (bmvals.depth, 1);
124 params->nz2 = nz * nz;
125 params->nzlz = nz * lz;
126
127 /* Optimize for vertical normals */
128 params->background = lz;
129
130 /* Calculate darkness compensation factor */
131 params->compensation = sin(elevation);
132
133 /* Create look-up table for map type */
134 for (i = 0; i < 256; i++)
135 {
136 gdouble n;
137
138 switch (bmvals.type)
139 {
140 case SPHERICAL:
141 n = i / 255.0 - 1.0;
142 params->lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5);
143 break;
144
145 case SINUSOIDAL:
146 n = i / 255.0;
147 params->lut[i] = (int) (255.0 *
148 (sin((-G_PI / 2.0) + G_PI * n) + 1.0) /
149 2.0 + 0.5);
150 break;
151
152 case LINEAR:
153 default:
154 params->lut[i] = i;
155 }
156
157 if (bmvals.invert)
158 params->lut[i] = 255 - params->lut[i];
159 }
160}
161
162void
164 guchar *dest,
165 gint width,
166 const guchar *bm_row1,
167 const guchar *bm_row2,
168 const guchar *bm_row3,
169 bumpmap_params_t *params)
170{
171 gint xofs1, xofs2;
172 gint x;
173
174 for (x = 0; x < width; x++) {
175 gint xofs3;
176 gint shade;
177 gint nx, ny;
178
179 /* Calculate surface normal from bump map */
180
181 xofs2 = x;
182 xofs1 = xofs2 - 1;
183 xofs3 = xofs2 + 1;
184
185 nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] -
186 bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]);
187 ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] -
188 bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]);
189
190 /* Shade */
191
192 if ((nx == 0) && (ny == 0)) {
193 shade = params->background;
194 } else {
195 gint ndotl = nx * params->lx + ny * params->ly + params->nzlz;
196
197 if (ndotl < 0) {
198 shade = params->compensation * bmvals.ambient;
199 } else {
200 shade = ndotl / sqrt (nx * nx + ny * ny + params->nz2);
201
202 shade = shade + MAX(0.0, (255 * params->compensation - shade)) *
203 bmvals.ambient / 255;
204 }
205 }
206
207 /* Paint */
208
209 if (bmvals.compensate) {
210 int result = shade / params->compensation;
211 *dest++ = MIN(255, result);
212 } else {
213 *dest++ = shade;
214 }
215 }
216}
217
void readBytes(quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h) const
void writeBytes(const quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h)
void bumpmap_init_params(bumpmap_params_t *params, const bumpmap_vals_t &bmvals)
#define G_PI
bool gboolean
void bumpmap(KisPixelSelectionSP device, const QRect &selectionRect, const bumpmap_vals_t &bmvals)
void bumpmap_row(const bumpmap_vals_t &bmvals, guchar *dest, gint width, const guchar *bm_row1, const guchar *bm_row2, const guchar *bm_row3, bumpmap_params_t *params)
#define MIN(x, y)
int gint
#define MAX(x, y)
quint8 guchar
double gdouble
void convertRow(quint8 *data, int width, const quint8 *lut)
qint32 gint32
@ SINUSOIDAL
@ SPHERICAL
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
@ LINEAR
Definition nugrid.h:26