5 #include "pixops-internal.h"
7 #define SUBSAMPLE_BITS 4
8 #define SUBSAMPLE (1 << SUBSAMPLE_BITS)
9 #define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1)
10 #define SCALE_SHIFT 16
12 typedef struct _PixopsFilter PixopsFilter;
23 typedef guchar *(*PixopsLineFunc) (int *weights, int n_x, int n_y,
24 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
25 guchar **src, int src_channels, gboolean src_has_alpha,
26 int x_init, int x_step, int src_width,
27 int check_size, guint32 color1, guint32 color2);
29 typedef void (*PixopsPixelFunc) (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
30 int src_has_alpha, int check_size, guint32 color1,
32 int r, int g, int b, int a);
35 get_check_shift (int check_size)
38 g_return_val_if_fail (check_size >= 0, 4);
40 while (!(check_size & 1))
50 pixops_scale_nearest (guchar *dest_buf,
57 gboolean dest_has_alpha,
58 const guchar *src_buf,
63 gboolean src_has_alpha,
69 int x_step = (1 << SCALE_SHIFT) / scale_x;
70 int y_step = (1 << SCALE_SHIFT) / scale_y;
72 #define INNER_LOOP(SRC_CHANNELS,DEST_CHANNELS) \
73 for (j=0; j < (render_x1 - render_x0); j++) \
75 const guchar *p = src + (x >> SCALE_SHIFT) * SRC_CHANNELS; \
81 if (DEST_CHANNELS == 4) \
83 if (SRC_CHANNELS == 4) \
89 dest += DEST_CHANNELS; \
93 for (i = 0; i < (render_y1 - render_y0); i++)
95 const guchar *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
96 guchar *dest = dest_buf + i * dest_rowstride;
98 x = render_x0 * x_step + x_step / 2;
100 if (src_channels == 3)
102 if (dest_channels == 3)
111 else if (src_channels == 4)
113 if (dest_channels == 3)
119 for (j=0; j < (render_x1 - render_x0); j++)
121 const guchar *p = src + (x >> SCALE_SHIFT) * 4;
124 p32 = (guint32 *) dest;
125 *p32 = *((guint32 *) p);
137 pixops_composite_nearest (guchar *dest_buf,
144 gboolean dest_has_alpha,
145 const guchar *src_buf,
150 gboolean src_has_alpha,
157 int x_step = (1 << SCALE_SHIFT) / scale_x;
158 int y_step = (1 << SCALE_SHIFT) / scale_y;
160 for (i = 0; i < (render_y1 - render_y0); i++)
162 const guchar *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
163 /* FIXME Owen needs to look at this */
164 guchar *dest = dest_buf + i * dest_rowstride;
166 x = render_x0 * x_step + x_step / 2;
168 for (j=0; j < (render_x1 - render_x0); j++)
170 const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
174 a0 = (p[3] * overall_alpha) / 0xff;
180 unsigned int w0 = 0xff * a0;
181 unsigned int w1 = (0xff - a0) * dest[3];
182 unsigned int w = w0 + w1;
186 dest[0] = (w0 * src[0] + w1 * dest[0]) / w;
187 dest[1] = (w0 * src[1] + w1 * dest[1]) / w;
188 dest[2] = (w0 * src[2] + w1 * dest[2]) / w;
201 dest[0] = (a0 * p[0] + (0xff - a0) * dest[0]) / 0xff;
202 dest[1] = (a0 * p[1] + (0xff - a0) * dest[1]) / 0xff;
203 dest[2] = (a0 * p[2] + (0xff - a0) * dest[2]) / 0xff;
205 if (dest_channels == 4)
209 dest += dest_channels;
216 pixops_composite_color_nearest (guchar *dest_buf,
223 gboolean dest_has_alpha,
224 const guchar *src_buf,
229 gboolean src_has_alpha,
241 int x_step = (1 << SCALE_SHIFT) / scale_x;
242 int y_step = (1 << SCALE_SHIFT) / scale_y;
243 int r1, g1, b1, r2, g2, b2;
244 int check_shift = get_check_shift (check_size);
246 for (i = 0; i < (render_y1 - render_y0); i++)
248 const guchar *src = src_buf + (((i + render_y0) * y_step + y_step/2) >> SCALE_SHIFT) * src_rowstride;
249 guchar *dest = dest_buf + i * dest_rowstride;
251 x = render_x0 * x_step + x_step / 2;
253 if (((i + check_y) >> check_shift) & 1)
255 r1 = (color2 & 0xff0000) >> 16;
256 g1 = (color2 & 0xff00) >> 8;
259 r2 = (color1 & 0xff0000) >> 16;
260 g2 = (color1 & 0xff00) >> 8;
265 r1 = (color1 & 0xff0000) >> 16;
266 g1 = (color1 & 0xff00) >> 8;
269 r2 = (color2 & 0xff0000) >> 16;
270 g2 = (color2 & 0xff00) >> 8;
274 for (j=0 ; j < (render_x1 - render_x0); j++)
276 const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
280 a0 = (p[3] * overall_alpha + 0xff) >> 8;
284 if (((j + check_x) >> check_shift) & 1)
286 dest[0] = r2 + ((a0 * ((int)p[0] - r2) + 0xff) >> 8);
287 dest[1] = g2 + ((a0 * ((int)p[1] - g2) + 0xff) >> 8);
288 dest[2] = b2 + ((a0 * ((int)p[2] - b2) + 0xff) >> 8);
292 dest[0] = r1 + ((a0 * ((int)p[0] - r1) + 0xff) >> 8);
293 dest[1] = g1 + ((a0 * ((int)p[1] - g1) + 0xff) >> 8);
294 dest[2] = b1 + ((a0 * ((int)p[2] - b1) + 0xff) >> 8);
297 if (dest_channels == 4)
300 dest += dest_channels;
307 composite_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
308 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
309 int r, int g, int b, int a)
313 unsigned int w0 = a - (a >> 8);
314 unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
315 unsigned int w = w0 + w1;
319 dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
320 dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
321 dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
322 dest[3] = w / 0xff00;
334 dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
335 dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
336 dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
341 composite_line (int *weights, int n_x, int n_y,
342 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
343 guchar **src, int src_channels, gboolean src_has_alpha,
344 int x_init, int x_step, int src_width,
345 int check_size, guint32 color1, guint32 color2)
350 while (dest < dest_end)
352 int x_scaled = x >> SCALE_SHIFT;
353 unsigned int r = 0, g = 0, b = 0, a = 0;
356 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
358 for (i=0; i<n_y; i++)
360 guchar *q = src[i] + x_scaled * src_channels;
361 int *line_weights = pixel_weights + n_x * i;
363 for (j=0; j<n_x; j++)
368 ta = q[3] * line_weights[j];
370 ta = 0xff * line_weights[j];
383 unsigned int w0 = a - (a >> 8);
384 unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
385 unsigned int w = w0 + w1;
389 dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
390 dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
391 dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
392 dest[3] = w / 0xff00;
404 dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
405 dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
406 dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
409 dest += dest_channels;
417 composite_line_22_4a4 (int *weights, int n_x, int n_y,
418 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
419 guchar **src, int src_channels, gboolean src_has_alpha,
420 int x_init, int x_step, int src_width,
421 int check_size, guint32 color1, guint32 color2)
424 guchar *src0 = src[0];
425 guchar *src1 = src[1];
427 g_return_val_if_fail (src_channels != 3, dest);
428 g_return_val_if_fail (src_has_alpha, dest);
430 while (dest < dest_end)
432 int x_scaled = x >> SCALE_SHIFT;
433 unsigned int r, g, b, a, ta;
438 q0 = src0 + x_scaled * 4;
439 q1 = src1 + x_scaled * 4;
441 pixel_weights = (int *)((char *)weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS - 4)) & (SUBSAMPLE_MASK << 4)));
443 w1 = pixel_weights[0];
444 w2 = pixel_weights[1];
445 w3 = pixel_weights[2];
446 w4 = pixel_weights[3];
471 dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
472 dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24;
473 dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24;
485 composite_line_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
486 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
487 guchar **src, int src_channels, gboolean src_has_alpha,
488 int x_init, int x_step, int src_width,
489 int check_size, guint32 color1, guint32 color2)
491 guint32 mmx_weights[16][8];
496 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
497 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
498 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
499 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
500 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
501 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
502 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
503 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
506 return pixops_composite_line_22_4a4_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init);
511 composite_pixel_color (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
512 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
513 int r, int g, int b, int a)
515 int dest_r, dest_g, dest_b;
516 int check_shift = get_check_shift (check_size);
518 if ((dest_x >> check_shift) & 1)
520 dest_r = (color2 & 0xff0000) >> 16;
521 dest_g = (color2 & 0xff00) >> 8;
522 dest_b = color2 & 0xff;
526 dest_r = (color1 & 0xff0000) >> 16;
527 dest_g = (color1 & 0xff00) >> 8;
528 dest_b = color1 & 0xff;
531 dest[0] = ((0xff0000 - a) * dest_r + r) >> 24;
532 dest[1] = ((0xff0000 - a) * dest_g + g) >> 24;
533 dest[2] = ((0xff0000 - a) * dest_b + b) >> 24;
537 else if (dest_channels == 4)
542 composite_line_color (int *weights, int n_x, int n_y,
543 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
544 guchar **src, int src_channels, gboolean src_has_alpha,
545 int x_init, int x_step, int src_width,
546 int check_size, guint32 color1, guint32 color2)
550 int check_shift = get_check_shift (check_size);
551 int dest_r1, dest_g1, dest_b1;
552 int dest_r2, dest_g2, dest_b2;
554 g_return_val_if_fail (check_size != 0, dest);
556 dest_r1 = (color1 & 0xff0000) >> 16;
557 dest_g1 = (color1 & 0xff00) >> 8;
558 dest_b1 = color1 & 0xff;
560 dest_r2 = (color2 & 0xff0000) >> 16;
561 dest_g2 = (color2 & 0xff00) >> 8;
562 dest_b2 = color2 & 0xff;
564 while (dest < dest_end)
566 int x_scaled = x >> SCALE_SHIFT;
567 unsigned int r = 0, g = 0, b = 0, a = 0;
570 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
572 for (i=0; i<n_y; i++)
574 guchar *q = src[i] + x_scaled * src_channels;
575 int *line_weights = pixel_weights + n_x * i;
577 for (j=0; j<n_x; j++)
582 ta = q[3] * line_weights[j];
584 ta = 0xff * line_weights[j];
595 if ((dest_x >> check_shift) & 1)
597 dest[0] = ((0xff0000 - a) * dest_r2 + r) >> 24;
598 dest[1] = ((0xff0000 - a) * dest_g2 + g) >> 24;
599 dest[2] = ((0xff0000 - a) * dest_b2 + b) >> 24;
603 dest[0] = ((0xff0000 - a) * dest_r1 + r) >> 24;
604 dest[1] = ((0xff0000 - a) * dest_g1 + g) >> 24;
605 dest[2] = ((0xff0000 - a) * dest_b1 + b) >> 24;
610 else if (dest_channels == 4)
613 dest += dest_channels;
623 composite_line_color_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
624 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
625 guchar **src, int src_channels, gboolean src_has_alpha,
626 int x_init, int x_step, int src_width,
627 int check_size, guint32 color1, guint32 color2)
629 guint32 mmx_weights[16][8];
630 int check_shift = get_check_shift (check_size);
636 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
637 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
638 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
639 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
640 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
641 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
642 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
643 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
646 colors[0] = (color1 & 0xff00) << 8 | (color1 & 0xff);
647 colors[1] = (color1 & 0xff0000) >> 16;
648 colors[2] = (color2 & 0xff00) << 8 | (color2 & 0xff);
649 colors[3] = (color2 & 0xff0000) >> 16;
651 return pixops_composite_line_color_22_4a4_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init,
652 dest_x, check_shift, colors);
657 scale_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
658 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
659 int r, int g, int b, int a)
680 dest[0] = (r + 0xffffff) >> 24;
681 dest[1] = (g + 0xffffff) >> 24;
682 dest[2] = (b + 0xffffff) >> 24;
690 scale_line (int *weights, int n_x, int n_y,
691 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
692 guchar **src, int src_channels, gboolean src_has_alpha,
693 int x_init, int x_step, int src_width,
694 int check_size, guint32 color1, guint32 color2)
699 while (dest < dest_end)
701 int x_scaled = x >> SCALE_SHIFT;
704 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
708 unsigned int r = 0, g = 0, b = 0, a = 0;
709 for (i=0; i<n_y; i++)
711 guchar *q = src[i] + x_scaled * src_channels;
712 int *line_weights = pixel_weights + n_x * i;
714 for (j=0; j<n_x; j++)
718 ta = q[3] * line_weights[j];
745 unsigned int r = 0, g = 0, b = 0;
746 for (i=0; i<n_y; i++)
748 guchar *q = src[i] + x_scaled * src_channels;
749 int *line_weights = pixel_weights + n_x * i;
751 for (j=0; j<n_x; j++)
753 unsigned int ta = line_weights[j];
763 dest[0] = (r + 0xffff) >> 16;
764 dest[1] = (g + 0xffff) >> 16;
765 dest[2] = (b + 0xffff) >> 16;
771 dest += dest_channels;
781 scale_line_22_33_mmx_stub (int *weights, int n_x, int n_y,
782 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
783 guchar **src, int src_channels, gboolean src_has_alpha,
784 int x_init, int x_step, int src_width,
785 int check_size, guint32 color1, guint32 color2)
787 guint32 mmx_weights[16][8];
792 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
793 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
794 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
795 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
796 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
797 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
798 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
799 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
802 return pixops_scale_line_22_33_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init);
807 scale_line_22_33 (int *weights, int n_x, int n_y,
808 guchar *dest, guchar *dest_end, int dest_channels, int dest_has_alpha,
809 guchar **src, int src_channels, gboolean src_has_alpha,
810 int x_init, int x_step, int src_width,
811 int check_size, guint32 color1, guint32 color2)
814 guchar *src0 = src[0];
815 guchar *src1 = src[1];
817 while (dest < dest_end)
819 unsigned int r, g, b;
820 int x_scaled = x >> SCALE_SHIFT;
825 q0 = src0 + x_scaled * 3;
826 q1 = src1 + x_scaled * 3;
828 pixel_weights = (int *)((char *)weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS - 4)) & (SUBSAMPLE_MASK << 4)));
830 w1 = pixel_weights[0];
831 w2 = pixel_weights[1];
832 w3 = pixel_weights[2];
833 w4 = pixel_weights[3];
864 process_pixel (int *weights, int n_x, int n_y,
865 guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
866 guchar **src, int src_channels, gboolean src_has_alpha,
867 int x_start, int src_width,
868 int check_size, guint32 color1, guint32 color2,
869 PixopsPixelFunc pixel_func)
871 unsigned int r = 0, g = 0, b = 0, a = 0;
874 for (i=0; i<n_y; i++)
876 int *line_weights = weights + n_x * i;
878 for (j=0; j<n_x; j++)
885 else if (x_start + j < src_width)
886 q = src[i] + (x_start + j) * src_channels;
888 q = src[i] + (src_width - 1) * src_channels;
891 ta = q[3] * line_weights[j];
893 ta = 0xff * line_weights[j];
902 (*pixel_func) (dest, dest_x, dest_channels, dest_has_alpha, src_has_alpha, check_size, color1, color2, r, g, b, a);
906 pixops_process (guchar *dest_buf,
913 gboolean dest_has_alpha,
914 const guchar *src_buf,
919 gboolean src_has_alpha,
927 PixopsFilter *filter,
928 PixopsLineFunc line_func,
929 PixopsPixelFunc pixel_func)
933 guchar **line_bufs = g_new (guchar *, filter->n_y);
935 int x_step = (1 << SCALE_SHIFT) / scale_x;
936 int y_step = (1 << SCALE_SHIFT) / scale_y;
939 int scaled_x_offset = floor (filter->x_offset * (1 << SCALE_SHIFT));
941 int run_end_index = (((src_width - filter->n_x + 1) << SCALE_SHIFT) - scaled_x_offset - 1) / x_step + 1 - render_x0;
942 int check_shift = check_size ? get_check_shift (check_size) : 0;
944 y = render_y0 * y_step + floor (filter->y_offset * (1 << SCALE_SHIFT));
945 for (i = 0; i < (render_y1 - render_y0); i++)
947 int y_start = y >> SCALE_SHIFT;
949 int *run_weights = filter->weights + ((y >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * filter->n_x * filter->n_y * SUBSAMPLE;
951 guint32 tcolor1, tcolor2;
953 guchar *outbuf = dest_buf + dest_rowstride * i;
954 guchar *outbuf_end = outbuf + dest_channels * (render_x1 - render_x0);
956 if (((i + check_y) >> check_shift) & 1)
967 for (j=0; j<filter->n_y; j++)
970 line_bufs[j] = (guchar *)src_buf;
971 else if (y_start < src_height)
972 line_bufs[j] = (guchar *)src_buf + src_rowstride * y_start;
974 line_bufs[j] = (guchar *)src_buf + src_rowstride * (src_height - 1);
980 x = render_x0 * x_step + scaled_x_offset;
981 x_start = x >> SCALE_SHIFT;
983 while (x_start < 0 && outbuf < outbuf_end)
985 process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->n_x * filter->n_y), filter->n_x, filter->n_y,
986 outbuf, dest_x, dest_channels, dest_has_alpha,
987 line_bufs, src_channels, src_has_alpha,
988 x >> SCALE_SHIFT, src_width,
989 check_size, tcolor1, tcolor2, pixel_func);
992 x_start = x >> SCALE_SHIFT;
994 outbuf += dest_channels;
997 new_outbuf = (*line_func)(run_weights, filter->n_x, filter->n_y,
999 MIN (outbuf_end, dest_buf + dest_rowstride * i + run_end_index * dest_channels),
1000 dest_channels, dest_has_alpha,
1001 line_bufs, src_channels, src_has_alpha,
1002 x, x_step, src_width, check_size, tcolor1, tcolor2);
1004 dest_x += (new_outbuf - outbuf) / dest_channels;
1006 x = dest_x * x_step + scaled_x_offset;
1007 outbuf = new_outbuf;
1009 while (outbuf < outbuf_end)
1011 process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->n_x * filter->n_y), filter->n_x, filter->n_y,
1012 outbuf, dest_x, dest_channels, dest_has_alpha,
1013 line_bufs, src_channels, src_has_alpha,
1014 x >> SCALE_SHIFT, src_width,
1015 check_size, tcolor1, tcolor2, pixel_func);
1019 outbuf += dest_channels;
1029 tile_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
1031 int i_offset, j_offset;
1033 int n_x = ceil(1/x_scale + 1);
1034 int n_y = ceil(1/y_scale + 1);
1036 filter->x_offset = 0;
1037 filter->y_offset = 0;
1040 filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
1042 for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
1043 for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
1045 int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
1046 double x = (double)j_offset / 16;
1047 double y = (double)i_offset / 16;
1050 for (i = 0; i < n_y; i++)
1057 th = MIN(i+1, y + 1/y_scale) - y;
1063 if (y + 1/y_scale > i)
1064 th = MIN(i+1, y + 1/y_scale) - i;
1069 for (j = 0; j < n_x; j++)
1074 tw = MIN(j+1, x + 1/x_scale) - x;
1080 if (x + 1/x_scale > j)
1081 tw = MIN(j+1, x + 1/x_scale) - j;
1086 *(pixel_weights + n_x * i + j) = 65536 * tw * x_scale * th * y_scale * overall_alpha;
1093 bilinear_make_fast_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
1095 int i_offset, j_offset;
1096 double *x_weights, *y_weights;
1099 if (x_scale > 1.0) /* Bilinear */
1102 filter->x_offset = 0.5 * (1/x_scale - 1);
1106 n_x = ceil(1.0 + 1.0/x_scale);
1107 filter->x_offset = 0.0;
1110 if (y_scale > 1.0) /* Bilinear */
1113 filter->y_offset = 0.5 * (1/y_scale - 1);
1117 n_y = ceil(1.0 + 1.0/y_scale);
1118 filter->y_offset = 0.0;
1123 filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
1125 x_weights = g_new (double, n_x);
1126 y_weights = g_new (double, n_y);
1128 for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
1129 for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
1131 int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
1132 double x = (double)j_offset / 16;
1133 double y = (double)i_offset / 16;
1136 if (x_scale > 1.0) /* Bilinear */
1138 for (i = 0; i < n_x; i++)
1140 x_weights[i] = ((i == 0) ? (1 - x) : x) / x_scale;
1145 for (i = 0; i < n_x; i++)
1150 x_weights[i] = MIN(i+1, x + 1/x_scale) - x;
1156 if (x + 1/x_scale > i)
1157 x_weights[i] = MIN(i+1, x + 1/x_scale) - i;
1164 if (y_scale > 1.0) /* Bilinear */
1166 for (i = 0; i < n_y; i++)
1168 y_weights[i] = ((i == 0) ? (1 - y) : y) / y_scale;
1173 for (i = 0; i < n_y; i++)
1178 y_weights[i] = MIN(i+1, y + 1/y_scale) - y;
1184 if (y + 1/y_scale > i)
1185 y_weights[i] = MIN(i+1, y + 1/y_scale) - i;
1192 for (i = 0; i < n_y; i++)
1193 for (j = 0; j < n_x; j++)
1194 *(pixel_weights + n_x * i + j) = 65536 * x_weights[j] * x_scale * y_weights[i] * y_scale * overall_alpha;
1202 bilinear_quadrant (double bx0, double bx1, double by0, double by1)
1204 double ax0, ax1, ay0, ay1;
1205 double x0, x1, y0, y1;
1217 x1 = MIN (ax1, bx1);
1227 x1 = MIN (ax1, bx1);
1238 y1 = MIN (ay1, by1);
1248 y1 = MIN (ay1, by1);
1254 return 0.25 * (x1*x1 - x0*x0) * (y1*y1 - y0*y0);
1258 bilinear_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
1260 int i_offset, j_offset;
1262 int n_x = ceil(1/x_scale + 2.0);
1263 int n_y = ceil(1/y_scale + 2.0);
1265 filter->x_offset = -1.0;
1266 filter->y_offset = -1.0;
1270 filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
1272 for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
1273 for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
1275 int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
1276 double x = (double)j_offset / 16;
1277 double y = (double)i_offset / 16;
1280 for (i = 0; i < n_y; i++)
1281 for (j = 0; j < n_x; j++)
1285 w = bilinear_quadrant (0.5 + j - (x + 1 / x_scale), 0.5 + j - x, 0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
1286 w += bilinear_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j, 0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
1287 w += bilinear_quadrant (0.5 + j - (x + 1 / x_scale), 0.5 + j - x, 1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
1288 w += bilinear_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j, 1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
1290 *(pixel_weights + n_x * i + j) = 65536 * w * x_scale * y_scale * overall_alpha;
1296 pixops_composite_color (guchar *dest_buf,
1303 gboolean dest_has_alpha,
1304 const guchar *src_buf,
1309 gboolean src_has_alpha,
1312 GdkInterpType interp_type,
1320 PixopsFilter filter;
1321 PixopsLineFunc line_func;
1324 gboolean found_mmx = pixops_have_mmx();
1327 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
1328 g_return_if_fail (!(src_channels == 3 && src_has_alpha));
1330 if (scale_x == 0 || scale_y == 0)
1333 if (!src_has_alpha && overall_alpha == 255)
1334 pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1,
1335 dest_rowstride, dest_channels, dest_has_alpha,
1336 src_buf, src_width, src_height, src_rowstride, src_channels,
1337 src_has_alpha, scale_x, scale_y, interp_type);
1339 switch (interp_type)
1341 case GDK_INTERP_NEAREST:
1342 pixops_composite_color_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1343 dest_rowstride, dest_channels, dest_has_alpha,
1344 src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha,
1345 scale_x, scale_y, overall_alpha,
1346 check_x, check_y, check_size, color1, color2);
1349 case GDK_INTERP_TILES:
1350 tile_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1353 case GDK_INTERP_BILINEAR:
1354 bilinear_make_fast_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1357 case GDK_INTERP_HYPER:
1358 bilinear_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1363 if (filter.n_x == 2 && filter.n_y == 2 &&
1364 dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha && found_mmx)
1365 line_func = composite_line_color_22_4a4_mmx_stub;
1368 line_func = composite_line_color;
1370 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1371 dest_rowstride, dest_channels, dest_has_alpha,
1372 src_buf, src_width, src_height, src_rowstride, src_channels,
1373 src_has_alpha, scale_x, scale_y, check_x, check_y, check_size, color1, color2,
1374 &filter, line_func, composite_pixel_color);
1376 g_free (filter.weights);
1380 pixops_composite (guchar *dest_buf,
1387 gboolean dest_has_alpha,
1388 const guchar *src_buf,
1393 gboolean src_has_alpha,
1396 GdkInterpType interp_type,
1399 PixopsFilter filter;
1400 PixopsLineFunc line_func;
1403 gboolean found_mmx = pixops_have_mmx();
1406 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
1407 g_return_if_fail (!(src_channels == 3 && src_has_alpha));
1409 if (scale_x == 0 || scale_y == 0)
1412 if (!src_has_alpha && overall_alpha == 255)
1413 pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1,
1414 dest_rowstride, dest_channels, dest_has_alpha,
1415 src_buf, src_width, src_height, src_rowstride, src_channels,
1416 src_has_alpha, scale_x, scale_y, interp_type);
1418 switch (interp_type)
1420 case GDK_INTERP_NEAREST:
1421 pixops_composite_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1422 dest_rowstride, dest_channels, dest_has_alpha,
1423 src_buf, src_width, src_height, src_rowstride, src_channels,
1424 src_has_alpha, scale_x, scale_y, overall_alpha);
1427 case GDK_INTERP_TILES:
1428 tile_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1431 case GDK_INTERP_BILINEAR:
1432 bilinear_make_fast_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1435 case GDK_INTERP_HYPER:
1436 bilinear_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1440 if (filter.n_x == 2 && filter.n_y == 2 &&
1441 dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha)
1445 line_func = composite_line_22_4a4_mmx_stub;
1448 line_func = composite_line_22_4a4;
1451 line_func = composite_line;
1453 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1454 dest_rowstride, dest_channels, dest_has_alpha,
1455 src_buf, src_width, src_height, src_rowstride, src_channels,
1456 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
1457 &filter, line_func, composite_pixel);
1459 g_free (filter.weights);
1463 pixops_scale (guchar *dest_buf,
1470 gboolean dest_has_alpha,
1471 const guchar *src_buf,
1476 gboolean src_has_alpha,
1479 GdkInterpType interp_type)
1481 PixopsFilter filter;
1482 PixopsLineFunc line_func;
1485 gboolean found_mmx = pixops_have_mmx();
1488 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
1489 g_return_if_fail (!(src_channels == 3 && src_has_alpha));
1490 g_return_if_fail (!(src_has_alpha && !dest_has_alpha));
1492 if (scale_x == 0 || scale_y == 0)
1495 switch (interp_type)
1497 case GDK_INTERP_NEAREST:
1498 pixops_scale_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1499 dest_rowstride, dest_channels, dest_has_alpha,
1500 src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha,
1504 case GDK_INTERP_TILES:
1505 tile_make_weights (&filter, scale_x, scale_y, 1.0);
1508 case GDK_INTERP_BILINEAR:
1509 bilinear_make_fast_weights (&filter, scale_x, scale_y, 1.0);
1512 case GDK_INTERP_HYPER:
1513 bilinear_make_weights (&filter, scale_x, scale_y, 1.0);
1518 if (filter.n_x == 2 && filter.n_y == 2 &&
1519 found_mmx && dest_channels == 3 && src_channels == 3)
1520 line_func = scale_line_22_33_mmx_stub;
1523 line_func = scale_line;
1525 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1526 dest_rowstride, dest_channels, dest_has_alpha,
1527 src_buf, src_width, src_height, src_rowstride, src_channels,
1528 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
1529 &filter, line_func, scale_pixel);
1531 g_free (filter.weights);