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;
24 typedef art_u8 *(*PixopsLineFunc) (int *weights, int n_x, int n_y,
25 art_u8 *dest, int dest_x, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
26 art_u8 **src, int src_channels, art_boolean src_has_alpha,
27 int x_init, int x_step, int src_width,
28 int check_size, art_u32 color1, art_u32 color2);
30 typedef void (*PixopsPixelFunc) (art_u8 *dest, int dest_x, int dest_channels, int dest_has_alpha,
31 int src_has_alpha, int check_size, art_u32 color1,
33 int r, int g, int b, int a);
36 get_check_shift (int check_size)
39 g_return_val_if_fail (check_size >= 0, 4);
41 while (!(check_size & 1))
51 pixops_scale_nearest (art_u8 *dest_buf,
58 art_boolean dest_has_alpha,
64 art_boolean src_has_alpha,
70 int x_step = (1 << SCALE_SHIFT) / scale_x;
71 int y_step = (1 << SCALE_SHIFT) / scale_y;
73 #define INNER_LOOP(SRC_CHANNELS,DEST_CHANNELS) \
74 for (j=0; j < (render_x1 - render_x0); j++) \
76 art_u8 *p = src + (x >> SCALE_SHIFT) * SRC_CHANNELS; \
82 if (DEST_CHANNELS == 4) \
84 if (SRC_CHANNELS == 4) \
90 dest += DEST_CHANNELS; \
94 for (i = 0; i < (render_y1 - render_y0); i++)
96 art_u8 *src = src_buf + ((i * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
97 art_u8 *dest = dest_buf + i * dest_rowstride;
99 x = render_x0 * x_step + x_step / 2;
101 if (src_channels == 3)
103 if (dest_channels == 3)
112 else if (src_channels == 4)
114 if (dest_channels == 3)
120 for (j=0; j < (render_x1 - render_x0); j++)
122 art_u8 *p = src + (x >> SCALE_SHIFT) * 4;
124 *(art_u32 *)dest = *(art_u32 *)p;
136 pixops_composite_nearest (art_u8 *dest_buf,
143 art_boolean dest_has_alpha,
149 art_boolean src_has_alpha,
156 int x_step = (1 << SCALE_SHIFT) / scale_x;
157 int y_step = (1 << SCALE_SHIFT) / scale_y;
159 for (i = 0; i < (render_y1 - render_y0); i++)
161 art_u8 *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
162 art_u8 *dest = dest_buf + i * dest_rowstride + render_x0 * dest_channels;
164 x = render_x0 * x_step + x_step / 2;
166 for (j=0; j < (render_x1 - render_x0); j++)
168 art_u8 *p = src + (x >> SCALE_SHIFT) * src_channels;
172 a0 = (p[3] * overall_alpha + 0xff) >> 8;
178 unsigned int a1 = dest[3];
179 unsigned int total = a0 + a1;
183 dest[0] = (a0 * src[0] + a1 * dest[0]) / (total);
184 dest[1] = (a0 * src[1] + a1 * dest[1]) / (total);
185 dest[2] = (a0 * src[2] + a1 * dest[2]) / (total);
186 dest[3] = total - ((a0 * a1 + 0xff) >> 8);
198 dest[0] = dest[0] + ((a0 * (p[0] - dest[0]) + 0xff) >> 8);
199 dest[1] = dest[1] + ((a0 * (p[1] - dest[1]) + 0xff) >> 8);
200 dest[2] = dest[2] + ((a0 * (p[2] - dest[2]) + 0xff) >> 8);
202 if (dest_channels == 4)
206 dest += dest_channels;
213 pixops_composite_color_nearest (art_u8 *dest_buf,
220 art_boolean dest_has_alpha,
226 art_boolean src_has_alpha,
238 int x_step = (1 << SCALE_SHIFT) / scale_x;
239 int y_step = (1 << SCALE_SHIFT) / scale_y;
240 int r1, g1, b1, r2, g2, b2;
241 int check_shift = get_check_shift (check_size);
243 for (i = 0; i < (render_y1 - render_y0); i++)
245 art_u8 *src = src_buf + (((i + render_y0) * y_step + y_step/2) >> SCALE_SHIFT) * src_rowstride;
246 art_u8 *dest = dest_buf + i * dest_rowstride;
248 x = render_x0 * x_step + x_step / 2;
250 if (((i + check_y) >> check_shift) & 1)
252 r1 = color2 & 0xff0000 >> 16;
253 g1 = color2 & 0xff00 >> 8;
256 r2 = color1 & 0xff0000 >> 16;
257 g2 = color1 & 0xff00 >> 8;
262 r1 = color1 & 0xff0000 >> 16;
263 g1 = color1 & 0xff00 >> 8;
266 r2 = color2 & 0xff0000 >> 16;
267 g2 = color2 & 0xff00 >> 8;
271 for (j=0 ; j < (render_x1 - render_x0); j++)
273 art_u8 *p = src + (x >> SCALE_SHIFT) * src_channels;
277 a0 = (p[3] * overall_alpha + 0xff) >> 8;
281 if (((j + check_x) >> check_shift) & 1)
283 dest[0] = r2 + ((a0 * ((int)p[0] - r2) + 0xff) >> 8);
284 dest[1] = g2 + ((a0 * ((int)p[1] - g2) + 0xff) >> 8);
285 dest[2] = b2 + ((a0 * ((int)p[2] - b2) + 0xff) >> 8);
289 dest[0] = r1 + ((a0 * ((int)p[0] - r1) + 0xff) >> 8);
290 dest[1] = g1 + ((a0 * ((int)p[1] - g1) + 0xff) >> 8);
291 dest[2] = b1 + ((a0 * ((int)p[2] - b1) + 0xff) >> 8);
294 if (dest_channels == 4)
297 dest += dest_channels;
304 composite_pixel (art_u8 *dest, int dest_x, int dest_channels, int dest_has_alpha,
305 int src_has_alpha, int check_size, art_u32 color1, art_u32 color2,
306 int r, int g, int b, int a)
310 unsigned int w = (((1 << 16) - a) * dest[3]) >> 8;
311 unsigned int total = a + w;
315 dest[0] = (r + w * dest[0]) / total;
316 dest[1] = (g + w * dest[1]) / total;
317 dest[2] = (b + w * dest[2]) / total;
318 dest[3] = (r * w) >> 16;
330 dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
331 dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24;
332 dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24;
337 composite_line (int *weights, int n_x, int n_y,
338 art_u8 *dest, int dest_x, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
339 art_u8 **src, int src_channels, art_boolean src_has_alpha,
340 int x_init, int x_step, int src_width,
341 int check_size, art_u32 color1, art_u32 color2)
346 while (dest < dest_end)
348 int x_scaled = x >> SCALE_SHIFT;
349 unsigned int r = 0, g = 0, b = 0, a = 0;
352 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
354 for (i=0; i<n_y; i++)
356 art_u8 *q = src[i] + x_scaled * src_channels;
357 int *line_weights = pixel_weights + n_x * i;
359 for (j=0; j<n_x; j++)
364 ta = q[3] * line_weights[j];
366 ta = 0xff * line_weights[j];
379 unsigned int w = (((1 << 16) - a) * dest[3]) >> 8;
380 unsigned int total = a + w;
384 dest[0] = (r + w * dest[0]) / total;
385 dest[1] = (r + w * dest[1]) / total;
386 dest[2] = (r + w * dest[2]) / total;
387 dest[3] = (r * w) >> 16;
399 dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
400 dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24;
401 dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24;
404 dest += dest_channels;
412 composite_line_22_4a4 (int *weights, int n_x, int n_y,
413 art_u8 *dest, int dest_x, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
414 art_u8 **src, int src_channels, art_boolean src_has_alpha,
415 int x_init, int x_step, int src_width,
416 int check_size, art_u32 color1, art_u32 color2)
419 art_u8 *src0 = src[0];
420 art_u8 *src1 = src[1];
422 g_return_val_if_fail (src_channels != 3, dest);
423 g_return_val_if_fail (src_has_alpha, dest);
425 while (dest < dest_end)
427 int x_scaled = x >> SCALE_SHIFT;
428 unsigned int r, g, b, a, ta;
433 q0 = src0 + x_scaled * 4;
434 q1 = src1 + x_scaled * 4;
436 pixel_weights = (int *)((char *)weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS - 4)) & (SUBSAMPLE_MASK << 4)));
438 w1 = pixel_weights[0];
439 w2 = pixel_weights[1];
440 w3 = pixel_weights[2];
441 w4 = pixel_weights[3];
466 dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
467 dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24;
468 dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24;
480 composite_line_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
481 art_u8 *dest, int dest_x, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
482 art_u8 **src, int src_channels, art_boolean src_has_alpha,
483 int x_init, int x_step, int src_width,
484 int check_size, art_u32 color1, art_u32 color2)
486 art_u32 mmx_weights[16][8];
491 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
492 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
493 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
494 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
495 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
496 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
497 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
498 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
501 return pixops_composite_line_22_4a4_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init);
506 composite_pixel_color (art_u8 *dest, int dest_x, int dest_channels, int dest_has_alpha,
507 int src_has_alpha, int check_size, art_u32 color1, art_u32 color2,
508 int r, int g, int b, int a)
510 int dest_r, dest_g, dest_b;
511 int check_shift = get_check_shift (check_size);
513 if ((dest_x >> check_shift) & 1)
515 dest_r = color2 & 0xff0000 >> 16;
516 dest_g = color2 & 0xff00 >> 8;
517 dest_b = color2 & 0xff;
521 dest_r = color1 & 0xff0000 >> 16;
522 dest_g = color1 & 0xff00 >> 8;
523 dest_b = color1 & 0xff;
526 dest[0] = ((0xff0000 - a) * dest_r + r) >> 24;
527 dest[1] = ((0xff0000 - a) * dest_g + g) >> 24;
528 dest[2] = ((0xff0000 - a) * dest_b + b) >> 24;
532 else if (dest_channels == 4)
537 composite_line_color (int *weights, int n_x, int n_y,
538 art_u8 *dest, int dest_x, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
539 art_u8 **src, int src_channels, art_boolean src_has_alpha,
540 int x_init, int x_step, int src_width,
541 int check_size, art_u32 color1, art_u32 color2)
545 int check_shift = get_check_shift (check_size);
546 int dest_r1, dest_g1, dest_b1;
547 int dest_r2, dest_g2, dest_b2;
549 g_return_val_if_fail (check_size != 0, dest);
551 dest_r1 = color1 & 0xff0000 >> 16;
552 dest_g1 = color1 & 0xff00 >> 8;
553 dest_b1 = color1 & 0xff;
555 dest_r2 = color2 & 0xff0000 >> 16;
556 dest_g2 = color2 & 0xff00 >> 8;
557 dest_b2 = color2 & 0xff;
559 while (dest < dest_end)
561 int x_scaled = x >> SCALE_SHIFT;
562 unsigned int r = 0, g = 0, b = 0, a = 0;
565 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
567 for (i=0; i<n_y; i++)
569 art_u8 *q = src[i] + x_scaled * src_channels;
570 int *line_weights = pixel_weights + n_x * i;
572 for (j=0; j<n_x; j++)
577 ta = q[3] * line_weights[j];
579 ta = 0xff * line_weights[j];
590 if ((dest_x >> check_shift) & 1)
592 dest[0] = ((0xff0000 - a) * dest_r2 + r) >> 24;
593 dest[1] = ((0xff0000 - a) * dest_g2 + g) >> 24;
594 dest[2] = ((0xff0000 - a) * dest_b2 + b) >> 24;
598 dest[0] = ((0xff0000 - a) * dest_r1 + r) >> 24;
599 dest[1] = ((0xff0000 - a) * dest_g1 + g) >> 24;
600 dest[2] = ((0xff0000 - a) * dest_b1 + b) >> 24;
605 else if (dest_channels == 4)
608 dest += dest_channels;
618 composite_line_color_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
619 art_u8 *dest, int dest_x, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
620 art_u8 **src, int src_channels, art_boolean src_has_alpha,
621 int x_init, int x_step, int src_width,
622 int check_size, art_u32 color1, art_u32 color2)
624 art_u32 mmx_weights[16][8];
625 int check_shift = get_check_shift (check_size);
631 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
632 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
633 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
634 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
635 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
636 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
637 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
638 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
641 colors[0] = (color1 & 0xff00) << 8 | (color1 & 0xff);
642 colors[1] = (color1 & 0xff0000) >> 16;
643 colors[2] = (color2 & 0xff00) << 8 | (color2 & 0xff);
644 colors[3] = (color2 & 0xff0000) >> 16;
646 return pixops_composite_line_color_22_4a4_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init,
647 dest_x, check_shift, colors);
652 scale_pixel (art_u8 *dest, int dest_x, int dest_channels, int dest_has_alpha,
653 int src_has_alpha, int check_size, art_u32 color1, art_u32 color2,
654 int r, int g, int b, int a)
685 scale_line (int *weights, int n_x, int n_y,
686 art_u8 *dest, int dest_x, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
687 art_u8 **src, int src_channels, art_boolean src_has_alpha,
688 int x_init, int x_step, int src_width,
689 int check_size, art_u32 color1, art_u32 color2)
694 while (dest < dest_end)
696 int x_scaled = x >> SCALE_SHIFT;
699 pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
703 unsigned int r = 0, g = 0, b = 0, a = 0;
704 for (i=0; i<n_y; i++)
706 art_u8 *q = src[i] + x_scaled * src_channels;
707 int *line_weights = pixel_weights + n_x * i;
709 for (j=0; j<n_x; j++)
713 ta = q[3] * line_weights[j];
740 unsigned int r = 0, g = 0, b = 0;
741 for (i=0; i<n_y; i++)
743 art_u8 *q = src[i] + x_scaled * src_channels;
744 int *line_weights = pixel_weights + n_x * i;
746 for (j=0; j<n_x; j++)
748 unsigned int ta = line_weights[j];
766 dest += dest_channels;
776 scale_line_22_33_mmx_stub (int *weights, int n_x, int n_y,
777 art_u8 *dest, int dest_x, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
778 art_u8 **src, int src_channels, art_boolean src_has_alpha,
779 int x_init, int x_step, int src_width,
780 int check_size, art_u32 color1, art_u32 color2)
782 art_u32 mmx_weights[16][8];
787 mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
788 mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
789 mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
790 mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
791 mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
792 mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
793 mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
794 mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
797 return pixops_scale_line_22_33_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init);
802 scale_line_22_33 (int *weights, int n_x, int n_y,
803 art_u8 *dest, art_u8 *dest_end, int dest_channels, int dest_has_alpha,
804 art_u8 **src, int src_channels, art_boolean src_has_alpha,
805 int x_init, int x_step, int src_width,
806 int check_size, art_u32 color1, art_u32 color2)
809 art_u8 *src0 = src[0];
810 art_u8 *src1 = src[1];
812 while (dest < dest_end)
814 unsigned int r, g, b;
815 int x_scaled = x >> SCALE_SHIFT;
820 q0 = src0 + x_scaled * 3;
821 q1 = src1 + x_scaled * 3;
823 pixel_weights = (int *)((char *)weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS - 4)) & (SUBSAMPLE_MASK << 4)));
825 w1 = pixel_weights[0];
826 w2 = pixel_weights[1];
827 w3 = pixel_weights[2];
828 w4 = pixel_weights[3];
859 process_pixel (int *weights, int n_x, int n_y,
860 art_u8 *dest, int dest_x, int dest_channels, int dest_has_alpha,
861 art_u8 **src, int src_channels, art_boolean src_has_alpha,
862 int x_start, int src_width,
863 int check_size, art_u32 color1, art_u32 color2,
864 PixopsPixelFunc pixel_func)
866 unsigned int r = 0, g = 0, b = 0, a = 0;
869 for (i=0; i<n_y; i++)
871 int *line_weights = weights + n_x * i;
873 for (j=0; j<n_x; j++)
880 else if (x_start + j < src_width)
881 q = src[i] + (x_start + j) * src_channels;
883 q = src[i] + (src_width - 1) * src_channels;
886 ta = q[3] * line_weights[j];
888 ta = 0xff * line_weights[j];
897 (*pixel_func) (dest, dest_x, dest_channels, dest_has_alpha, src_has_alpha, check_size, color1, color2, r, g, b, a);
901 pixops_process (art_u8 *dest_buf,
908 art_boolean dest_has_alpha,
914 art_boolean src_has_alpha,
922 PixopsFilter *filter,
923 PixopsLineFunc line_func,
924 PixopsPixelFunc pixel_func)
928 art_u8 **line_bufs = g_new (art_u8 *, filter->n_y);
930 int x_step = (1 << SCALE_SHIFT) / scale_x;
931 int y_step = (1 << SCALE_SHIFT) / scale_y;
934 int scaled_x_offset = floor (filter->x_offset * (1 << SCALE_SHIFT));
936 int run_end_index = (((src_width - filter->n_x + 1) << SCALE_SHIFT) - scaled_x_offset - 1) / x_step + 1 - render_x0;
937 int check_shift = check_size ? get_check_shift (check_size) : 0;
939 y = render_y0 * y_step + floor (filter->y_offset * (1 << SCALE_SHIFT));
940 for (i = 0; i < (render_y1 - render_y0); i++)
942 int y_start = y >> SCALE_SHIFT;
944 int *run_weights = filter->weights + ((y >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * filter->n_x * filter->n_y * SUBSAMPLE;
946 art_u32 tcolor1, tcolor2;
948 art_u8 *outbuf = dest_buf + dest_rowstride * i;
949 art_u8 *outbuf_end = outbuf + dest_channels * (render_x1 - render_x0);
951 if (((i + check_y) >> check_shift) & 1)
962 for (j=0; j<filter->n_y; j++)
965 line_bufs[j] = src_buf;
966 else if (y_start < src_height)
967 line_bufs[j] = src_buf + src_rowstride * y_start;
969 line_bufs[j] = src_buf + src_rowstride * (src_height - 1);
975 x = render_x0 * x_step + scaled_x_offset;
976 x_start = x >> SCALE_SHIFT;
978 while (x_start < 0 && outbuf < outbuf_end)
980 process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->n_x * filter->n_y), filter->n_x, filter->n_y,
981 outbuf, dest_x, dest_channels, dest_has_alpha,
982 line_bufs, src_channels, src_has_alpha,
983 x >> SCALE_SHIFT, src_width,
984 check_size, tcolor1, tcolor2, pixel_func);
987 x_start = x >> SCALE_SHIFT;
989 outbuf += dest_channels;
992 new_outbuf = (*line_func)(run_weights, filter->n_x, filter->n_y,
994 MIN (outbuf_end, dest_buf + dest_rowstride * i + run_end_index * dest_channels),
995 dest_channels, dest_has_alpha,
996 line_bufs, src_channels, src_has_alpha,
997 x, x_step, src_width, check_size, tcolor1, tcolor2);
999 dest_x += (new_outbuf - outbuf) / dest_channels;
1001 x = dest_x * x_step + scaled_x_offset;
1002 outbuf = new_outbuf;
1004 while (outbuf < outbuf_end)
1006 process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->n_x * filter->n_y), filter->n_x, filter->n_y,
1007 outbuf, dest_x, dest_channels, dest_has_alpha,
1008 line_bufs, src_channels, src_has_alpha,
1009 x >> SCALE_SHIFT, src_width,
1010 check_size, tcolor1, tcolor2, pixel_func);
1014 outbuf += dest_channels;
1024 tile_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
1026 int i_offset, j_offset;
1028 int n_x = ceil(1/x_scale + 1);
1029 int n_y = ceil(1/y_scale + 1);
1031 filter->x_offset = 0;
1032 filter->y_offset = 0;
1035 filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
1037 for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
1038 for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
1040 int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
1041 double x = (double)j_offset / 16;
1042 double y = (double)i_offset / 16;
1045 for (i = 0; i < n_y; i++)
1052 th = MIN(i+1, y + 1/y_scale) - y;
1058 if (y + 1/y_scale > i)
1059 th = MIN(i+1, y + 1/y_scale) - i;
1064 for (j = 0; j < n_x; j++)
1069 tw = MIN(j+1, x + 1/x_scale) - x;
1075 if (x + 1/x_scale > j)
1076 tw = MIN(j+1, x + 1/x_scale) - j;
1081 *(pixel_weights + n_x * i + j) = 65536 * tw * x_scale * th * y_scale * overall_alpha;
1088 bilinear_make_fast_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
1090 int i_offset, j_offset;
1091 double *x_weights, *y_weights;
1094 if (x_scale > 1.0) /* Bilinear */
1097 filter->x_offset = 0.5 * (1/x_scale - 1);
1101 n_x = ceil(1.0 + 1.0/x_scale);
1102 filter->x_offset = 0.0;
1105 if (y_scale > 1.0) /* Bilinear */
1108 filter->y_offset = 0.5 * (1/y_scale - 1);
1112 n_y = ceil(1.0 + 1.0/y_scale);
1113 filter->y_offset = 0.0;
1118 filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
1120 x_weights = g_new (double, n_x);
1121 y_weights = g_new (double, n_y);
1123 for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
1124 for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
1126 int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
1127 double x = (double)j_offset / 16;
1128 double y = (double)i_offset / 16;
1131 if (x_scale > 1.0) /* Bilinear */
1133 for (i = 0; i < n_x; i++)
1135 x_weights[i] = ((i == 0) ? (1 - x) : x) / x_scale;
1140 for (i = 0; i < n_x; i++)
1145 x_weights[i] = MIN(i+1, x + 1/x_scale) - x;
1151 if (x + 1/x_scale > i)
1152 x_weights[i] = MIN(i+1, x + 1/x_scale) - i;
1159 if (y_scale > 1.0) /* Bilinear */
1161 for (i = 0; i < n_y; i++)
1163 y_weights[i] = ((i == 0) ? (1 - y) : y) / y_scale;
1168 for (i = 0; i < n_y; i++)
1173 y_weights[i] = MIN(i+1, y + 1/y_scale) - y;
1179 if (y + 1/y_scale > i)
1180 y_weights[i] = MIN(i+1, y + 1/y_scale) - i;
1187 for (i = 0; i < n_y; i++)
1188 for (j = 0; j < n_x; j++)
1189 *(pixel_weights + n_x * i + j) = 65536 * x_weights[j] * x_scale * y_weights[i] * y_scale * overall_alpha;
1197 bilinear_quadrant (double bx0, double bx1, double by0, double by1)
1199 double ax0, ax1, ay0, ay1;
1200 double x0, x1, y0, y1;
1212 x1 = MIN (ax1, bx1);
1222 x1 = MIN (ax1, bx1);
1233 y1 = MIN (ay1, by1);
1243 y1 = MIN (ay1, by1);
1249 return 0.25 * (x1*x1 - x0*x0) * (y1*y1 - y0*y0);
1253 bilinear_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
1255 int i_offset, j_offset;
1257 int n_x = ceil(1/x_scale + 2.0);
1258 int n_y = ceil(1/y_scale + 2.0);
1260 filter->x_offset = -1.0;
1261 filter->y_offset = -1.0;
1265 filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
1267 for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
1268 for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
1270 int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
1271 double x = (double)j_offset / 16;
1272 double y = (double)i_offset / 16;
1275 for (i = 0; i < n_y; i++)
1276 for (j = 0; j < n_x; j++)
1280 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);
1281 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);
1282 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);
1283 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);
1285 *(pixel_weights + n_x * i + j) = 65536 * w * x_scale * y_scale * overall_alpha;
1291 pixops_composite_color (art_u8 *dest_buf,
1298 art_boolean dest_has_alpha,
1304 art_boolean src_has_alpha,
1307 ArtFilterLevel filter_level,
1315 PixopsFilter filter;
1316 PixopsLineFunc line_func;
1319 art_boolean found_mmx = pixops_have_mmx();
1322 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
1323 g_return_if_fail (!(src_channels == 3 && src_has_alpha));
1325 if (scale_x == 0 || scale_y == 0)
1328 if (!src_has_alpha && overall_alpha == 255)
1329 pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1,
1330 dest_rowstride, dest_channels, dest_has_alpha,
1331 src_buf, src_width, src_height, src_rowstride, src_channels,
1332 src_has_alpha, scale_x, scale_y, filter_level);
1334 switch (filter_level)
1336 case ART_FILTER_NEAREST:
1337 pixops_composite_color_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1338 dest_rowstride, dest_channels, dest_has_alpha,
1339 src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha,
1340 scale_x, scale_y, overall_alpha,
1341 check_x, check_y, check_size, color1, color2);
1344 case ART_FILTER_TILES:
1345 tile_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1348 case ART_FILTER_BILINEAR:
1349 bilinear_make_fast_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1352 case ART_FILTER_HYPER:
1353 bilinear_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1358 if (filter.n_x == 2 && filter.n_y == 2 &&
1359 dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha && found_mmx)
1360 line_func = composite_line_color_22_4a4_mmx_stub;
1363 line_func = composite_line_color;
1365 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1366 dest_rowstride, dest_channels, dest_has_alpha,
1367 src_buf, src_width, src_height, src_rowstride, src_channels,
1368 src_has_alpha, scale_x, scale_y, check_x, check_y, check_size, color1, color2,
1369 &filter, line_func, composite_pixel_color);
1371 g_free (filter.weights);
1375 pixops_composite (art_u8 *dest_buf,
1382 art_boolean dest_has_alpha,
1388 art_boolean src_has_alpha,
1391 ArtFilterLevel filter_level,
1394 PixopsFilter filter;
1395 PixopsLineFunc line_func;
1398 art_boolean found_mmx = pixops_have_mmx();
1401 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
1402 g_return_if_fail (!(src_channels == 3 && src_has_alpha));
1404 if (scale_x == 0 || scale_y == 0)
1407 if (!src_has_alpha && overall_alpha == 255)
1408 pixops_scale (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,
1411 src_has_alpha, scale_x, scale_y, filter_level);
1413 switch (filter_level)
1415 case ART_FILTER_NEAREST:
1416 pixops_composite_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1417 dest_rowstride, dest_channels, dest_has_alpha,
1418 src_buf, src_width, src_height, src_rowstride, src_channels,
1419 src_has_alpha, scale_x, scale_y, overall_alpha);
1422 case ART_FILTER_TILES:
1423 tile_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1426 case ART_FILTER_BILINEAR:
1427 bilinear_make_fast_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1430 case ART_FILTER_HYPER:
1431 bilinear_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
1435 if (filter.n_x == 2 && filter.n_y == 2 &&
1436 dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha)
1440 line_func = composite_line_22_4a4_mmx_stub;
1443 line_func = composite_line_22_4a4;
1446 line_func = composite_line;
1448 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1449 dest_rowstride, dest_channels, dest_has_alpha,
1450 src_buf, src_width, src_height, src_rowstride, src_channels,
1451 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
1452 &filter, line_func, composite_pixel);
1454 g_free (filter.weights);
1458 pixops_scale (art_u8 *dest_buf,
1465 art_boolean dest_has_alpha,
1471 art_boolean src_has_alpha,
1474 ArtFilterLevel filter_level)
1476 PixopsFilter filter;
1477 PixopsLineFunc line_func;
1480 art_boolean found_mmx = pixops_have_mmx();
1483 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
1484 g_return_if_fail (!(src_channels == 3 && src_has_alpha));
1485 g_return_if_fail (!(src_has_alpha && !dest_has_alpha));
1487 if (scale_x == 0 || scale_y == 0)
1490 switch (filter_level)
1492 case ART_FILTER_NEAREST:
1493 pixops_scale_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
1494 dest_rowstride, dest_channels, dest_has_alpha,
1495 src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha,
1499 case ART_FILTER_TILES:
1500 tile_make_weights (&filter, scale_x, scale_y, 1.0);
1503 case ART_FILTER_BILINEAR:
1504 bilinear_make_fast_weights (&filter, scale_x, scale_y, 1.0);
1507 case ART_FILTER_HYPER:
1508 bilinear_make_weights (&filter, scale_x, scale_y, 1.0);
1513 if (filter.n_x == 2 && filter.n_y == 2 &&
1514 found_mmx && dest_channels == 3 && src_channels == 3)
1515 line_func = scale_line_22_33_mmx_stub;
1518 line_func = scale_line;
1520 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1521 dest_rowstride, dest_channels, dest_has_alpha,
1522 src_buf, src_width, src_height, src_rowstride, src_channels,
1523 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
1524 &filter, line_func, scale_pixel);
1526 g_free (filter.weights);