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 }
157 }
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)
167 {
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 }
217 }
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)
223 {
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 }
292 }
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)
297 {
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 }
339 }
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);