Code

ad1279f30dd72de9411aeff42734789e48f81a6c
[inkscape.git] / src / libnr / nr-compose-transform.cpp
1 #define __NR_COMPOSE_TRANSFORM_C__
3 /*
4  * Pixel buffer rendering library
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * This code is in public domain
10  */
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
16 #include "nr-pixops.h"
17 #include "nr-matrix.h"
19 /*#ifdef WITH_MMX
20 #ifdef __cplusplus
21 extern "C" {
22 #endif /* __cplusplus */
23 /* fixme: */
24 /*int nr_have_mmx (void);
25 #define NR_PIXOPS_MMX (1 && nr_have_mmx ())
26 #ifdef __cplusplus
27 }
28 #endif //__cplusplus
29 #endif
30 */
32 /* fixme: Implement missing (Lauris) */
33 /* fixme: PREMUL colors before calculating average (Lauris) */
35 /* Fixed point precision */
36 #define FBITS 12
37 #define FBITS_HP 18 // In some places we need a higher precision
39 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
40                                                const unsigned char *spx, int sw, int sh, int srs,
41                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
42 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
43                                                const unsigned char *spx, int sw, int sh, int srs,
44                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
45 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
46                                                const unsigned char *spx, int sw, int sh, int srs,
47                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
48 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
49                                                const unsigned char *spx, int sw, int sh, int srs,
50                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
52 void
53 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
54                                                const unsigned char *spx, int sw, int sh, int srs,
55                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
56 {
57         int xsize, ysize, size, dbits;
58         long FFs_x_x, FFs_x_y, FFs_y_x, FFs_y_y, FFs__x, FFs__y;
59         long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
60         /* Subpixel positions */
61         int FF_sx_S[256];
62         int FF_sy_S[256];
63         unsigned char *d0;
64         int FFsx0, FFsy0;
65         int x, y;
67         if (alpha == 0) return;
69         xsize = (1 << xd);
70         ysize = (1 << yd);
71         size = xsize * ysize;
72         dbits = xd + yd;
74         /* Set up fixed point matrix */
75         FFs_x_x = (long) (d2s[0] * (1 << FBITS) + 0.5);
76         FFs_x_y = (long) (d2s[1] * (1 << FBITS) + 0.5);
77         FFs_y_x = (long) (d2s[2] * (1 << FBITS) + 0.5);
78         FFs_y_y = (long) (d2s[3] * (1 << FBITS) + 0.5);
79         FFs__x = (long) (d2s[4] * (1 << FBITS) + 0.5);
80         FFs__y = (long) (d2s[5] * (1 << FBITS) + 0.5);
82         FFs_x_x_S = FFs_x_x >> xd;
83         FFs_x_y_S = FFs_x_y >> xd;
84         FFs_y_x_S = FFs_y_x >> yd;
85         FFs_y_y_S = FFs_y_y >> yd;
87         /* Set up subpixel matrix */
88         /* fixme: We can calculate that in floating point (Lauris) */
89         for (y = 0; y < ysize; y++) {
90                 for (x = 0; x < xsize; x++) {
91                         FF_sx_S[y * xsize + x] = FFs_x_x_S * x + FFs_y_x_S * y;
92                         FF_sy_S[y * xsize + x] = FFs_x_y_S * x + FFs_y_y_S * y;
93                 }
94         }
96         d0 = px;
97         FFsx0 = FFs__x;
98         FFsy0 = FFs__y;
100         for (y = 0; y < h; y++) {
101                 unsigned char *d;
102                 long FFsx, FFsy;
103                 d = d0;
104                 FFsx = FFsx0;
105                 FFsy = FFsy0;
106                 for (x = 0; x < w; x++) {
107                         unsigned int r, g, b, a;
108                         long sx, sy;
109                         int i;
110                         r = g = b = a = 0;
111                         for (i = 0; i < size; i++) {
112                                 sx = (FFsx + FF_sx_S[i]) >> FBITS;
113                                 if ((sx >= 0) && (sx < sw)) {
114                                         sy = (FFsy + FF_sy_S[i]) >> FBITS;
115                                         if ((sy >= 0) && (sy < sh)) {
116                                                 const unsigned char *s;
117                                                 unsigned int ca;
118                                                 s = spx + sy * srs + sx * 4;
119                                                 ca = NR_PREMUL_112 (s[3], alpha);
120                                                 r += NR_PREMUL_121 (s[0], ca);
121                                                 g += NR_PREMUL_121 (s[1], ca);
122                                                 b += NR_PREMUL_121 (s[2], ca);
123                                                 a += NR_NORMALIZE_21(ca);
124                                         }
125                                 }
126                         }
127                         a >>= dbits;
128                         if (a != 0) {
129                                 r = r >> dbits;
130                                 g = g >> dbits;
131                                 b = b >> dbits;
132                                 if (a == 255) {
133                                         /* Transparent BG, premul src */
134                                         d[0] = r;
135                                         d[1] = g;
136                                         d[2] = b;
137                                         d[3] = a;
138                                 } else {
139                                         unsigned int ca;
140                                         /* Full composition */
141                                         ca = NR_COMPOSEA_112(a, d[3]);
142                                         d[0] = NR_COMPOSENNN_111121 (r, a, d[0], d[3], ca);
143                                         d[1] = NR_COMPOSENNN_111121 (g, a, d[1], d[3], ca);
144                                         d[2] = NR_COMPOSENNN_111121 (b, a, d[2], d[3], ca);
145                                         d[3] = NR_NORMALIZE_21(ca);
146                                 }
147                         }
148                         /* Advance pointers */
149                         FFsx += FFs_x_x;
150                         FFsy += FFs_x_y;
151                         d += 4;
152                 }
153                 FFsx0 += FFs_y_x;
154                 FFsy0 += FFs_y_y;
155                 d0 += rs;
156         }
159 void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
160                                                     const unsigned char *spx, int sw, int sh, int srs,
161                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
163 static void
164 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs,
165                                                  const unsigned char *spx, int sw, int sh, int srs,
166                                                  const long long *FFd2s, unsigned int alpha)
168     unsigned char *d0;
169         long long FFsx0, FFsy0;
170         int x, y;
172         d0 = px;
173         FFsx0 = FFd2s[4];
174         FFsy0 = FFd2s[5];
176         for (y = 0; y < h; y++) {
177                 unsigned char *d;
178                 long long FFsx, FFsy;
179                 d = d0;
180                 FFsx = FFsx0;
181                 FFsy = FFsy0;
182                 for (x = 0; x < w; x++) {
183                         long sx, sy;
184                         sx = long(FFsx >> FBITS_HP);
185                         if ((sx >= 0) && (sx < sw)) {
186                                 sy = long(FFsy >> FBITS_HP);
187                                 if ((sy >= 0) && (sy < sh)) {
188                                         const unsigned char *s;
189                                         unsigned int a;
190                                         s = spx + sy * srs + sx * 4;
191                                         a = NR_PREMUL_112 (s[3], alpha);
192                                         if (a != 0) {
193                                                 if ((a == 255*255) || (d[3] == 0)) {
194                                                         /* Transparent BG, premul src */
195                                                         d[0] = NR_PREMUL_121 (s[0], a);
196                                                         d[1] = NR_PREMUL_121 (s[1], a);
197                                                         d[2] = NR_PREMUL_121 (s[2], a);
198                                                         d[3] = NR_NORMALIZE_21(a);
199                                                 } else {
200                                                         d[0] = NR_COMPOSENPP_1211 (s[0], a, d[0]);
201                                                         d[1] = NR_COMPOSENPP_1211 (s[1], a, d[1]);
202                                                         d[2] = NR_COMPOSENPP_1211 (s[2], a, d[2]);
203                                                         d[3] = NR_COMPOSEA_211(a, d[3]);
204                                                 }
205                                         }
206                                 }
207                         }
208                         /* Advance pointers */
209                         FFsx += FFd2s[0];
210                         FFsy += FFd2s[1];
211                         d += 4;
212                 }
213                 FFsx0 += FFd2s[2];
214                 FFsy0 += FFd2s[3];
215                 d0 += rs;
216         }
219 static void
220 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs,
221                                                  const unsigned char *spx, int sw, int sh, int srs,
222                                                  const long long *FFd2s, const long *FF_S, unsigned int alpha, int dbits)
224         int size;
225         unsigned char *d0;
226         long long FFsx0, FFsy0;
227         int x, y;
229         size = (1 << dbits);
230     unsigned alpha_rounding_fix = size * 255;
231     unsigned rgb_rounding_fix = size * (255 * 256);
232     if (alpha > 127) ++alpha;
234         d0 = px;
235         FFsx0 = FFd2s[4];
236         FFsy0 = FFd2s[5];
238         for (y = 0; y < h; y++) {
239                 unsigned char *d;
240                 long long FFsx, FFsy;
241                 d = d0;
242                 FFsx = FFsx0;
243                 FFsy = FFsy0;
244                 for (x = 0; x < w; x++) {
245                         unsigned int r, g, b, a;
246                         int i;
247                         r = g = b = a = 0;
248                         for (i = 0; i < size; i++) {
249                                 long sx, sy;
250                                 sx = (long (FFsx >> (FBITS_HP - FBITS)) + FF_S[2 * i]) >> FBITS;
251                                 if ((sx >= 0) && (sx < sw)) {
252                                         sy = (long (FFsy >> (FBITS_HP - FBITS)) + FF_S[2 * i + 1]) >> FBITS;
253                                         if ((sy >= 0) && (sy < sh)) {
254                                                 const unsigned char *s;
255                                                 unsigned int ca;
256                                                 s = spx + sy * srs + sx * 4;
257                                                 ca = NR_PREMUL_112(s[3], alpha);
258                                                 r += NR_PREMUL_123(s[0], ca);
259                                                 g += NR_PREMUL_123(s[1], ca);
260                                                 b += NR_PREMUL_123(s[2], ca);
261                                                 a += ca;
262                                         }
263                                 }
264                         }
265                         a = (a + alpha_rounding_fix) >> (8 + dbits);
266                         if (a != 0) {
267                                 r = (r + rgb_rounding_fix) >> (16 + dbits);
268                                 g = (g + rgb_rounding_fix) >> (16 + dbits);
269                                 b = (b + rgb_rounding_fix) >> (16 + dbits);
270                                 if ((a == 255) || (d[3] == 0)) {
271                                         /* Transparent BG, premul src */
272                                         d[0] = r;
273                                         d[1] = g;
274                                         d[2] = b;
275                                         d[3] = a;
276                                 } else {
277                                         d[0] = NR_COMPOSEPPP_1111 (r, a, d[0]);
278                                         d[1] = NR_COMPOSEPPP_1111 (g, a, d[1]);
279                                         d[2] = NR_COMPOSEPPP_1111 (b, a, d[2]);
280                                         d[3] = NR_COMPOSEA_111(a, d[3]);
281                                 }
282                         }
283                         /* Advance pointers */
284                         FFsx += FFd2s[0];
285                         FFsy += FFd2s[1];
286                         d += 4;
287                 }
288                 FFsx0 += FFd2s[2];
289                 FFsy0 += FFd2s[3];
290                 d0 += rs;
291         }
294 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
295                                                     const unsigned char *spx, int sw, int sh, int srs,
296                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
298         int dbits;
299         long FFd2s[6];
300         long long FFd2s_HP[6]; // with higher precision
301         int i;
303         if (alpha == 0) return;
305         dbits = xd + yd;
307         for (i = 0; i < 6; i++) {
308                 FFd2s[i] = (long) (d2s[i] * (1 << FBITS) + 0.5);
309                 FFd2s_HP[i] = (long long) (d2s[i] * (1 << FBITS_HP) + 0.5);;
310         }
312         if (dbits == 0) {
313                 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, alpha);
314         } else {
315                 int xsize, ysize;
316                 long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
317                 long FF_S[2 * 256];
318                 int x, y;
320                 xsize = (1 << xd);
321                 ysize = (1 << yd);
323                 FFs_x_x_S = FFd2s[0] >> xd;
324                 FFs_x_y_S = FFd2s[1] >> xd;
325                 FFs_y_x_S = FFd2s[2] >> yd;
326                 FFs_y_y_S = FFd2s[3] >> yd;
328                 /* Set up subpixel matrix */
329                 /* fixme: We can calculate that in floating point (Lauris) */
330                 for (y = 0; y < ysize; y++) {
331                         for (x = 0; x < xsize; x++) {
332                                 FF_S[2 * (y * xsize + x)] = FFs_x_x_S * x + FFs_y_x_S * y;
333                                 FF_S[2 * (y * xsize + x) + 1] = FFs_x_y_S * x + FFs_y_y_S * y;
334                         }
335                 }
337                 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, FF_S, alpha, dbits);
338         }
341 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
342                                                     const unsigned char *spx, int sw, int sh, int srs,
343                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);