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 *data++ = 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, data);
795 =item fill_image(fill, x, y, width, channels, data, work)
799 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
801 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
808 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
809 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
810 double ix = floor(rx / f->src->xsize);
811 double iy = floor(ry / f->src->ysize);
818 ix = floor(rx / f->src->xsize);
822 iy = floor(ry / f->src->ysize);
824 rx -= ix * f->src->xsize;
825 ry -= iy * f->src->ysize;
827 for (dy = 0; dy < 2; ++dy) {
828 if ((int)rx == f->src->xsize-1) {
829 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
830 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
833 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
836 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
838 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
844 /* this should be possible to optimize to use i_glin() */
848 int ix = rx / f->src->xsize;
849 int iy = ry / f->src->ysize;
853 ix = rx / f->src->xsize;
857 iy = ry / f->src->xsize;
859 rx -= ix * f->src->xsize;
860 ry -= iy * f->src->ysize;
861 i_gpixf(f->src, rx, ry, data);
868 static void combine_replace(i_color *, i_color *, int, int);
869 static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
870 static void combine_alphablend(i_color *, i_color *, int, int);
871 static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
872 static void combine_mult(i_color *, i_color *, int, int);
873 static void combine_multf(i_fcolor *, i_fcolor *, int, int);
874 static void combine_dissolve(i_color *, i_color *, int, int);
875 static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
876 static void combine_add(i_color *, i_color *, int, int);
877 static void combine_addf(i_fcolor *, i_fcolor *, int, int);
878 static void combine_subtract(i_color *, i_color *, int, int);
879 static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
880 static void combine_diff(i_color *, i_color *, int, int);
881 static void combine_difff(i_fcolor *, i_fcolor *, int, int);
882 static void combine_darken(i_color *, i_color *, int, int);
883 static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
884 static void combine_lighten(i_color *, i_color *, int, int);
885 static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
886 static void combine_hue(i_color *, i_color *, int, int);
887 static void combine_huef(i_fcolor *, i_fcolor *, int, int);
888 static void combine_sat(i_color *, i_color *, int, int);
889 static void combine_satf(i_fcolor *, i_fcolor *, int, int);
890 static void combine_value(i_color *, i_color *, int, int);
891 static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
892 static void combine_color(i_color *, i_color *, int, int);
893 static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
895 static struct i_combines {
896 i_fill_combine_f combine;
897 i_fill_combinef_f combinef;
960 =item i_get_combine(combine, color_func, fcolor_func)
965 void i_get_combine(int combine, i_fill_combine_f *color_func,
966 i_fill_combinef_f *fcolor_func) {
967 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
970 *color_func = combines[combine].combine;
971 *fcolor_func = combines[combine].combinef;
974 static void combine_replace(i_color *out, i_color *in, int channels, int count) {
980 static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
986 static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
988 COMBINE(*out, *in, channels);
994 static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
996 COMBINEF(*out, *in, channels);
1002 static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1007 double mult[MAXCHANNELS];
1008 mult[3] = in->channel[3];
1009 for (ch = 0; ch < (channels); ++ch) {
1011 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1013 COMBINEA(*out, mult, channels);
1019 static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1024 for (ch = 0; ch < channels; ++ch) {
1026 c.channel[ch] = out->channel[ch] * in->channel[ch];
1028 COMBINEF(*out, c, channels);
1034 static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
1038 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1039 COMBINE(*out, *in, channels);
1045 static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1049 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1050 COMBINEF(*out, *in, channels);
1056 static void combine_add(i_color *out, i_color *in, int channels, int count) {
1061 for (ch = 0; ch < (channels); ++ch) {
1063 int total = out->channel[ch] + in->channel[ch];
1066 c.channel[ch] = total;
1069 COMBINE(*out, c, channels);
1075 static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1080 for (ch = 0; ch < (channels); ++ch) {
1082 double total = out->channel[ch] + in->channel[ch];
1085 out->channel[ch] = total;
1088 COMBINEF(*out, c, channels);
1094 static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1099 for (ch = 0; ch < (channels); ++ch) {
1101 int total = out->channel[ch] - in->channel[ch];
1104 c.channel[ch] = total;
1107 COMBINE(*out, c, channels);
1113 static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1118 for (ch = 0; ch < channels; ++ch) {
1120 double total = out->channel[ch] - in->channel[ch];
1123 c.channel[ch] = total;
1126 COMBINEF(*out, c, channels);
1132 static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1137 for (ch = 0; ch < (channels); ++ch) {
1139 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1141 COMBINE(*out, c, channels)
1147 static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1152 for (ch = 0; ch < (channels); ++ch) {
1154 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
1156 COMBINEF(*out, c, channels);
1162 static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1166 for (ch = 0; ch < channels; ++ch) {
1167 if (ch != 3 && out->channel[ch] < in->channel[ch])
1168 in->channel[ch] = out->channel[ch];
1170 COMBINE(*out, *in, channels);
1176 static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1180 for (ch = 0; ch < channels; ++ch) {
1181 if (ch != 3 && out->channel[ch] < in->channel[ch])
1182 in->channel[ch] = out->channel[ch];
1184 COMBINEF(*out, *in, channels);
1190 static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1194 for (ch = 0; ch < channels; ++ch) {
1195 if (ch != 3 && out->channel[ch] > in->channel[ch])
1196 in->channel[ch] = out->channel[ch];
1198 COMBINE(*out, *in, channels);
1204 static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1208 for (ch = 0; ch < channels; ++ch) {
1209 if (ch != 3 && out->channel[ch] > in->channel[ch])
1210 in->channel[ch] = out->channel[ch];
1212 COMBINEF(*out, *in, channels);
1218 static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1223 c.channel[0] = in->channel[0];
1225 c.channel[3] = in->channel[3];
1226 COMBINE(*out, c, channels);
1232 static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1237 c.channel[0] = in->channel[0];
1239 c.channel[3] = in->channel[3];
1240 COMBINEF(*out, c, channels);
1246 static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1251 c.channel[1] = in->channel[1];
1253 c.channel[3] = in->channel[3];
1254 COMBINE(*out, c, channels);
1260 static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1265 c.channel[1] = in->channel[1];
1267 c.channel[3] = in->channel[3];
1268 COMBINEF(*out, c, channels);
1274 static void combine_value(i_color *out, i_color *in, int channels, int count) {
1279 c.channel[2] = in->channel[2];
1281 c.channel[3] = in->channel[3];
1282 COMBINE(*out, c, channels);
1288 static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1294 c.channel[2] = in->channel[2];
1296 c.channel[3] = in->channel[3];
1297 COMBINEF(*out, c, channels);
1303 static void combine_color(i_color *out, i_color *in, int channels, int count) {
1308 c.channel[0] = in->channel[0];
1309 c.channel[1] = in->channel[1];
1311 c.channel[3] = in->channel[3];
1312 COMBINE(*out, c, channels);
1318 static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1324 c.channel[0] = in->channel[0];
1325 c.channel[1] = in->channel[1];
1327 c.channel[3] = in->channel[3];
1328 COMBINEF(*out, c, channels);
1340 Tony Cook <tony@develop-help.com>