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 // Both alpha and color components are stored temporarily with a range of [0,255^2], so more supersampling and we get an overflow
70 if (xd+yd>16) {
71 xd = 8;
72 yd = 8;
73 }
75 xsize = (1 << xd);
76 ysize = (1 << yd);
77 size = xsize * ysize;
78 dbits = xd + yd;
79 unsigned int rounding_fix = size/2;
81 /* Set up fixed point matrix */
82 FFs_x_x = (long) floor(d2s[0] * (1 << FBITS) + 0.5);
83 FFs_x_y = (long) floor(d2s[1] * (1 << FBITS) + 0.5);
84 FFs_y_x = (long) floor(d2s[2] * (1 << FBITS) + 0.5);
85 FFs_y_y = (long) floor(d2s[3] * (1 << FBITS) + 0.5);
86 FFs__x = (long) floor(d2s[4] * (1 << FBITS) + 0.5);
87 FFs__y = (long) floor(d2s[5] * (1 << FBITS) + 0.5);
89 FFs_x_x_S = FFs_x_x >> xd;
90 FFs_x_y_S = FFs_x_y >> xd;
91 FFs_y_x_S = FFs_y_x >> yd;
92 FFs_y_y_S = FFs_y_y >> yd;
94 /* Set up subpixel matrix */
95 /* fixme: We can calculate that in floating point (Lauris) */
96 for (y = 0; y < ysize; y++) {
97 for (x = 0; x < xsize; x++) {
98 FF_sx_S[y * xsize + x] = FFs_x_x_S * x + FFs_y_x_S * y;
99 FF_sy_S[y * xsize + x] = FFs_x_y_S * x + FFs_y_y_S * y;
100 }
101 }
103 d0 = px;
104 FFsx0 = FFs__x;
105 FFsy0 = FFs__y;
107 for (y = 0; y < h; y++) {
108 unsigned char *d;
109 long FFsx, FFsy;
110 d = d0;
111 FFsx = FFsx0;
112 FFsy = FFsy0;
113 for (x = 0; x < w; x++) {
114 unsigned int r, g, b, a;
115 long sx, sy;
116 int i;
117 r = g = b = a = 0;
118 for (i = 0; i < size; i++) {
119 sx = (FFsx + FF_sx_S[i]) >> FBITS;
120 if ((sx >= 0) && (sx < sw)) {
121 sy = (FFsy + FF_sy_S[i]) >> FBITS;
122 if ((sy >= 0) && (sy < sh)) {
123 const unsigned char *s;
124 s = spx + sy * srs + sx * 4;
125 r += NR_PREMUL_112 (s[0], s[3]);
126 g += NR_PREMUL_112 (s[1], s[3]);
127 b += NR_PREMUL_112 (s[2], s[3]);
128 a += s[3];
129 }
130 }
131 }
132 a = (a*alpha + rounding_fix) >> dbits;
133 // Compare to nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P
134 if (a != 0) {
135 r = (r + rounding_fix) >> dbits;
136 g = (g + rounding_fix) >> dbits;
137 b = (b + rounding_fix) >> dbits;
138 if (a == 255) {
139 /* Full coverage, demul src */
140 d[0] = NR_NORMALIZE_21(r);
141 d[1] = NR_NORMALIZE_21(g);
142 d[2] = NR_NORMALIZE_21(b);
143 d[3] = NR_NORMALIZE_21(a);
144 } else if (d[3] == 0) {
145 /* Only foreground, demul src */
146 d[0] = NR_DEMUL_221(r,a);
147 d[1] = NR_DEMUL_221(g,a);
148 d[2] = NR_DEMUL_221(b,a);
149 d[3] = NR_NORMALIZE_21(a);
150 } else {
151 unsigned int ca;
152 /* Full composition */
153 ca = NR_COMPOSEA_213(a, d[3]);
154 d[0] = NR_COMPOSEPNN_221131 (r, a, d[0], d[3], ca);
155 d[1] = NR_COMPOSEPNN_221131 (g, a, d[1], d[3], ca);
156 d[2] = NR_COMPOSEPNN_221131 (b, a, d[2], d[3], ca);
157 d[3] = NR_NORMALIZE_31(ca);
158 }
159 }
160 /* Advance pointers */
161 FFsx += FFs_x_x;
162 FFsy += FFs_x_y;
163 d += 4;
164 }
165 FFsx0 += FFs_y_x;
166 FFsy0 += FFs_y_y;
167 d0 += rs;
168 }
169 }
171 void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
172 const unsigned char *spx, int sw, int sh, int srs,
173 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
175 static void
176 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs,
177 const unsigned char *spx, int sw, int sh, int srs,
178 const long long *FFd2s, unsigned int alpha)
179 {
180 unsigned char *d0;
181 long long FFsx0, FFsy0;
182 int x, y;
184 d0 = px;
185 FFsx0 = FFd2s[4];
186 FFsy0 = FFd2s[5];
188 for (y = 0; y < h; y++) {
189 unsigned char *d;
190 long long FFsx, FFsy;
191 d = d0;
192 FFsx = FFsx0;
193 FFsy = FFsy0;
194 for (x = 0; x < w; x++) {
195 long sx, sy;
196 sx = long(FFsx >> FBITS_HP);
197 if ((sx >= 0) && (sx < sw)) {
198 sy = long(FFsy >> FBITS_HP);
199 if ((sy >= 0) && (sy < sh)) {
200 const unsigned char *s;
201 unsigned int a;
202 s = spx + sy * srs + sx * 4;
203 a = NR_PREMUL_112 (s[3], alpha);
204 if (a != 0) {
205 if ((a == 255*255) || (d[3] == 0)) {
206 /* Transparent BG, premul src */
207 d[0] = NR_PREMUL_121 (s[0], a);
208 d[1] = NR_PREMUL_121 (s[1], a);
209 d[2] = NR_PREMUL_121 (s[2], a);
210 d[3] = NR_NORMALIZE_21(a);
211 } else {
212 d[0] = NR_COMPOSENPP_1211 (s[0], a, d[0]);
213 d[1] = NR_COMPOSENPP_1211 (s[1], a, d[1]);
214 d[2] = NR_COMPOSENPP_1211 (s[2], a, d[2]);
215 d[3] = NR_COMPOSEA_211(a, d[3]);
216 }
217 }
218 }
219 }
220 /* Advance pointers */
221 FFsx += FFd2s[0];
222 FFsy += FFd2s[1];
223 d += 4;
224 }
225 FFsx0 += FFd2s[2];
226 FFsy0 += FFd2s[3];
227 d0 += rs;
228 }
229 }
231 static void
232 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs,
233 const unsigned char *spx, int sw, int sh, int srs,
234 const long long *FFd2s, const long *FF_S, unsigned int alpha, int dbits)
235 {
236 int size;
237 unsigned char *d0;
238 long long FFsx0, FFsy0;
239 int x, y;
241 size = (1 << dbits);
242 unsigned int rounding_fix = size/2;
244 d0 = px;
245 FFsx0 = FFd2s[4];
246 FFsy0 = FFd2s[5];
248 for (y = 0; y < h; y++) {
249 unsigned char *d;
250 long long FFsx, FFsy;
251 d = d0;
252 FFsx = FFsx0;
253 FFsy = FFsy0;
254 for (x = 0; x < w; x++) {
255 unsigned int r, g, b, a;
256 int i;
257 r = g = b = a = 0;
258 for (i = 0; i < size; i++) {
259 long sx, sy;
260 sx = (long (FFsx >> (FBITS_HP - FBITS)) + FF_S[2 * i]) >> FBITS;
261 if ((sx >= 0) && (sx < sw)) {
262 sy = (long (FFsy >> (FBITS_HP - FBITS)) + FF_S[2 * i + 1]) >> FBITS;
263 if ((sy >= 0) && (sy < sh)) {
264 const unsigned char *s;
265 s = spx + sy * srs + sx * 4;
266 r += NR_PREMUL_112(s[0], s[3]);
267 g += NR_PREMUL_112(s[1], s[3]);
268 b += NR_PREMUL_112(s[2], s[3]);
269 a += s[3];
270 }
271 }
272 }
273 a = (a*alpha + rounding_fix) >> dbits;
274 if (a != 0) {
275 r = (r + rounding_fix) >> dbits;
276 g = (g + rounding_fix) >> dbits;
277 b = (b + rounding_fix) >> dbits;
278 if ((a == 255) || (d[3] == 0)) {
279 /* Transparent BG, premul src */
280 d[0] = NR_NORMALIZE_21(r);
281 d[1] = NR_NORMALIZE_21(g);
282 d[2] = NR_NORMALIZE_21(b);
283 d[3] = NR_NORMALIZE_21(a);
284 } else {
285 d[0] = NR_COMPOSEPPP_2211 (r, a, d[0]);
286 d[1] = NR_COMPOSEPPP_2211 (g, a, d[1]);
287 d[2] = NR_COMPOSEPPP_2211 (b, a, d[2]);
288 d[3] = NR_COMPOSEA_211(a, d[3]);
289 }
290 }
291 /* Advance pointers */
292 FFsx += FFd2s[0];
293 FFsy += FFd2s[1];
294 d += 4;
295 }
296 FFsx0 += FFd2s[2];
297 FFsy0 += FFd2s[3];
298 d0 += rs;
299 }
300 }
302 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
303 const unsigned char *spx, int sw, int sh, int srs,
304 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
305 {
306 int dbits;
307 long FFd2s[6];
308 long long FFd2s_HP[6]; // with higher precision
309 int i;
311 if (alpha == 0) return;
313 // Both alpha and color components are stored temporarily with a range of [0,255^2], so more supersampling and we get an overflow
314 if (xd+yd>16) {
315 xd = 8;
316 yd = 8;
317 }
319 dbits = xd + yd;
321 for (i = 0; i < 6; i++) {
322 FFd2s[i] = (long) floor(d2s[i] * (1 << FBITS) + 0.5);
323 FFd2s_HP[i] = (long long) floor(d2s[i] * (1 << FBITS_HP) + 0.5);;
324 }
326 if (dbits == 0) {
327 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, alpha);
328 } else {
329 int xsize, ysize;
330 long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
331 long FF_S[2 * 256];
332 int x, y;
334 xsize = (1 << xd);
335 ysize = (1 << yd);
337 FFs_x_x_S = FFd2s[0] >> xd;
338 FFs_x_y_S = FFd2s[1] >> xd;
339 FFs_y_x_S = FFd2s[2] >> yd;
340 FFs_y_y_S = FFd2s[3] >> yd;
342 /* Set up subpixel matrix */
343 /* fixme: We can calculate that in floating point (Lauris) */
344 for (y = 0; y < ysize; y++) {
345 for (x = 0; x < xsize; x++) {
346 FF_S[2 * (y * xsize + x)] = FFs_x_x_S * x + FFs_y_x_S * y;
347 FF_S[2 * (y * xsize + x) + 1] = FFs_x_y_S * x + FFs_y_y_S * y;
348 }
349 }
351 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, FF_S, alpha, dbits);
352 }
353 }
355 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
356 const unsigned char *spx, int sw, int sh, int srs,
357 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);