7 fills.c - implements the basic general fills
15 fill = i_new_fill_solidf(&fc1, combine);
16 fill = i_new_fill_solid(&c1, combine);
17 fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
18 fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
19 fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
24 Implements the basic general fills, which can be used for filling some
25 shapes and for flood fills.
27 Each fill can implement up to 3 functions:
33 called for fills on 8-bit images. This can be NULL in which case the
34 fill_with_colorf function is called.
36 =item fill_with_fcolor
38 called for fills on non-8-bit images or when fill_with_color is NULL.
42 called by i_fill_destroy() if non-NULL, to release any extra resources
43 that the fill may need.
47 fill_with_color and fill_with_fcolor are basically the same function
48 except that the first works with lines of i_color and the second with
51 If the combines member if non-zero the line data is populated from the
52 target image before calling fill_with_*color.
54 fill_with_color needs to fill the I<data> parameter with the fill
55 pixels. If combines is non-zero it the fill pixels should be combined
56 with the existing data.
58 The current fills are:
76 Fountain fill is implemented by L<filters.c>.
78 Other fills that could be implemented include:
84 image - an image tiled over the fill area, with an offset either
85 horizontally or vertically.
89 checkerboard - combine 2 fills in a checkerboard
93 combine - combine the levels of 2 other fills based in the levels of
98 regmach - use the register machine to generate colors
107 static i_color fcolor_to_color(i_fcolor *c) {
111 for (ch = 0; ch < MAXCHANNELS; ++ch)
112 out.channel[ch] = SampleFTo8(c->channel[ch]);
117 static i_fcolor color_to_fcolor(i_color *c) {
121 for (ch = 0; ch < MAXCHANNELS; ++ch)
122 out.channel[ch] = Sample8ToF(c->channel[ch]);
127 /* alpha combine in with out */
128 #define COMBINE(out, in, channels) \
131 for (ch = 0; ch < (channels); ++ch) { \
132 (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
133 + (in).channel[ch] * (in).channel[3]) / 255; \
137 /* alpha combine in with out, in this case in is a simple array of
138 samples, potentially not integers - the mult combiner uses doubles
140 #define COMBINEA(out, in, channels) \
143 for (ch = 0; ch < (channels); ++ch) { \
144 (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
145 + (in)[ch] * (in)[3]) / 255; \
149 #define COMBINEF(out, in, channels) \
152 for (ch = 0; ch < (channels); ++ch) { \
153 (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
154 + (in).channel[ch] * (in).channel[3]; \
165 static void fill_solid(i_fill_t *, int x, int y, int width, int channels,
167 static void fill_solidf(i_fill_t *, int x, int y, int width, int channels,
169 static void fill_solid_comb(i_fill_t *, int x, int y, int width, int channels,
171 static void fill_solidf_comb(i_fill_t *, int x, int y, int width,
172 int channels, i_fcolor *);
174 static i_fill_solid_t base_solid_fill =
184 static i_fill_solid_t base_solid_fill_comb =
196 =item i_fill_destroy(fill)
198 Call to destroy any fill object.
204 i_fill_destroy(i_fill_t *fill) {
206 (fill->destroy)(fill);
211 =item i_new_fill_solidf(color, combine)
213 Create a solid fill based on a float color.
215 If combine is non-zero then alpha values will be combined.
221 i_new_fill_solidf(i_fcolor *c, int combine) {
223 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
226 *fill = base_solid_fill_comb;
227 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
230 *fill = base_solid_fill;
232 for (ch = 0; ch < MAXCHANNELS; ++ch) {
233 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
240 =item i_new_fill_solid(color, combine)
242 Create a solid fill based.
244 If combine is non-zero then alpha values will be combined.
250 i_new_fill_solid(i_color *c, int combine) {
252 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
255 *fill = base_solid_fill_comb;
256 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
259 *fill = base_solid_fill;
261 for (ch = 0; ch < MAXCHANNELS; ++ch) {
262 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
269 builtin_hatches[][8] =
272 /* 1x1 checkerboard */
273 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
276 /* 2x2 checkerboard */
277 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
280 /* 4 x 4 checkerboard */
281 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
284 /* single vertical lines */
285 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
288 /* double vertical lines */
289 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
292 /* quad vertical lines */
293 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
297 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
305 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
309 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
313 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
317 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
321 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
325 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
329 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
333 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
337 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
345 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
349 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
353 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
356 /* single cross hatch */
357 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
360 /* double cross hatch */
361 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
364 /* vertical lozenge */
365 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
368 /* horizontal lozenge */
369 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
372 /* scales overlapping downwards */
373 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
376 /* scales overlapping upwards */
377 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
380 /* scales overlapping leftwards */
381 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
384 /* scales overlapping rightwards */
385 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
389 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
393 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
397 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
406 unsigned char hatch[8];
410 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
412 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
416 i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
417 int combine, int hatch, unsigned char *cust_hatch,
421 =item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
423 Creates a new hatched fill with the fg color used for the 1 bits in
424 the hatch and bg for the 0 bits. If combine is non-zero alpha values
427 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
428 hash definition, with the high-bits to the left.
430 If cust_hatch is NULL then one of the standard hatches is used.
432 (dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
437 i_new_fill_hatch(i_color *fg, i_color *bg, int combine, int hatch,
438 unsigned char *cust_hatch, int dx, int dy) {
439 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
444 =item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
446 Creates a new hatched fill with the fg color used for the 1 bits in
447 the hatch and bg for the 0 bits. If combine is non-zero alpha values
450 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
451 hash definition, with the high-bits to the left.
453 If cust_hatch is NULL then one of the standard hatches is used.
455 (dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
460 i_new_fill_hatchf(i_fcolor *fg, i_fcolor *bg, int combine, int hatch,
461 unsigned char *cust_hatch, int dx, int dy) {
462 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
466 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
468 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
470 struct i_fill_image_t {
479 =item i_new_fill_image(im, matrix, xoff, yoff, combine)
481 Create an image based fill.
486 i_new_fill_image(i_img *im, double *matrix, int xoff, int yoff, int combine) {
487 struct i_fill_image_t *fill = mymalloc(sizeof(*fill));
489 fill->base.fill_with_color = fill_image;
490 fill->base.fill_with_fcolor = fill_imagef;
491 fill->base.destroy = NULL;
494 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
497 fill->base.combine = NULL;
498 fill->base.combinef = NULL;
508 fill->has_matrix = 1;
509 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
512 fill->has_matrix = 0;
518 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
523 =head1 INTERNAL FUNCTIONS
527 =item fill_solid(fill, x, y, width, channels, data)
529 The 8-bit sample fill function for non-combining solid fills.
534 fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
536 while (width-- > 0) {
537 *data++ = T_SOLID_FILL(fill)->c;
542 =item fill_solid(fill, x, y, width, channels, data)
544 The floating sample fill function for non-combining solid fills.
549 fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
551 while (width-- > 0) {
552 *data++ = T_SOLID_FILL(fill)->fc;
557 =item fill_solid_comb(fill, x, y, width, channels, data)
559 The 8-bit sample fill function for combining solid fills.
564 fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels,
566 i_color c = T_SOLID_FILL(fill)->c;
568 while (width-- > 0) {
574 =item fill_solidf_comb(fill, x, y, width, channels, data)
576 The floating sample fill function for combining solid fills.
581 fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels,
583 i_fcolor c = T_SOLID_FILL(fill)->fc;
585 while (width-- > 0) {
591 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
593 Implements creation of hatch fill objects.
599 i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
600 int combine, int hatch, unsigned char *cust_hatch,
602 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t));
604 fill->base.fill_with_color = fill_hatch;
605 fill->base.fill_with_fcolor = fill_hatchf;
606 fill->base.destroy = NULL;
607 fill->fg = fg ? *fg : fcolor_to_color(ffg);
608 fill->bg = bg ? *bg : fcolor_to_color(fbg);
609 fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
610 fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
612 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
615 fill->base.combine = NULL;
616 fill->base.combinef = NULL;
619 memcpy(fill->hatch, cust_hatch, 8);
622 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
624 memcpy(fill->hatch, builtin_hatches[hatch], 8);
633 =item fill_hatch(fill, x, y, width, channels, data)
635 The 8-bit sample fill function for hatched fills.
639 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
641 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
642 int byte = f->hatch[(y + f->dy) & 7];
643 int xpos = (x + f->dx) & 7;
644 int mask = 128 >> xpos;
646 while (width-- > 0) {
647 *data++ = (byte & mask) ? f->fg : f->bg;
649 if ((mask >>= 1) == 0)
655 =item fill_hatchf(fill, x, y, width, channels, data)
657 The floating sample fill function for hatched fills.
661 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
663 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
664 int byte = f->hatch[(y + f->dy) & 7];
665 int xpos = (x + f->dx) & 7;
666 int mask = 128 >> xpos;
668 while (width-- > 0) {
669 *data++ = (byte & mask) ? f->ffg : f->fbg;
671 if ((mask >>= 1) == 0)
676 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
677 /* linear interpolation */
678 static i_color interp_i_color(i_color before, i_color after, double pos,
684 for (ch = 0; ch < channels; ++ch)
685 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
687 for (ch = 0; ch < channels; ++ch)
689 int temp = out.channel[ch] * 255 / out.channel[3];
692 out.channel[ch] = temp;
698 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
699 /* linear interpolation */
700 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
706 for (ch = 0; ch < channels; ++ch)
707 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
709 for (ch = 0; ch < channels; ++ch)
711 int temp = out.channel[ch] / out.channel[3];
714 out.channel[ch] = temp;
721 =item fill_image(fill, x, y, width, channels, data, work)
725 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
727 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
734 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
735 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
736 double ix = floor(rx / f->src->xsize);
737 double iy = floor(ry / f->src->ysize);
744 ix = floor(rx / f->src->xsize);
748 iy = floor(ry / f->src->ysize);
750 rx -= ix * f->src->xsize;
751 ry -= iy * f->src->ysize;
753 for (dy = 0; dy < 2; ++dy) {
754 if ((int)rx == f->src->xsize-1) {
755 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
756 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
759 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
762 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
764 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
770 /* this should be possible to optimize to use i_glin() */
774 int ix = rx / f->src->xsize;
775 int iy = ry / f->src->ysize;
779 ix = rx / f->src->xsize;
783 iy = ry / f->src->xsize;
785 rx -= ix * f->src->xsize;
786 ry -= iy * f->src->ysize;
787 i_gpix(f->src, rx, ry, out);
792 if (f->src->channels == 3) {
793 /* just set the alpha */
794 for (i = 0; i < width; ++i) {
795 data->channel[3] = 255;
799 else if (f->src->channels == 2) {
800 /* copy the alpha to channel 3, duplicate the grey value */
801 for (i = 0; i < width; ++i) {
802 data->channel[3] = data->channel[1];
803 data->channel[1] = data->channel[2] = data->channel[0];
807 else if (f->src->channels == 1) {
808 /* set the alpha, duplicate grey */
809 for (i = 0; i < width; ++i) {
810 data->channel[3] = 255;
811 data->channel[1] = data->channel[2] = data->channel[0];
818 =item fill_image(fill, x, y, width, channels, data, work)
822 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
824 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
830 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
831 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
832 double ix = floor(rx / f->src->xsize);
833 double iy = floor(ry / f->src->ysize);
840 ix = floor(rx / f->src->xsize);
844 iy = floor(ry / f->src->ysize);
846 rx -= ix * f->src->xsize;
847 ry -= iy * f->src->ysize;
849 for (dy = 0; dy < 2; ++dy) {
850 if ((int)rx == f->src->xsize-1) {
851 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
852 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
855 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
858 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
860 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
866 /* this should be possible to optimize to use i_glin() */
870 int ix = rx / f->src->xsize;
871 int iy = ry / f->src->ysize;
875 ix = rx / f->src->xsize;
879 iy = ry / f->src->xsize;
881 rx -= ix * f->src->xsize;
882 ry -= iy * f->src->ysize;
883 i_gpixf(f->src, rx, ry, data);
888 if (f->src->channels == 3) {
889 /* just set the alpha */
890 for (i = 0; i < width; ++i) {
891 data->channel[3] = 1.0;
895 else if (f->src->channels == 2) {
896 /* copy the alpha to channel 3, duplicate the grey value */
897 for (i = 0; i < width; ++i) {
898 data->channel[3] = data->channel[1];
899 data->channel[1] = data->channel[2] = data->channel[0];
903 else if (f->src->channels == 1) {
904 /* set the alpha, duplicate grey */
905 for (i = 0; i < width; ++i) {
906 data->channel[3] = 1.0;
907 data->channel[1] = data->channel[2] = data->channel[0];
913 static void combine_replace(i_color *, i_color *, int, int);
914 static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
915 static void combine_alphablend(i_color *, i_color *, int, int);
916 static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
917 static void combine_mult(i_color *, i_color *, int, int);
918 static void combine_multf(i_fcolor *, i_fcolor *, int, int);
919 static void combine_dissolve(i_color *, i_color *, int, int);
920 static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
921 static void combine_add(i_color *, i_color *, int, int);
922 static void combine_addf(i_fcolor *, i_fcolor *, int, int);
923 static void combine_subtract(i_color *, i_color *, int, int);
924 static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
925 static void combine_diff(i_color *, i_color *, int, int);
926 static void combine_difff(i_fcolor *, i_fcolor *, int, int);
927 static void combine_darken(i_color *, i_color *, int, int);
928 static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
929 static void combine_lighten(i_color *, i_color *, int, int);
930 static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
931 static void combine_hue(i_color *, i_color *, int, int);
932 static void combine_huef(i_fcolor *, i_fcolor *, int, int);
933 static void combine_sat(i_color *, i_color *, int, int);
934 static void combine_satf(i_fcolor *, i_fcolor *, int, int);
935 static void combine_value(i_color *, i_color *, int, int);
936 static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
937 static void combine_color(i_color *, i_color *, int, int);
938 static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
940 static struct i_combines {
941 i_fill_combine_f combine;
942 i_fill_combinef_f combinef;
1005 =item i_get_combine(combine, color_func, fcolor_func)
1010 void i_get_combine(int combine, i_fill_combine_f *color_func,
1011 i_fill_combinef_f *fcolor_func) {
1012 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
1015 *color_func = combines[combine].combine;
1016 *fcolor_func = combines[combine].combinef;
1019 static void combine_replace(i_color *out, i_color *in, int channels, int count) {
1025 static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1031 static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
1033 COMBINE(*out, *in, channels);
1039 static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1041 COMBINEF(*out, *in, channels);
1047 static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1051 double mult[MAXCHANNELS];
1052 mult[3] = in->channel[3];
1053 for (ch = 0; ch < (channels); ++ch) {
1055 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1057 COMBINEA(*out, mult, channels);
1063 static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1068 for (ch = 0; ch < channels; ++ch) {
1070 c.channel[ch] = out->channel[ch] * in->channel[ch];
1072 COMBINEF(*out, c, channels);
1078 static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
1080 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1081 COMBINE(*out, *in, channels);
1087 static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1089 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1090 COMBINEF(*out, *in, channels);
1096 static void combine_add(i_color *out, i_color *in, int channels, int count) {
1101 for (ch = 0; ch < (channels); ++ch) {
1103 int total = out->channel[ch] + in->channel[ch];
1106 c.channel[ch] = total;
1109 COMBINE(*out, c, channels);
1115 static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1120 for (ch = 0; ch < (channels); ++ch) {
1122 double total = out->channel[ch] + in->channel[ch];
1125 out->channel[ch] = total;
1128 COMBINEF(*out, c, channels);
1134 static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1139 for (ch = 0; ch < (channels); ++ch) {
1141 int total = out->channel[ch] - in->channel[ch];
1144 c.channel[ch] = total;
1147 COMBINE(*out, c, channels);
1153 static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1158 for (ch = 0; ch < channels; ++ch) {
1160 double total = out->channel[ch] - in->channel[ch];
1163 c.channel[ch] = total;
1166 COMBINEF(*out, c, channels);
1172 static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1177 for (ch = 0; ch < (channels); ++ch) {
1179 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1181 COMBINE(*out, c, channels)
1187 static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1192 for (ch = 0; ch < (channels); ++ch) {
1194 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
1196 COMBINEF(*out, c, channels);
1202 static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1206 for (ch = 0; ch < channels; ++ch) {
1207 if (ch != 3 && out->channel[ch] < in->channel[ch])
1208 in->channel[ch] = out->channel[ch];
1210 COMBINE(*out, *in, channels);
1216 static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1220 for (ch = 0; ch < channels; ++ch) {
1221 if (ch != 3 && out->channel[ch] < in->channel[ch])
1222 in->channel[ch] = out->channel[ch];
1224 COMBINEF(*out, *in, channels);
1230 static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1234 for (ch = 0; ch < channels; ++ch) {
1235 if (ch != 3 && out->channel[ch] > in->channel[ch])
1236 in->channel[ch] = out->channel[ch];
1238 COMBINE(*out, *in, channels);
1244 static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1248 for (ch = 0; ch < channels; ++ch) {
1249 if (ch != 3 && out->channel[ch] > in->channel[ch])
1250 in->channel[ch] = out->channel[ch];
1252 COMBINEF(*out, *in, channels);
1258 static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1263 c.channel[0] = in->channel[0];
1265 c.channel[3] = in->channel[3];
1266 COMBINE(*out, c, channels);
1272 static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1277 c.channel[0] = in->channel[0];
1279 c.channel[3] = in->channel[3];
1280 COMBINEF(*out, c, channels);
1286 static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1291 c.channel[1] = in->channel[1];
1293 c.channel[3] = in->channel[3];
1294 COMBINE(*out, c, channels);
1300 static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1305 c.channel[1] = in->channel[1];
1307 c.channel[3] = in->channel[3];
1308 COMBINEF(*out, c, channels);
1314 static void combine_value(i_color *out, i_color *in, int channels, int count) {
1319 c.channel[2] = in->channel[2];
1321 c.channel[3] = in->channel[3];
1322 COMBINE(*out, c, channels);
1328 static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1334 c.channel[2] = in->channel[2];
1336 c.channel[3] = in->channel[3];
1337 COMBINEF(*out, c, channels);
1343 static void combine_color(i_color *out, i_color *in, int channels, int count) {
1348 c.channel[0] = in->channel[0];
1349 c.channel[1] = in->channel[1];
1351 c.channel[3] = in->channel[3];
1352 COMBINE(*out, c, channels);
1358 static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1364 c.channel[0] = in->channel[0];
1365 c.channel[1] = in->channel[1];
1367 c.channel[3] = in->channel[3];
1368 COMBINEF(*out, c, channels);
1380 Tony Cook <tony@develop-help.com>