6 #include "pixops-internal.h"
8 #define SUBSAMPLE_BITS 4
9 #define SUBSAMPLE (1 << SUBSAMPLE_BITS)
10 #define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1)
11 #define SCALE_SHIFT 16
13 typedef struct _PixopsFilter PixopsFilter;
14 typedef struct _PixopsFilterDimension PixopsFilterDimension;
16 struct _PixopsFilterDimension
25 PixopsFilterDimension x;
26 PixopsFilterDimension y;
30 typedef guchar *(*PixopsLineFunc) (int *weights, int n_x, int n_y,
31 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
32 guchar **src, int src_channels, gboolean src_has_alpha,
33 int x_init, int x_step, int src_width,
34 int check_size, guint32 color1, guint32 color2);
36 typedef void (*PixopsPixelFunc) (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
37 int src_has_alpha, int check_size, guint32 color1,
39 guint r, guint g, guint b, guint a);
42 get_check_shift (int check_size)
45 g_return_val_if_fail (check_size >= 0, 4);
47 while (!(check_size & 1))
57 pixops_scale_nearest (guchar *dest_buf,
64 gboolean dest_has_alpha,
65 const guchar *src_buf,
70 gboolean src_has_alpha,
76 int x_step = (1 << SCALE_SHIFT) / scale_x;
77 int y_step = (1 << SCALE_SHIFT) / scale_y;
79 #define INNER_LOOP(SRC_CHANNELS,DEST_CHANNELS) \
80 for (j=0; j < (render_x1 - render_x0); j++) \
82 const guchar *p = src + (x >> SCALE_SHIFT) * SRC_CHANNELS; \
88 if (DEST_CHANNELS == 4) \
90 if (SRC_CHANNELS == 4) \
96 dest += DEST_CHANNELS; \
100 for (i = 0; i < (render_y1 - render_y0); i++)
102 const guchar *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
103 guchar *dest = dest_buf + i * dest_rowstride;
105 x = render_x0 * x_step + x_step / 2;
107 if (src_channels == 3)
109 if (dest_channels == 3)
118 else if (src_channels == 4)
120 if (dest_channels == 3)
126 for (j=0; j < (render_x1 - render_x0); j++)
128 const guchar *p = src + (x >> SCALE_SHIFT) * 4;
131 p32 = (guint32 *) dest;
132 *p32 = *((guint32 *) p);
144 pixops_composite_nearest (guchar *dest_buf,
151 gboolean dest_has_alpha,
152 const guchar *src_buf,
157 gboolean src_has_alpha,
164 int x_step = (1 << SCALE_SHIFT) / scale_x;
165 int y_step = (1 << SCALE_SHIFT) / scale_y;
167 for (i = 0; i < (render_y1 - render_y0); i++)
169 const guchar *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
170 guchar *dest = dest_buf + i * dest_rowstride;
172 x = render_x0 * x_step + x_step / 2;
174 for (j=0; j < (render_x1 - render_x0); j++)
176 const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
180 a0 = (p[3] * overall_alpha) / 0xff;
198 unsigned int w0 = 0xff * a0;
199 unsigned int w1 = (0xff - a0) * dest[3];
200 unsigned int w = w0 + w1;
202 dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
203 dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
204 dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
209 unsigned int a1 = 0xff - a0;
212 tmp = a0 * p[0] + a1 * dest[0] + 0x80;
213 dest[0] = (tmp + (tmp >> 8)) >> 8;
214 tmp = a0 * p[1] + a1 * dest[1] + 0x80;
215 dest[1] = (tmp + (tmp >> 8)) >> 8;
216 tmp = a0 * p[2] + a1 * dest[2] + 0x80;
217 dest[2] = (tmp + (tmp >> 8)) >> 8;
221 dest += dest_channels;
228 pixops_composite_color_nearest (guchar *dest_buf,
235 gboolean dest_has_alpha,
236 const guchar *src_buf,
241 gboolean src_has_alpha,
253 int x_step = (1 << SCALE_SHIFT) / scale_x;
254 int y_step = (1 << SCALE_SHIFT) / scale_y;
255 int r1, g1, b1, r2, g2, b2;
256 int check_shift = get_check_shift (check_size);
258 for (i = 0; i < (render_y1 - render_y0); i++)
260 const guchar *src = src_buf + (((i + render_y0) * y_step + y_step/2) >> SCALE_SHIFT) * src_rowstride;
261 guchar *dest = dest_buf + i * dest_rowstride;
263 x = render_x0 * x_step + x_step / 2;
265 if (((i + check_y) >> check_shift) & 1)
267 r1 = (color2 & 0xff0000) >> 16;
268 g1 = (color2 & 0xff00) >> 8;
271 r2 = (color1 & 0xff0000) >> 16;
272 g2 = (color1 & 0xff00) >> 8;
277 r1 = (color1 & 0xff0000) >> 16;
278 g1 = (color1 & 0xff00) >> 8;
281 r2 = (color2 & 0xff0000) >> 16;
282 g2 = (color2 & 0xff00) >> 8;
286 for (j=0 ; j < (render_x1 - render_x0); j++)
288 const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
293 a0 = (p[3] * overall_alpha + 0xff) >> 8;
300 if (((j + check_x) >> check_shift) & 1)
319 if (((j + check_x) >> check_shift) & 1)
321 tmp = ((int) p[0] - r2) * a0;
322 dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
323 tmp = ((int) p[1] - g2) * a0;
324 dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
325 tmp = ((int) p[2] - b2) * a0;
326 dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
330 tmp = ((int) p[0] - r1) * a0;
331 dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
332 tmp = ((int) p[1] - g1) * a0;
333 dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
334 tmp = ((int) p[2] - b1) * a0;
335 dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
340 if (dest_channels == 4)
343 dest += dest_channels;
350 composite_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
351 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
352 guint r, guint g, guint b, guint a)
356 unsigned int w0 = a - (a >> 8);
357 unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
358 unsigned int w = w0 + w1;
362 dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
363 dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
364 dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
365 dest[3] = w / 0xff00;
377 dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
378 dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
379 dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
384 composite_line (int *weights, int n_x, int n_y,
385 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
386 guchar **src, int src_channels, gboolean src_has_alpha,
387 int x_init, int x_step, int src_width,
388 int check_size, guint32 color1, guint32 color2)
393 while (dest < dest_end)
395 int x_scaled = x >> SCALE_SHIFT;
396 unsigned int r = 0, g = 0, b = 0, a = 0;
399 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
401 for (i=0; i<n_y; i++)
403 guchar *q = src[i] + x_scaled * src_channels;
404 int *line_weights = pixel_weights + n_x * i;
406 for (j=0; j<n_x; j++)
411 ta = q[3] * line_weights[j];
413 ta = 0xff * line_weights[j];
426 unsigned int w0 = a - (a >> 8);
427 unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
428 unsigned int w = w0 + w1;
432 dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
433 dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
434 dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
435 dest[3] = w / 0xff00;
447 dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
448 dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
449 dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
452 dest += dest_channels;
460 composite_line_22_4a4 (int *weights, int n_x, int n_y,
461 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
462 guchar **src, int src_channels, gboolean src_has_alpha,
463 int x_init, int x_step, int src_width,
464 int check_size, guint32 color1, guint32 color2)
467 guchar *src0 = src[0];
468 guchar *src1 = src[1];
470 g_return_val_if_fail (src_channels != 3, dest);
471 g_return_val_if_fail (src_has_alpha, dest);
473 while (dest < dest_end)
475 int x_scaled = x >> SCALE_SHIFT;
476 unsigned int r, g, b, a, ta;
481 q0 = src0 + x_scaled * 4;
482 q1 = src1 + x_scaled * 4;
484 pixel_weights = (int *)((char *)weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS - 4)) & (SUBSAMPLE_MASK << 4)));
486 w1 = pixel_weights[0];
487 w2 = pixel_weights[1];
488 w3 = pixel_weights[2];
489 w4 = pixel_weights[3];
514 dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
515 dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24;
516 dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24;
528 composite_line_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
529 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
530 guchar **src, int src_channels, gboolean src_has_alpha,
531 int x_init, int x_step, int src_width,
532 int check_size, guint32 color1, guint32 color2)
534 guint32 mmx_weights[16][8];
539 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
540 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
541 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
542 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
543 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
544 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
545 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
546 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
549 return pixops_composite_line_22_4a4_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init);
554 composite_pixel_color (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
555 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
556 guint r, guint g, guint b, guint a)
558 int dest_r, dest_g, dest_b;
559 int check_shift = get_check_shift (check_size);
561 if ((dest_x >> check_shift) & 1)
563 dest_r = (color2 & 0xff0000) >> 16;
564 dest_g = (color2 & 0xff00) >> 8;
565 dest_b = color2 & 0xff;
569 dest_r = (color1 & 0xff0000) >> 16;
570 dest_g = (color1 & 0xff00) >> 8;
571 dest_b = color1 & 0xff;
574 dest[0] = ((0xff0000 - a) * dest_r + r) >> 24;
575 dest[1] = ((0xff0000 - a) * dest_g + g) >> 24;
576 dest[2] = ((0xff0000 - a) * dest_b + b) >> 24;
580 else if (dest_channels == 4)
585 composite_line_color (int *weights, int n_x, int n_y,
586 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
587 guchar **src, int src_channels, gboolean src_has_alpha,
588 int x_init, int x_step, int src_width,
589 int check_size, guint32 color1, guint32 color2)
593 int check_shift = get_check_shift (check_size);
594 int dest_r1, dest_g1, dest_b1;
595 int dest_r2, dest_g2, dest_b2;
597 g_return_val_if_fail (check_size != 0, dest);
599 dest_r1 = (color1 & 0xff0000) >> 16;
600 dest_g1 = (color1 & 0xff00) >> 8;
601 dest_b1 = color1 & 0xff;
603 dest_r2 = (color2 & 0xff0000) >> 16;
604 dest_g2 = (color2 & 0xff00) >> 8;
605 dest_b2 = color2 & 0xff;
607 while (dest < dest_end)
609 int x_scaled = x >> SCALE_SHIFT;
610 unsigned int r = 0, g = 0, b = 0, a = 0;
613 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
615 for (i=0; i<n_y; i++)
617 guchar *q = src[i] + x_scaled * src_channels;
618 int *line_weights = pixel_weights + n_x * i;
620 for (j=0; j<n_x; j++)
625 ta = q[3] * line_weights[j];
627 ta = 0xff * line_weights[j];
638 if ((dest_x >> check_shift) & 1)
640 dest[0] = ((0xff0000 - a) * dest_r2 + r) >> 24;
641 dest[1] = ((0xff0000 - a) * dest_g2 + g) >> 24;
642 dest[2] = ((0xff0000 - a) * dest_b2 + b) >> 24;
646 dest[0] = ((0xff0000 - a) * dest_r1 + r) >> 24;
647 dest[1] = ((0xff0000 - a) * dest_g1 + g) >> 24;
648 dest[2] = ((0xff0000 - a) * dest_b1 + b) >> 24;
653 else if (dest_channels == 4)
656 dest += dest_channels;
666 composite_line_color_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
667 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
668 guchar **src, int src_channels, gboolean src_has_alpha,
669 int x_init, int x_step, int src_width,
670 int check_size, guint32 color1, guint32 color2)
672 guint32 mmx_weights[16][8];
673 int check_shift = get_check_shift (check_size);
679 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
680 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
681 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
682 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
683 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
684 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
685 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
686 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
689 colors[0] = (color1 & 0xff00) << 8 | (color1 & 0xff);
690 colors[1] = (color1 & 0xff0000) >> 16;
691 colors[2] = (color2 & 0xff00) << 8 | (color2 & 0xff);
692 colors[3] = (color2 & 0xff0000) >> 16;
694 return pixops_composite_line_color_22_4a4_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init,
695 dest_x, check_shift, colors);
700 scale_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
701 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
702 guint r, guint g, guint b, guint a)
723 dest[0] = (r + 0xffffff) >> 24;
724 dest[1] = (g + 0xffffff) >> 24;
725 dest[2] = (b + 0xffffff) >> 24;
733 scale_line (int *weights, int n_x, int n_y,
734 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
735 guchar **src, int src_channels, gboolean src_has_alpha,
736 int x_init, int x_step, int src_width,
737 int check_size, guint32 color1, guint32 color2)
742 while (dest < dest_end)
744 int x_scaled = x >> SCALE_SHIFT;
747 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
751 unsigned int r = 0, g = 0, b = 0, a = 0;
752 for (i=0; i<n_y; i++)
754 guchar *q = src[i] + x_scaled * src_channels;
755 int *line_weights = pixel_weights + n_x * i;
757 for (j=0; j<n_x; j++)
761 ta = q[3] * line_weights[j];
788 unsigned int r = 0, g = 0, b = 0;
789 for (i=0; i<n_y; i++)
791 guchar *q = src[i] + x_scaled * src_channels;
792 int *line_weights = pixel_weights + n_x * i;
794 for (j=0; j<n_x; j++)
796 unsigned int ta = line_weights[j];
806 dest[0] = (r + 0xffff) >> 16;
807 dest[1] = (g + 0xffff) >> 16;
808 dest[2] = (b + 0xffff) >> 16;
814 dest += dest_channels;
824 scale_line_22_33_mmx_stub (int *weights, int n_x, int n_y,
825 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
826 guchar **src, int src_channels, gboolean src_has_alpha,
827 int x_init, int x_step, int src_width,
828 int check_size, guint32 color1, guint32 color2)
830 guint32 mmx_weights[16][8];
835 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
836 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
837 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
838 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
839 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
840 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
841 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
842 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
845 return pixops_scale_line_22_33_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init);
850 scale_line_22_33 (int *weights, int n_x, int n_y,
851 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
852 guchar **src, int src_channels, gboolean src_has_alpha,
853 int x_init, int x_step, int src_width,
854 int check_size, guint32 color1, guint32 color2)
857 guchar *src0 = src[0];
858 guchar *src1 = src[1];
860 while (dest < dest_end)
862 unsigned int r, g, b;
863 int x_scaled = x >> SCALE_SHIFT;
868 q0 = src0 + x_scaled * 3;
869 q1 = src1 + x_scaled * 3;
871 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * 4;
873 w1 = pixel_weights[0];
874 w2 = pixel_weights[1];
875 w3 = pixel_weights[2];
876 w4 = pixel_weights[3];
894 dest[0] = (r + 0x8000) >> 16;
895 dest[1] = (g + 0x8000) >> 16;
896 dest[2] = (b + 0x8000) >> 16;
906 process_pixel (int *weights, int n_x, int n_y,
907 guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
908 guchar **src, int src_channels, gboolean src_has_alpha,
909 int x_start, int src_width,
910 int check_size, guint32 color1, guint32 color2,
911 PixopsPixelFunc pixel_func)
913 unsigned int r = 0, g = 0, b = 0, a = 0;
916 for (i=0; i<n_y; i++)
918 int *line_weights = weights + n_x * i;
920 for (j=0; j<n_x; j++)
927 else if (x_start + j < src_width)
928 q = src[i] + (x_start + j) * src_channels;
930 q = src[i] + (src_width - 1) * src_channels;
933 ta = q[3] * line_weights[j];
935 ta = 0xff * line_weights[j];
944 (*pixel_func) (dest, dest_x, dest_channels, dest_has_alpha, src_has_alpha, check_size, color1, color2, r, g, b, a);
948 correct_total (int *weights,
952 double overall_alpha)
954 int correction = (int)(0.5 + 65536 * overall_alpha) - total;
955 int remaining, c, d, i;
959 remaining = correction;
960 for (d = 1, c = correction; c != 0 && remaining != 0; d++, c = correction / d)
961 for (i = n_x * n_y - 1; i >= 0 && c != 0 && remaining != 0; i--)
962 if (*(weights + i) + c >= 0)
966 if ((0 < remaining && remaining < c) ||
967 (0 > remaining && remaining > c))
974 make_filter_table (PixopsFilter *filter)
976 int i_offset, j_offset;
977 int n_x = filter->x.n;
978 int n_y = filter->y.n;
979 int *weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
981 for (i_offset=0; i_offset < SUBSAMPLE; i_offset++)
982 for (j_offset=0; j_offset < SUBSAMPLE; j_offset++)
985 int *pixel_weights = weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
989 for (i=0; i < n_y; i++)
990 for (j=0; j < n_x; j++)
992 weight = filter->x.weights[(j_offset * n_x) + j] *
993 filter->y.weights[(i_offset * n_y) + i] *
994 filter->overall_alpha * 65536 + 0.5;
996 total += (int)weight;
998 *(pixel_weights + n_x * i + j) = weight;
1001 correct_total (pixel_weights, n_x, n_y, total, filter->overall_alpha);
1008 pixops_process (guchar *dest_buf,
1015 gboolean dest_has_alpha,
1016 const guchar *src_buf,
1021 gboolean src_has_alpha,
1029 PixopsFilter *filter,
1030 PixopsLineFunc line_func,
1031 PixopsPixelFunc pixel_func)
1034 int x, y; /* X and Y position in source (fixed_point) */
1036 guchar **line_bufs = g_new (guchar *, filter->y.n);
1037 int *filter_weights = make_filter_table (filter);
1039 int x_step = (1 << SCALE_SHIFT) / scale_x; /* X step in source (fixed point) */
1040 int y_step = (1 << SCALE_SHIFT) / scale_y; /* Y step in source (fixed point) */
1042 int check_shift = check_size ? get_check_shift (check_size) : 0;
1044 int scaled_x_offset = floor (filter->x.offset * (1 << SCALE_SHIFT));
1046 /* Compute the index where we run off the end of the source buffer. The furthest
1047 * source pixel we access at index i is:
1049 * ((render_x0 + i) * x_step + scaled_x_offset) >> SCALE_SHIFT + filter->x.n - 1
1051 * So, run_end_index is the smallest i for which this pixel is src_width, i.e, for which:
1053 * (i + render_x0) * x_step >= ((src_width - filter->x.n + 1) << SCALE_SHIFT) - scaled_x_offset
1056 #define MYDIV(a,b) ((a) > 0 ? (a) / (b) : ((a) - (b) + 1) / (b)) /* Division so that -1/5 = -1 */
1058 int run_end_x = (((src_width - filter->x.n + 1) << SCALE_SHIFT) - scaled_x_offset);
1059 int run_end_index = MYDIV (run_end_x + x_step - 1, x_step) - render_x0;
1060 run_end_index = MIN (run_end_index, render_x1 - render_x0);
1062 y = render_y0 * y_step + floor (filter->y.offset * (1 << SCALE_SHIFT));
1063 for (i = 0; i < (render_y1 - render_y0); i++)
1066 int y_start = y >> SCALE_SHIFT;
1068 int *run_weights = filter_weights +
1069 ((y >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) *
1070 filter->x.n * filter->y.n * SUBSAMPLE;
1072 guint32 tcolor1, tcolor2;
1074 guchar *outbuf = dest_buf + dest_rowstride * i;
1075 guchar *outbuf_end = outbuf + dest_channels * (render_x1 - render_x0);
1077 if (((i + check_y) >> check_shift) & 1)
1088 for (j=0; j<filter->y.n; j++)
1091 line_bufs[j] = (guchar *)src_buf;
1092 else if (y_start < src_height)
1093 line_bufs[j] = (guchar *)src_buf + src_rowstride * y_start;
1095 line_bufs[j] = (guchar *)src_buf + src_rowstride * (src_height - 1);
1101 x = render_x0 * x_step + scaled_x_offset;
1102 x_start = x >> SCALE_SHIFT;
1104 while (x_start < 0 && outbuf < outbuf_end)
1106 process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->x.n * filter->y.n), filter->x.n, filter->y.n,
1107 outbuf, dest_x, dest_channels, dest_has_alpha,
1108 line_bufs, src_channels, src_has_alpha,
1109 x >> SCALE_SHIFT, src_width,
1110 check_size, tcolor1, tcolor2, pixel_func);
1113 x_start = x >> SCALE_SHIFT;
1115 outbuf += dest_channels;
1118 new_outbuf = (*line_func) (run_weights, filter->x.n, filter->y.n,
1120 dest_buf + dest_rowstride * i + run_end_index * dest_channels,
1121 dest_channels, dest_has_alpha,
1122 line_bufs, src_channels, src_has_alpha,
1123 x, x_step, src_width, check_size, tcolor1, tcolor2);
1125 dest_x += (new_outbuf - outbuf) / dest_channels;
1127 x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset;
1128 outbuf = new_outbuf;
1130 while (outbuf < outbuf_end)
1132 process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->x.n * filter->y.n), filter->x.n, filter->y.n,
1133 outbuf, dest_x, dest_channels, dest_has_alpha,
1134 line_bufs, src_channels, src_has_alpha,
1135 x >> SCALE_SHIFT, src_width,
1136 check_size, tcolor1, tcolor2, pixel_func);
1140 outbuf += dest_channels;
1147 g_free (filter_weights);
1150 /* Compute weights for reconstruction by replication followed by
1151 * sampling with a box filter
1154 tile_make_weights (PixopsFilterDimension *dim,
1157 int n = ceil (1 / scale + 1);
1158 double *pixel_weights = g_new (double, SUBSAMPLE * n);
1164 dim->weights = pixel_weights;
1166 for (offset = 0; offset < SUBSAMPLE; offset++)
1168 double x = (double)offset / SUBSAMPLE;
1169 double a = x + 1 / scale;
1171 for (i = 0; i < n; i++)
1176 *(pixel_weights++) = (MIN (i + 1, a) - x) * scale;
1178 *(pixel_weights++) = 0;
1183 *(pixel_weights++) = (MIN (i + 1, a) - i) * scale;
1185 *(pixel_weights++) = 0;
1191 /* Compute weights for a filter that, for minification
1192 * is the same as 'tiles', and for magnification, is bilinear
1193 * reconstruction followed by a sampling with a delta function.
1196 bilinear_magnify_make_weights (PixopsFilterDimension *dim,
1199 double *pixel_weights;
1204 if (scale > 1.0) /* Linear */
1207 dim->offset = 0.5 * (1 / scale - 1);
1211 n = ceil (1.0 + 1.0 / scale);
1216 dim->weights = g_new (double, SUBSAMPLE * n);
1218 pixel_weights = dim->weights;
1220 for (offset=0; offset < SUBSAMPLE; offset++)
1222 double x = (double)offset / SUBSAMPLE;
1224 if (scale > 1.0) /* Linear */
1226 for (i = 0; i < n; i++)
1227 *(pixel_weights++) = (((i == 0) ? (1 - x) : x) / scale) * scale;
1231 double a = x + 1 / scale;
1234 * ---------|--.-|----|--.-|------- SRC
1235 * ------------|---------|--------- DEST
1237 for (i = 0; i < n; i++)
1242 *(pixel_weights++) = (MIN (i + 1, a) - x) * scale;
1244 *(pixel_weights++) = 0;
1249 *(pixel_weights++) = (MIN (i + 1, a) - i) * scale;
1251 *(pixel_weights++) = 0;
1258 /* Computes the integral from b0 to b1 of
1260 * f(x) = x; 0 <= x < 1
1261 * f(x) = 0; otherwise
1263 * We combine two of these to compute the convolution of
1264 * a box filter with a triangular spike.
1267 linear_box_half (double b0, double b1)
1296 return 0.5 * (x1*x1 - x0*x0);
1299 /* Compute weights for reconstructing with bilinear
1300 * interpolation, then sampling with a box filter
1303 bilinear_box_make_weights (PixopsFilterDimension *dim,
1306 int n = ceil (1/scale + 2.0);
1307 double *pixel_weights = g_new (double, SUBSAMPLE * n);
1313 dim->weights = pixel_weights;
1315 for (offset = 0; offset < SUBSAMPLE; offset++)
1317 double x = (double)offset / SUBSAMPLE;
1318 double a = x + 1 / scale;
1320 for (i = 0; i < n; i++)
1322 w = linear_box_half (0.5 + i - a, 0.5 + i - x);
1323 w += linear_box_half (0.5 + x - i, 0.5 + a - i);
1325 *(pixel_weights++) = w * scale;
1331 make_weights (PixopsFilter *filter,
1332 PixopsInterpType interp_type,
1336 switch (interp_type)
1338 case PIXOPS_INTERP_NEAREST:
1339 g_assert_not_reached ();
1342 case PIXOPS_INTERP_TILES:
1343 tile_make_weights (&filter->x, scale_x);
1344 tile_make_weights (&filter->y, scale_y);
1347 case PIXOPS_INTERP_BILINEAR:
1348 bilinear_magnify_make_weights (&filter->x, scale_x);
1349 bilinear_magnify_make_weights (&filter->y, scale_y);
1352 case PIXOPS_INTERP_HYPER:
1353 bilinear_box_make_weights (&filter->x, scale_x);
1354 bilinear_box_make_weights (&filter->y, scale_y);
1360 _pixops_composite_color (guchar *dest_buf,
1367 gboolean dest_has_alpha,
1368 const guchar *src_buf,
1373 gboolean src_has_alpha,
1376 PixopsInterpType interp_type,
1384 PixopsFilter filter;
1385 PixopsLineFunc line_func;
1388 gboolean found_mmx = pixops_have_mmx();
1391 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
1392 g_return_if_fail (!(src_channels == 3 && src_has_alpha));
1394 if (scale_x == 0 || scale_y == 0)
1397 if (!src_has_alpha && overall_alpha == 255)
1399 _pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1,
1400 dest_rowstride, dest_channels, dest_has_alpha,
1401 src_buf, src_width, src_height, src_rowstride, src_channels,
1402 src_has_alpha, scale_x, scale_y, interp_type);
1406 if (interp_type == PIXOPS_INTERP_NEAREST)
1408 pixops_composite_color_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1409 dest_rowstride, dest_channels, dest_has_alpha,
1410 src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha,
1411 scale_x, scale_y, overall_alpha,
1412 check_x, check_y, check_size, color1, color2);
1416 filter.overall_alpha = overall_alpha / 255.;
1417 make_weights (&filter, interp_type, scale_x, scale_y);
1420 if (filter.x.n == 2 && filter.y.n == 2 &&
1421 dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha && found_mmx)
1422 line_func = composite_line_color_22_4a4_mmx_stub;
1425 line_func = composite_line_color;
1427 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1428 dest_rowstride, dest_channels, dest_has_alpha,
1429 src_buf, src_width, src_height, src_rowstride, src_channels,
1430 src_has_alpha, scale_x, scale_y, check_x, check_y, check_size, color1, color2,
1431 &filter, line_func, composite_pixel_color);
1433 g_free (filter.x.weights);
1434 g_free (filter.y.weights);
1438 * _pixops_composite:
1439 * @dest_buf: pointer to location to store result
1440 * @render_x0: x0 of region of scaled source to store into @dest_buf
1441 * @render_y0: y0 of region of scaled source to store into @dest_buf
1442 * @render_x1: x1 of region of scaled source to store into @dest_buf
1443 * @render_y1: y1 of region of scaled source to store into @dest_buf
1444 * @dest_rowstride: rowstride of @dest_buf
1445 * @dest_channels: number of channels in @dest_buf
1446 * @dest_has_alpha: whether @dest_buf has alpha
1447 * @src_buf: pointer to source pixels
1448 * @src_width: width of source (used for clipping)
1449 * @src_height: height of source (used for clipping)
1450 * @src_rowstride: rowstride of source
1451 * @src_channels: number of channels in @src_buf
1452 * @src_has_alpha: whether @src_buf has alpha
1453 * @scale_x: amount to scale source by in X direction
1454 * @scale_y: amount to scale source by in Y direction
1455 * @interp_type: type of enumeration
1456 * @overall_alpha: overall alpha factor to multiply source by
1458 * Scale source buffer by scale_x / scale_y, then composite a given rectangle
1459 * of the result into the destination buffer.
1462 _pixops_composite (guchar *dest_buf,
1469 gboolean dest_has_alpha,
1470 const guchar *src_buf,
1475 gboolean src_has_alpha,
1478 PixopsInterpType 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));
1491 if (scale_x == 0 || scale_y == 0)
1494 if (!src_has_alpha && overall_alpha == 255)
1496 _pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1,
1497 dest_rowstride, dest_channels, dest_has_alpha,
1498 src_buf, src_width, src_height, src_rowstride, src_channels,
1499 src_has_alpha, scale_x, scale_y, interp_type);
1503 if (interp_type == PIXOPS_INTERP_NEAREST)
1505 pixops_composite_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1506 dest_rowstride, dest_channels, dest_has_alpha,
1507 src_buf, src_width, src_height, src_rowstride, src_channels,
1508 src_has_alpha, scale_x, scale_y, overall_alpha);
1512 filter.overall_alpha = overall_alpha / 255.;
1513 make_weights (&filter, interp_type, scale_x, scale_y);
1515 if (filter.x.n == 2 && filter.y.n == 2 &&
1516 dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha)
1520 line_func = composite_line_22_4a4_mmx_stub;
1523 line_func = composite_line_22_4a4;
1526 line_func = composite_line;
1528 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1529 dest_rowstride, dest_channels, dest_has_alpha,
1530 src_buf, src_width, src_height, src_rowstride, src_channels,
1531 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
1532 &filter, line_func, composite_pixel);
1534 g_free (filter.x.weights);
1535 g_free (filter.y.weights);
1539 _pixops_scale (guchar *dest_buf,
1546 gboolean dest_has_alpha,
1547 const guchar *src_buf,
1552 gboolean src_has_alpha,
1555 PixopsInterpType interp_type)
1557 PixopsFilter filter;
1558 PixopsLineFunc line_func;
1561 gboolean found_mmx = pixops_have_mmx();
1564 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
1565 g_return_if_fail (!(src_channels == 3 && src_has_alpha));
1566 g_return_if_fail (!(src_has_alpha && !dest_has_alpha));
1568 if (scale_x == 0 || scale_y == 0)
1571 if (interp_type == PIXOPS_INTERP_NEAREST)
1573 pixops_scale_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1574 dest_rowstride, dest_channels, dest_has_alpha,
1575 src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha,
1580 filter.overall_alpha = 1.0;
1581 make_weights (&filter, interp_type, scale_x, scale_y);
1583 if (filter.x.n == 2 && filter.y.n == 2 && dest_channels == 3 && src_channels == 3)
1587 line_func = scale_line_22_33_mmx_stub;
1590 line_func = scale_line_22_33;
1593 line_func = scale_line;
1595 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1596 dest_rowstride, dest_channels, dest_has_alpha,
1597 src_buf, src_width, src_height, src_rowstride, src_channels,
1598 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
1599 &filter, line_func, scale_pixel);
1601 g_free (filter.x.weights);
1602 g_free (filter.y.weights);