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;
735 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
736 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
737 double ix = floor(rx / f->src->xsize);
738 double iy = floor(ry / f->src->ysize);
745 ix = floor(rx / f->src->xsize);
749 iy = floor(ry / f->src->ysize);
751 rx -= ix * f->src->xsize;
752 ry -= iy * f->src->ysize;
754 for (dy = 0; dy < 2; ++dy) {
755 if ((int)rx == f->src->xsize-1) {
756 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
757 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
760 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
763 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
765 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
771 /* this should be possible to optimize to use i_glin() */
775 int ix = rx / f->src->xsize;
776 int iy = ry / f->src->ysize;
780 ix = rx / f->src->xsize;
784 iy = ry / f->src->xsize;
786 rx -= ix * f->src->xsize;
787 ry -= iy * f->src->ysize;
788 i_gpix(f->src, rx, ry, out);
793 if (f->src->channels == 3) {
794 /* just set the alpha */
795 for (i = 0; i < width; ++i) {
796 data->channel[3] = 255;
800 else if (f->src->channels == 2) {
801 /* copy the alpha to channel 3, duplicate the grey value */
802 for (i = 0; i < width; ++i) {
803 data->channel[3] = data->channel[1];
804 data->channel[1] = data->channel[2] = data->channel[0];
808 else if (f->src->channels == 1) {
809 /* set the alpha, duplicate grey */
810 for (i = 0; i < width; ++i) {
811 data->channel[3] = 255;
812 data->channel[1] = data->channel[2] = data->channel[0];
819 =item fill_image(fill, x, y, width, channels, data, work)
823 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
825 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
832 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
833 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
834 double ix = floor(rx / f->src->xsize);
835 double iy = floor(ry / f->src->ysize);
842 ix = floor(rx / f->src->xsize);
846 iy = floor(ry / f->src->ysize);
848 rx -= ix * f->src->xsize;
849 ry -= iy * f->src->ysize;
851 for (dy = 0; dy < 2; ++dy) {
852 if ((int)rx == f->src->xsize-1) {
853 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
854 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
857 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
860 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
862 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
868 /* this should be possible to optimize to use i_glin() */
872 int ix = rx / f->src->xsize;
873 int iy = ry / f->src->ysize;
877 ix = rx / f->src->xsize;
881 iy = ry / f->src->xsize;
883 rx -= ix * f->src->xsize;
884 ry -= iy * f->src->ysize;
885 i_gpixf(f->src, rx, ry, data);
890 if (f->src->channels == 3) {
891 /* just set the alpha */
892 for (i = 0; i < width; ++i) {
893 data->channel[3] = 1.0;
897 else if (f->src->channels == 2) {
898 /* copy the alpha to channel 3, duplicate the grey value */
899 for (i = 0; i < width; ++i) {
900 data->channel[3] = data->channel[1];
901 data->channel[1] = data->channel[2] = data->channel[0];
905 else if (f->src->channels == 1) {
906 /* set the alpha, duplicate grey */
907 for (i = 0; i < width; ++i) {
908 data->channel[3] = 1.0;
909 data->channel[1] = data->channel[2] = data->channel[0];
915 static void combine_replace(i_color *, i_color *, int, int);
916 static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
917 static void combine_alphablend(i_color *, i_color *, int, int);
918 static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
919 static void combine_mult(i_color *, i_color *, int, int);
920 static void combine_multf(i_fcolor *, i_fcolor *, int, int);
921 static void combine_dissolve(i_color *, i_color *, int, int);
922 static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
923 static void combine_add(i_color *, i_color *, int, int);
924 static void combine_addf(i_fcolor *, i_fcolor *, int, int);
925 static void combine_subtract(i_color *, i_color *, int, int);
926 static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
927 static void combine_diff(i_color *, i_color *, int, int);
928 static void combine_difff(i_fcolor *, i_fcolor *, int, int);
929 static void combine_darken(i_color *, i_color *, int, int);
930 static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
931 static void combine_lighten(i_color *, i_color *, int, int);
932 static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
933 static void combine_hue(i_color *, i_color *, int, int);
934 static void combine_huef(i_fcolor *, i_fcolor *, int, int);
935 static void combine_sat(i_color *, i_color *, int, int);
936 static void combine_satf(i_fcolor *, i_fcolor *, int, int);
937 static void combine_value(i_color *, i_color *, int, int);
938 static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
939 static void combine_color(i_color *, i_color *, int, int);
940 static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
942 static struct i_combines {
943 i_fill_combine_f combine;
944 i_fill_combinef_f combinef;
1007 =item i_get_combine(combine, color_func, fcolor_func)
1012 void i_get_combine(int combine, i_fill_combine_f *color_func,
1013 i_fill_combinef_f *fcolor_func) {
1014 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
1017 *color_func = combines[combine].combine;
1018 *fcolor_func = combines[combine].combinef;
1021 static void combine_replace(i_color *out, i_color *in, int channels, int count) {
1027 static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1033 static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
1035 COMBINE(*out, *in, channels);
1041 static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1043 COMBINEF(*out, *in, channels);
1049 static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1054 double mult[MAXCHANNELS];
1055 mult[3] = in->channel[3];
1056 for (ch = 0; ch < (channels); ++ch) {
1058 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1060 COMBINEA(*out, mult, channels);
1066 static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1071 for (ch = 0; ch < channels; ++ch) {
1073 c.channel[ch] = out->channel[ch] * in->channel[ch];
1075 COMBINEF(*out, c, channels);
1081 static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
1085 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1086 COMBINE(*out, *in, channels);
1092 static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1096 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1097 COMBINEF(*out, *in, channels);
1103 static void combine_add(i_color *out, i_color *in, int channels, int count) {
1108 for (ch = 0; ch < (channels); ++ch) {
1110 int total = out->channel[ch] + in->channel[ch];
1113 c.channel[ch] = total;
1116 COMBINE(*out, c, channels);
1122 static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1127 for (ch = 0; ch < (channels); ++ch) {
1129 double total = out->channel[ch] + in->channel[ch];
1132 out->channel[ch] = total;
1135 COMBINEF(*out, c, channels);
1141 static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1146 for (ch = 0; ch < (channels); ++ch) {
1148 int total = out->channel[ch] - in->channel[ch];
1151 c.channel[ch] = total;
1154 COMBINE(*out, c, channels);
1160 static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1165 for (ch = 0; ch < channels; ++ch) {
1167 double total = out->channel[ch] - in->channel[ch];
1170 c.channel[ch] = total;
1173 COMBINEF(*out, c, channels);
1179 static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1184 for (ch = 0; ch < (channels); ++ch) {
1186 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1188 COMBINE(*out, c, channels)
1194 static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1199 for (ch = 0; ch < (channels); ++ch) {
1201 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
1203 COMBINEF(*out, c, channels);
1209 static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1213 for (ch = 0; ch < channels; ++ch) {
1214 if (ch != 3 && out->channel[ch] < in->channel[ch])
1215 in->channel[ch] = out->channel[ch];
1217 COMBINE(*out, *in, channels);
1223 static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1227 for (ch = 0; ch < channels; ++ch) {
1228 if (ch != 3 && out->channel[ch] < in->channel[ch])
1229 in->channel[ch] = out->channel[ch];
1231 COMBINEF(*out, *in, channels);
1237 static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1241 for (ch = 0; ch < channels; ++ch) {
1242 if (ch != 3 && out->channel[ch] > in->channel[ch])
1243 in->channel[ch] = out->channel[ch];
1245 COMBINE(*out, *in, channels);
1251 static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1255 for (ch = 0; ch < channels; ++ch) {
1256 if (ch != 3 && out->channel[ch] > in->channel[ch])
1257 in->channel[ch] = out->channel[ch];
1259 COMBINEF(*out, *in, channels);
1265 static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1270 c.channel[0] = in->channel[0];
1272 c.channel[3] = in->channel[3];
1273 COMBINE(*out, c, channels);
1279 static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1284 c.channel[0] = in->channel[0];
1286 c.channel[3] = in->channel[3];
1287 COMBINEF(*out, c, channels);
1293 static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1298 c.channel[1] = in->channel[1];
1300 c.channel[3] = in->channel[3];
1301 COMBINE(*out, c, channels);
1307 static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1312 c.channel[1] = in->channel[1];
1314 c.channel[3] = in->channel[3];
1315 COMBINEF(*out, c, channels);
1321 static void combine_value(i_color *out, i_color *in, int channels, int count) {
1326 c.channel[2] = in->channel[2];
1328 c.channel[3] = in->channel[3];
1329 COMBINE(*out, c, channels);
1335 static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1341 c.channel[2] = in->channel[2];
1343 c.channel[3] = in->channel[3];
1344 COMBINEF(*out, c, channels);
1350 static void combine_color(i_color *out, i_color *in, int channels, int count) {
1355 c.channel[0] = in->channel[0];
1356 c.channel[1] = in->channel[1];
1358 c.channel[3] = in->channel[3];
1359 COMBINE(*out, c, channels);
1365 static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1371 c.channel[0] = in->channel[0];
1372 c.channel[1] = in->channel[1];
1374 c.channel[3] = in->channel[3];
1375 COMBINEF(*out, c, channels);
1387 Tony Cook <tony@develop-help.com>