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"
20 #ifdef WITH_MMX
21 #ifdef __cplusplus
22 extern "C" {
23 #endif /* __cplusplus */
24 /* fixme: */
25 int nr_have_mmx (void);
26 void nr_mmx_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs,
27 const unsigned char *spx, int sw, int sh, int srs,
28 const long *FFd2s, unsigned int alpha);
29 void nr_mmx_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs,
30 const unsigned char *spx, int sw, int sh, int srs,
31 const long *FFd2s, const long *FF_S, unsigned int alpha, int dbits);
32 #define NR_PIXOPS_MMX (1 && nr_have_mmx ())
33 #ifdef __cplusplus
34 }
35 #endif //__cplusplus
36 #endif
38 /* fixme: Implement missing (Lauris) */
39 /* fixme: PREMUL colors before calculating average (Lauris) */
41 /* Fixed point precision */
42 #define FBITS 12
44 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
45 const unsigned char *spx, int sw, int sh, int srs,
46 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
47 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
48 const unsigned char *spx, int sw, int sh, int srs,
49 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
50 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
51 const unsigned char *spx, int sw, int sh, int srs,
52 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
53 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_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);
57 void
58 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
59 const unsigned char *spx, int sw, int sh, int srs,
60 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
61 {
62 int xsize, ysize, size, dbits;
63 long FFs_x_x, FFs_x_y, FFs_y_x, FFs_y_y, FFs__x, FFs__y;
64 long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
65 /* Subpixel positions */
66 int FF_sx_S[256];
67 int FF_sy_S[256];
68 unsigned char *d0;
69 int FFsx0, FFsy0;
70 int x, y;
72 if (alpha == 0) return;
74 xsize = (1 << xd);
75 ysize = (1 << yd);
76 size = xsize * ysize;
77 dbits = xd + yd;
79 /* Set up fixed point matrix */
80 FFs_x_x = (long) (d2s[0] * (1 << FBITS) + 0.5);
81 FFs_x_y = (long) (d2s[1] * (1 << FBITS) + 0.5);
82 FFs_y_x = (long) (d2s[2] * (1 << FBITS) + 0.5);
83 FFs_y_y = (long) (d2s[3] * (1 << FBITS) + 0.5);
84 FFs__x = (long) (d2s[4] * (1 << FBITS) + 0.5);
85 FFs__y = (long) (d2s[5] * (1 << FBITS) + 0.5);
87 FFs_x_x_S = FFs_x_x >> xd;
88 FFs_x_y_S = FFs_x_y >> xd;
89 FFs_y_x_S = FFs_y_x >> yd;
90 FFs_y_y_S = FFs_y_y >> yd;
92 /* Set up subpixel matrix */
93 /* fixme: We can calculate that in floating point (Lauris) */
94 for (y = 0; y < ysize; y++) {
95 for (x = 0; x < xsize; x++) {
96 FF_sx_S[y * xsize + x] = FFs_x_x_S * x + FFs_y_x_S * y;
97 FF_sy_S[y * xsize + x] = FFs_x_y_S * x + FFs_y_y_S * y;
98 }
99 }
101 d0 = px;
102 FFsx0 = FFs__x;
103 FFsy0 = FFs__y;
105 for (y = 0; y < h; y++) {
106 unsigned char *d;
107 long FFsx, FFsy;
108 d = d0;
109 FFsx = FFsx0;
110 FFsy = FFsy0;
111 for (x = 0; x < w; x++) {
112 unsigned int r, g, b, a;
113 long sx, sy;
114 int i;
115 r = g = b = a = 0;
116 for (i = 0; i < size; i++) {
117 sx = (FFsx + FF_sx_S[i]) >> FBITS;
118 if ((sx >= 0) && (sx < sw)) {
119 sy = (FFsy + FF_sy_S[i]) >> FBITS;
120 if ((sy >= 0) && (sy < sh)) {
121 const unsigned char *s;
122 unsigned int ca;
123 s = spx + sy * srs + sx * 4;
124 ca = NR_PREMUL_112 (s[3], alpha);
125 r += NR_PREMUL_121 (s[0], ca);
126 g += NR_PREMUL_121 (s[1], ca);
127 b += NR_PREMUL_121 (s[2], ca);
128 a += NR_NORMALIZE_21(ca);
129 }
130 }
131 }
132 a >>= dbits;
133 if (a != 0) {
134 r = r >> dbits;
135 g = g >> dbits;
136 b = b >> dbits;
137 if (a == 255) {
138 /* Transparent BG, premul src */
139 d[0] = r;
140 d[1] = g;
141 d[2] = b;
142 d[3] = a;
143 } else {
144 unsigned int ca;
145 /* Full composition */
146 ca = NR_COMPOSEA_112(a, d[3]);
147 d[0] = NR_COMPOSENNN_111121 (r, a, d[0], d[3], ca);
148 d[1] = NR_COMPOSENNN_111121 (g, a, d[1], d[3], ca);
149 d[2] = NR_COMPOSENNN_111121 (b, a, d[2], d[3], ca);
150 d[3] = NR_NORMALIZE_21(ca);
151 }
152 }
153 /* Advance pointers */
154 FFsx += FFs_x_x;
155 FFsy += FFs_x_y;
156 d += 4;
157 }
158 FFsx0 += FFs_y_x;
159 FFsy0 += FFs_y_y;
160 d0 += rs;
161 }
162 }
164 void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
165 const unsigned char *spx, int sw, int sh, int srs,
166 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
168 static void
169 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs,
170 const unsigned char *spx, int sw, int sh, int srs,
171 const long *FFd2s, unsigned int alpha)
172 {
173 unsigned char *d0;
174 int FFsx0, FFsy0;
175 int x, y;
177 d0 = px;
178 FFsx0 = FFd2s[4];
179 FFsy0 = FFd2s[5];
181 for (y = 0; y < h; y++) {
182 unsigned char *d;
183 long FFsx, FFsy;
184 d = d0;
185 FFsx = FFsx0;
186 FFsy = FFsy0;
187 for (x = 0; x < w; x++) {
188 long sx, sy;
189 sx = FFsx >> FBITS;
190 if ((sx >= 0) && (sx < sw)) {
191 sy = FFsy >> FBITS;
192 if ((sy >= 0) && (sy < sh)) {
193 const unsigned char *s;
194 unsigned int a;
195 s = spx + sy * srs + sx * 4;
196 a = NR_PREMUL_112 (s[3], alpha);
197 if (a != 0) {
198 if ((a == 255*255) || (d[3] == 0)) {
199 /* Transparent BG, premul src */
200 d[0] = NR_PREMUL_121 (s[0], a);
201 d[1] = NR_PREMUL_121 (s[1], a);
202 d[2] = NR_PREMUL_121 (s[2], a);
203 d[3] = NR_NORMALIZE_21(a);
204 } else {
205 d[0] = NR_COMPOSENPP_1211 (s[0], a, d[0]);
206 d[1] = NR_COMPOSENPP_1211 (s[1], a, d[1]);
207 d[2] = NR_COMPOSENPP_1211 (s[2], a, d[2]);
208 d[3] = NR_COMPOSEA_211(a, d[3]);
209 }
210 }
211 }
212 }
213 /* Advance pointers */
214 FFsx += FFd2s[0];
215 FFsy += FFd2s[1];
216 d += 4;
217 }
218 FFsx0 += FFd2s[2];
219 FFsy0 += FFd2s[3];
220 d0 += rs;
221 }
222 }
224 static void
225 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs,
226 const unsigned char *spx, int sw, int sh, int srs,
227 const long *FFd2s, const long *FF_S, unsigned int alpha, int dbits)
228 {
229 int size;
230 unsigned char *d0;
231 int FFsx0, FFsy0;
232 int x, y;
234 size = (1 << dbits);
235 unsigned alpha_rounding_fix = size * 255;
236 unsigned rgb_rounding_fix = size * (255 * 256);
237 if (alpha > 127) ++alpha;
239 d0 = px;
240 FFsx0 = FFd2s[4];
241 FFsy0 = FFd2s[5];
243 for (y = 0; y < h; y++) {
244 unsigned char *d;
245 long FFsx, FFsy;
246 d = d0;
247 FFsx = FFsx0;
248 FFsy = FFsy0;
249 for (x = 0; x < w; x++) {
250 unsigned int r, g, b, a;
251 int i;
252 r = g = b = a = 0;
253 for (i = 0; i < size; i++) {
254 long sx, sy;
255 sx = (FFsx + FF_S[2 * i]) >> FBITS;
256 if ((sx >= 0) && (sx < sw)) {
257 sy = (FFsy + FF_S[2 * i + 1]) >> FBITS;
258 if ((sy >= 0) && (sy < sh)) {
259 const unsigned char *s;
260 unsigned int ca;
261 s = spx + sy * srs + sx * 4;
262 ca = NR_PREMUL_112(s[3], alpha);
263 r += NR_PREMUL_123(s[0], ca);
264 g += NR_PREMUL_123(s[1], ca);
265 b += NR_PREMUL_123(s[2], ca);
266 a += ca;
267 }
268 }
269 }
270 a = (a + alpha_rounding_fix) >> (8 + dbits);
271 if (a != 0) {
272 r = (r + rgb_rounding_fix) >> (16 + dbits);
273 g = (g + rgb_rounding_fix) >> (16 + dbits);
274 b = (b + rgb_rounding_fix) >> (16 + dbits);
275 if ((a == 255) || (d[3] == 0)) {
276 /* Transparent BG, premul src */
277 d[0] = r;
278 d[1] = g;
279 d[2] = b;
280 d[3] = a;
281 } else {
282 d[0] = NR_COMPOSEPPP_1111 (r, a, d[0]);
283 d[1] = NR_COMPOSEPPP_1111 (g, a, d[1]);
284 d[2] = NR_COMPOSEPPP_1111 (b, a, d[2]);
285 d[3] = NR_COMPOSEA_111(a, d[3]);
286 }
287 }
288 /* Advance pointers */
289 FFsx += FFd2s[0];
290 FFsy += FFd2s[1];
291 d += 4;
292 }
293 FFsx0 += FFd2s[2];
294 FFsy0 += FFd2s[3];
295 d0 += rs;
296 }
297 }
299 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
300 const unsigned char *spx, int sw, int sh, int srs,
301 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
302 {
303 int dbits;
304 long FFd2s[6];
305 int i;
307 if (alpha == 0) return;
309 dbits = xd + yd;
311 for (i = 0; i < 6; i++) {
312 FFd2s[i] = (long) (d2s[i] * (1 << FBITS) + 0.5);
313 }
315 if (dbits == 0) {
316 #ifdef WITH_MMX
317 if (NR_PIXOPS_MMX) {
318 /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */
319 nr_mmx_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s, alpha);
320 return;
321 }
322 #endif
323 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s, alpha);
324 } else {
325 int xsize, ysize;
326 long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
327 long FF_S[2 * 256];
328 int x, y;
330 xsize = (1 << xd);
331 ysize = (1 << yd);
333 FFs_x_x_S = FFd2s[0] >> xd;
334 FFs_x_y_S = FFd2s[1] >> xd;
335 FFs_y_x_S = FFd2s[2] >> yd;
336 FFs_y_y_S = FFd2s[3] >> yd;
338 /* Set up subpixel matrix */
339 /* fixme: We can calculate that in floating point (Lauris) */
340 for (y = 0; y < ysize; y++) {
341 for (x = 0; x < xsize; x++) {
342 FF_S[2 * (y * xsize + x)] = FFs_x_x_S * x + FFs_y_x_S * y;
343 FF_S[2 * (y * xsize + x) + 1] = FFs_x_y_S * x + FFs_y_y_S * y;
344 }
345 }
347 #ifdef WITH_MMX
348 if (NR_PIXOPS_MMX) {
349 /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */
350 nr_mmx_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s, FF_S, alpha, dbits);
351 return;
352 }
353 #endif
354 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s, FF_S, alpha, dbits);
355 }
356 }
358 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
359 const unsigned char *spx, int sw, int sh, int srs,
360 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);