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(const 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(const 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)
199 =synopsis i_fill_destroy(fill);
201 Call to destroy any fill object.
207 i_fill_destroy(i_fill_t *fill) {
209 (fill->destroy)(fill);
214 =item i_new_fill_solidf(color, combine)
217 =synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine);
219 Create a solid fill based on a float color.
221 If combine is non-zero then alpha values will be combined.
227 i_new_fill_solidf(const i_fcolor *c, int combine) {
229 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
232 *fill = base_solid_fill_comb;
233 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
236 *fill = base_solid_fill;
238 for (ch = 0; ch < MAXCHANNELS; ++ch) {
239 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
246 =item i_new_fill_solid(color, combine)
249 =synopsis i_fill_t *fill = i_new_fill_solid(&color, combine);
251 Create a solid fill based on an 8-bit color.
253 If combine is non-zero then alpha values will be combined.
259 i_new_fill_solid(const i_color *c, int combine) {
261 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
264 *fill = base_solid_fill_comb;
265 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
268 *fill = base_solid_fill;
270 for (ch = 0; ch < MAXCHANNELS; ++ch) {
271 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
278 builtin_hatches[][8] =
281 /* 1x1 checkerboard */
282 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
285 /* 2x2 checkerboard */
286 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
289 /* 4 x 4 checkerboard */
290 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
293 /* single vertical lines */
294 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
297 /* double vertical lines */
298 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
301 /* quad vertical lines */
302 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
306 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
314 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
318 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
322 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
326 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
330 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
334 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
338 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
342 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
346 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
354 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
358 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
362 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
365 /* single cross hatch */
366 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
369 /* double cross hatch */
370 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
373 /* vertical lozenge */
374 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
377 /* horizontal lozenge */
378 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
381 /* scales overlapping downwards */
382 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
385 /* scales overlapping upwards */
386 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
389 /* scales overlapping leftwards */
390 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
393 /* scales overlapping rightwards */
394 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
398 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
402 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
406 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
415 unsigned char hatch[8];
419 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
421 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
425 i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg,
426 int combine, int hatch, const unsigned char *cust_hatch,
430 =item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
433 =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
435 Creates a new hatched fill with the fg color used for the 1 bits in
436 the hatch and bg for the 0 bits. If combine is non-zero alpha values
439 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
440 hash definition, with the high-bits to the left.
442 If cust_hatch is NULL then one of the standard hatches is used.
444 (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.
449 i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
450 const unsigned char *cust_hatch, int dx, int dy) {
451 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
456 =item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
459 =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
461 Creates a new hatched fill with the fg color used for the 1 bits in
462 the hatch and bg for the 0 bits. If combine is non-zero alpha values
465 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
466 hash definition, with the high-bits to the left.
468 If cust_hatch is NULL then one of the standard hatches is used.
470 (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.
475 i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
476 const unsigned char *cust_hatch, int dx, int dy) {
477 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
481 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
483 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
485 struct i_fill_image_t {
494 =item i_new_fill_image(im, matrix, xoff, yoff, combine)
497 =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
499 Create an image based fill.
501 matrix is an array of 9 doubles representing a transformation matrix.
503 xoff and yoff are the offset into the image to start filling from.
508 i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) {
509 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
511 fill->base.fill_with_color = fill_image;
512 fill->base.fill_with_fcolor = fill_imagef;
513 fill->base.destroy = NULL;
516 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
519 fill->base.combine = NULL;
520 fill->base.combinef = NULL;
530 fill->has_matrix = 1;
531 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
534 fill->has_matrix = 0;
540 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
545 =head1 INTERNAL FUNCTIONS
549 =item fill_solid(fill, x, y, width, channels, data)
551 The 8-bit sample fill function for non-combining solid fills.
556 fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
558 while (width-- > 0) {
559 *data++ = T_SOLID_FILL(fill)->c;
564 =item fill_solid(fill, x, y, width, channels, data)
566 The floating sample fill function for non-combining solid fills.
571 fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
573 while (width-- > 0) {
574 *data++ = T_SOLID_FILL(fill)->fc;
579 =item fill_solid_comb(fill, x, y, width, channels, data)
581 The 8-bit sample fill function for combining solid fills.
586 fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels,
588 i_color c = T_SOLID_FILL(fill)->c;
590 while (width-- > 0) {
596 =item fill_solidf_comb(fill, x, y, width, channels, data)
598 The floating sample fill function for combining solid fills.
603 fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels,
605 i_fcolor c = T_SOLID_FILL(fill)->fc;
607 while (width-- > 0) {
613 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
615 Implements creation of hatch fill objects.
621 i_new_hatch_low(const i_color *fg, const i_color *bg,
622 const i_fcolor *ffg, const i_fcolor *fbg,
623 int combine, int hatch, const unsigned char *cust_hatch,
625 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
627 fill->base.fill_with_color = fill_hatch;
628 fill->base.fill_with_fcolor = fill_hatchf;
629 fill->base.destroy = NULL;
630 /* Some Sun C didn't like the condition expressions that were here.
631 See https://rt.cpan.org/Ticket/Display.html?id=21944
636 fill->fg = fcolor_to_color(ffg);
640 fill->bg = fcolor_to_color(fbg);
644 fill->ffg = color_to_fcolor(fg);
648 fill->fbg = color_to_fcolor(bg);
650 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
653 fill->base.combine = NULL;
654 fill->base.combinef = NULL;
657 memcpy(fill->hatch, cust_hatch, 8);
660 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
662 memcpy(fill->hatch, builtin_hatches[hatch], 8);
671 =item fill_hatch(fill, x, y, width, channels, data)
673 The 8-bit sample fill function for hatched fills.
677 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
679 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
680 int byte = f->hatch[(y + f->dy) & 7];
681 int xpos = (x + f->dx) & 7;
682 int mask = 128 >> xpos;
684 while (width-- > 0) {
690 if ((mask >>= 1) == 0)
696 =item fill_hatchf(fill, x, y, width, channels, data)
698 The floating sample fill function for hatched fills.
702 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
704 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
705 int byte = f->hatch[(y + f->dy) & 7];
706 int xpos = (x + f->dx) & 7;
707 int mask = 128 >> xpos;
709 while (width-- > 0) {
715 if ((mask >>= 1) == 0)
720 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
721 /* linear interpolation */
722 static i_color interp_i_color(i_color before, i_color after, double pos,
728 for (ch = 0; ch < channels; ++ch)
729 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
730 if (channels > 3 && out.channel[3])
731 for (ch = 0; ch < channels; ++ch)
733 int temp = out.channel[ch] * 255 / out.channel[3];
736 out.channel[ch] = temp;
742 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
743 /* linear interpolation */
744 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
750 for (ch = 0; ch < channels; ++ch)
751 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
753 for (ch = 0; ch < channels; ++ch)
755 int temp = out.channel[ch] / out.channel[3];
758 out.channel[ch] = temp;
765 =item fill_image(fill, x, y, width, channels, data, work)
769 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
771 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
778 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
779 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
780 double ix = floor(rx / f->src->xsize);
781 double iy = floor(ry / f->src->ysize);
788 ix = floor(rx / f->src->xsize);
792 iy = floor(ry / f->src->ysize);
794 rx -= ix * f->src->xsize;
795 ry -= iy * f->src->ysize;
797 for (dy = 0; dy < 2; ++dy) {
798 if ((int)rx == f->src->xsize-1) {
799 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
800 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
803 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
806 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
808 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
814 /* this should be possible to optimize to use i_glin() */
818 int ix = rx / f->src->xsize;
819 int iy = ry / f->src->ysize;
823 ix = rx / f->src->xsize;
827 iy = ry / f->src->xsize;
829 rx -= ix * f->src->xsize;
830 ry -= iy * f->src->ysize;
831 i_gpix(f->src, rx, ry, out);
836 if (f->src->channels == 3) {
837 /* just set the alpha */
838 for (i = 0; i < width; ++i) {
839 data->channel[3] = 255;
843 else if (f->src->channels == 2) {
844 /* copy the alpha to channel 3, duplicate the grey value */
845 for (i = 0; i < width; ++i) {
846 data->channel[3] = data->channel[1];
847 data->channel[1] = data->channel[2] = data->channel[0];
851 else if (f->src->channels == 1) {
852 /* set the alpha, duplicate grey */
853 for (i = 0; i < width; ++i) {
854 data->channel[3] = 255;
855 data->channel[1] = data->channel[2] = data->channel[0];
862 =item fill_image(fill, x, y, width, channels, data, work)
866 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
868 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
874 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
875 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
876 double ix = floor(rx / f->src->xsize);
877 double iy = floor(ry / f->src->ysize);
884 ix = floor(rx / f->src->xsize);
888 iy = floor(ry / f->src->ysize);
890 rx -= ix * f->src->xsize;
891 ry -= iy * f->src->ysize;
893 for (dy = 0; dy < 2; ++dy) {
894 if ((int)rx == f->src->xsize-1) {
895 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
896 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
899 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
902 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
904 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
910 /* this should be possible to optimize to use i_glin() */
914 int ix = rx / f->src->xsize;
915 int iy = ry / f->src->ysize;
919 ix = rx / f->src->xsize;
923 iy = ry / f->src->xsize;
925 rx -= ix * f->src->xsize;
926 ry -= iy * f->src->ysize;
927 i_gpixf(f->src, rx, ry, data);
932 if (f->src->channels == 3) {
933 /* just set the alpha */
934 for (i = 0; i < width; ++i) {
935 data->channel[3] = 1.0;
939 else if (f->src->channels == 2) {
940 /* copy the alpha to channel 3, duplicate the grey value */
941 for (i = 0; i < width; ++i) {
942 data->channel[3] = data->channel[1];
943 data->channel[1] = data->channel[2] = data->channel[0];
947 else if (f->src->channels == 1) {
948 /* set the alpha, duplicate grey */
949 for (i = 0; i < width; ++i) {
950 data->channel[3] = 1.0;
951 data->channel[1] = data->channel[2] = data->channel[0];
957 static void combine_replace(i_color *, i_color *, int, int);
958 static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
959 static void combine_alphablend(i_color *, i_color *, int, int);
960 static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
961 static void combine_mult(i_color *, i_color *, int, int);
962 static void combine_multf(i_fcolor *, i_fcolor *, int, int);
963 static void combine_dissolve(i_color *, i_color *, int, int);
964 static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
965 static void combine_add(i_color *, i_color *, int, int);
966 static void combine_addf(i_fcolor *, i_fcolor *, int, int);
967 static void combine_subtract(i_color *, i_color *, int, int);
968 static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
969 static void combine_diff(i_color *, i_color *, int, int);
970 static void combine_difff(i_fcolor *, i_fcolor *, int, int);
971 static void combine_darken(i_color *, i_color *, int, int);
972 static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
973 static void combine_lighten(i_color *, i_color *, int, int);
974 static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
975 static void combine_hue(i_color *, i_color *, int, int);
976 static void combine_huef(i_fcolor *, i_fcolor *, int, int);
977 static void combine_sat(i_color *, i_color *, int, int);
978 static void combine_satf(i_fcolor *, i_fcolor *, int, int);
979 static void combine_value(i_color *, i_color *, int, int);
980 static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
981 static void combine_color(i_color *, i_color *, int, int);
982 static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
984 static struct i_combines {
985 i_fill_combine_f combine;
986 i_fill_combinef_f combinef;
1049 =item i_get_combine(combine, color_func, fcolor_func)
1054 void i_get_combine(int combine, i_fill_combine_f *color_func,
1055 i_fill_combinef_f *fcolor_func) {
1056 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
1059 *color_func = combines[combine].combine;
1060 *fcolor_func = combines[combine].combinef;
1063 static void combine_replace(i_color *out, i_color *in, int channels, int count) {
1069 static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1075 static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
1077 COMBINE(*out, *in, channels);
1083 static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1085 COMBINEF(*out, *in, channels);
1091 static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1095 double mult[MAXCHANNELS];
1096 mult[3] = in->channel[3];
1097 for (ch = 0; ch < (channels); ++ch) {
1099 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1101 COMBINEA(*out, mult, channels);
1107 static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1112 for (ch = 0; ch < channels; ++ch) {
1114 c.channel[ch] = out->channel[ch] * in->channel[ch];
1116 COMBINEF(*out, c, channels);
1122 static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
1124 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1125 COMBINE(*out, *in, channels);
1131 static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1133 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1134 COMBINEF(*out, *in, channels);
1140 static void combine_add(i_color *out, i_color *in, int channels, int count) {
1145 for (ch = 0; ch < (channels); ++ch) {
1147 int total = out->channel[ch] + in->channel[ch];
1150 c.channel[ch] = total;
1153 COMBINE(*out, c, channels);
1159 static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1164 for (ch = 0; ch < (channels); ++ch) {
1166 double total = out->channel[ch] + in->channel[ch];
1169 out->channel[ch] = total;
1172 COMBINEF(*out, c, channels);
1178 static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1183 for (ch = 0; ch < (channels); ++ch) {
1185 int total = out->channel[ch] - in->channel[ch];
1188 c.channel[ch] = total;
1191 COMBINE(*out, c, channels);
1197 static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1202 for (ch = 0; ch < channels; ++ch) {
1204 double total = out->channel[ch] - in->channel[ch];
1207 c.channel[ch] = total;
1210 COMBINEF(*out, c, channels);
1216 static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1221 for (ch = 0; ch < (channels); ++ch) {
1223 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1225 COMBINE(*out, c, channels)
1231 static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1236 for (ch = 0; ch < (channels); ++ch) {
1238 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
1240 COMBINEF(*out, c, channels);
1246 static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1250 for (ch = 0; ch < channels; ++ch) {
1251 if (ch != 3 && out->channel[ch] < in->channel[ch])
1252 in->channel[ch] = out->channel[ch];
1254 COMBINE(*out, *in, channels);
1260 static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1264 for (ch = 0; ch < channels; ++ch) {
1265 if (ch != 3 && out->channel[ch] < in->channel[ch])
1266 in->channel[ch] = out->channel[ch];
1268 COMBINEF(*out, *in, channels);
1274 static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1278 for (ch = 0; ch < channels; ++ch) {
1279 if (ch != 3 && out->channel[ch] > in->channel[ch])
1280 in->channel[ch] = out->channel[ch];
1282 COMBINE(*out, *in, channels);
1288 static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1292 for (ch = 0; ch < channels; ++ch) {
1293 if (ch != 3 && out->channel[ch] > in->channel[ch])
1294 in->channel[ch] = out->channel[ch];
1296 COMBINEF(*out, *in, channels);
1302 static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1307 c.channel[0] = in->channel[0];
1309 c.channel[3] = in->channel[3];
1310 COMBINE(*out, c, channels);
1316 static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1321 c.channel[0] = in->channel[0];
1323 c.channel[3] = in->channel[3];
1324 COMBINEF(*out, c, channels);
1330 static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1335 c.channel[1] = in->channel[1];
1337 c.channel[3] = in->channel[3];
1338 COMBINE(*out, c, channels);
1344 static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1349 c.channel[1] = in->channel[1];
1351 c.channel[3] = in->channel[3];
1352 COMBINEF(*out, c, channels);
1358 static void combine_value(i_color *out, i_color *in, int channels, int count) {
1363 c.channel[2] = in->channel[2];
1365 c.channel[3] = in->channel[3];
1366 COMBINE(*out, c, channels);
1372 static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1378 c.channel[2] = in->channel[2];
1380 c.channel[3] = in->channel[3];
1381 COMBINEF(*out, c, channels);
1387 static void combine_color(i_color *out, i_color *in, int channels, int count) {
1392 c.channel[0] = in->channel[0];
1393 c.channel[1] = in->channel[1];
1395 c.channel[3] = in->channel[3];
1396 COMBINE(*out, c, channels);
1402 static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1408 c.channel[0] = in->channel[0];
1409 c.channel[1] = in->channel[1];
1411 c.channel[3] = in->channel[3];
1412 COMBINEF(*out, c, channels);
1424 Tony Cook <tony@develop-help.com>