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)
200 Call to destroy any fill object.
206 i_fill_destroy(i_fill_t *fill) {
208 (fill->destroy)(fill);
213 =item i_new_fill_solidf(color, combine)
217 Create a solid fill based on a float color.
219 If combine is non-zero then alpha values will be combined.
225 i_new_fill_solidf(const i_fcolor *c, int combine) {
227 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
230 *fill = base_solid_fill_comb;
231 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
234 *fill = base_solid_fill;
236 for (ch = 0; ch < MAXCHANNELS; ++ch) {
237 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
244 =item i_new_fill_solid(color, combine)
248 Create a solid fill based on an 8-bit color.
250 If combine is non-zero then alpha values will be combined.
256 i_new_fill_solid(const i_color *c, int combine) {
258 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
261 *fill = base_solid_fill_comb;
262 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
265 *fill = base_solid_fill;
267 for (ch = 0; ch < MAXCHANNELS; ++ch) {
268 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
275 builtin_hatches[][8] =
278 /* 1x1 checkerboard */
279 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
282 /* 2x2 checkerboard */
283 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
286 /* 4 x 4 checkerboard */
287 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
290 /* single vertical lines */
291 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
294 /* double vertical lines */
295 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
298 /* quad vertical lines */
299 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
303 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
311 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
315 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
319 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
323 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
327 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
331 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
335 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
339 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
343 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
351 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
355 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
359 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
362 /* single cross hatch */
363 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
366 /* double cross hatch */
367 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
370 /* vertical lozenge */
371 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
374 /* horizontal lozenge */
375 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
378 /* scales overlapping downwards */
379 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
382 /* scales overlapping upwards */
383 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
386 /* scales overlapping leftwards */
387 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
390 /* scales overlapping rightwards */
391 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
395 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
399 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
403 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
412 unsigned char hatch[8];
416 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
418 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
422 i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg,
423 int combine, int hatch, const unsigned char *cust_hatch,
427 =item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
431 Creates a new hatched fill with the fg color used for the 1 bits in
432 the hatch and bg for the 0 bits. If combine is non-zero alpha values
435 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
436 hash definition, with the high-bits to the left.
438 If cust_hatch is NULL then one of the standard hatches is used.
440 (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.
445 i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
446 const unsigned char *cust_hatch, int dx, int dy) {
447 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
452 =item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
456 Creates a new hatched fill with the fg color used for the 1 bits in
457 the hatch and bg for the 0 bits. If combine is non-zero alpha values
460 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
461 hash definition, with the high-bits to the left.
463 If cust_hatch is NULL then one of the standard hatches is used.
465 (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.
470 i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
471 const unsigned char *cust_hatch, int dx, int dy) {
472 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
476 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
478 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
480 struct i_fill_image_t {
489 =item i_new_fill_image(im, matrix, xoff, yoff, combine)
493 Create an image based fill.
495 matrix is an array of 9 doubles representing a transformation matrix.
497 xoff and yoff are the offset into the image to start filling from.
502 i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) {
503 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
505 fill->base.fill_with_color = fill_image;
506 fill->base.fill_with_fcolor = fill_imagef;
507 fill->base.destroy = NULL;
510 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
513 fill->base.combine = NULL;
514 fill->base.combinef = NULL;
524 fill->has_matrix = 1;
525 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
528 fill->has_matrix = 0;
534 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
539 =head1 INTERNAL FUNCTIONS
543 =item fill_solid(fill, x, y, width, channels, data)
545 The 8-bit sample fill function for non-combining solid fills.
550 fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
552 while (width-- > 0) {
553 *data++ = T_SOLID_FILL(fill)->c;
558 =item fill_solid(fill, x, y, width, channels, data)
560 The floating sample fill function for non-combining solid fills.
565 fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
567 while (width-- > 0) {
568 *data++ = T_SOLID_FILL(fill)->fc;
573 =item fill_solid_comb(fill, x, y, width, channels, data)
575 The 8-bit sample fill function for combining solid fills.
580 fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels,
582 i_color c = T_SOLID_FILL(fill)->c;
584 while (width-- > 0) {
590 =item fill_solidf_comb(fill, x, y, width, channels, data)
592 The floating sample fill function for combining solid fills.
597 fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels,
599 i_fcolor c = T_SOLID_FILL(fill)->fc;
601 while (width-- > 0) {
607 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
609 Implements creation of hatch fill objects.
615 i_new_hatch_low(const i_color *fg, const i_color *bg,
616 const i_fcolor *ffg, const i_fcolor *fbg,
617 int combine, int hatch, const unsigned char *cust_hatch,
619 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
621 fill->base.fill_with_color = fill_hatch;
622 fill->base.fill_with_fcolor = fill_hatchf;
623 fill->base.destroy = NULL;
624 /* Some Sun C didn't like the condition expressions that were here.
625 See https://rt.cpan.org/Ticket/Display.html?id=21944
630 fill->fg = fcolor_to_color(ffg);
634 fill->bg = fcolor_to_color(fbg);
638 fill->ffg = color_to_fcolor(fg);
642 fill->fbg = color_to_fcolor(bg);
644 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
647 fill->base.combine = NULL;
648 fill->base.combinef = NULL;
651 memcpy(fill->hatch, cust_hatch, 8);
654 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
656 memcpy(fill->hatch, builtin_hatches[hatch], 8);
665 =item fill_hatch(fill, x, y, width, channels, data)
667 The 8-bit sample fill function for hatched fills.
671 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
673 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
674 int byte = f->hatch[(y + f->dy) & 7];
675 int xpos = (x + f->dx) & 7;
676 int mask = 128 >> xpos;
678 while (width-- > 0) {
679 *data++ = (byte & mask) ? f->fg : f->bg;
681 if ((mask >>= 1) == 0)
687 =item fill_hatchf(fill, x, y, width, channels, data)
689 The floating sample fill function for hatched fills.
693 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
695 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
696 int byte = f->hatch[(y + f->dy) & 7];
697 int xpos = (x + f->dx) & 7;
698 int mask = 128 >> xpos;
700 while (width-- > 0) {
701 *data++ = (byte & mask) ? f->ffg : f->fbg;
703 if ((mask >>= 1) == 0)
708 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
709 /* linear interpolation */
710 static i_color interp_i_color(i_color before, i_color after, double pos,
716 for (ch = 0; ch < channels; ++ch)
717 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
718 if (channels > 3 && out.channel[3])
719 for (ch = 0; ch < channels; ++ch)
721 int temp = out.channel[ch] * 255 / out.channel[3];
724 out.channel[ch] = temp;
730 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
731 /* linear interpolation */
732 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
738 for (ch = 0; ch < channels; ++ch)
739 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
741 for (ch = 0; ch < channels; ++ch)
743 int temp = out.channel[ch] / out.channel[3];
746 out.channel[ch] = temp;
753 =item fill_image(fill, x, y, width, channels, data, work)
757 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
759 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
766 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
767 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
768 double ix = floor(rx / f->src->xsize);
769 double iy = floor(ry / f->src->ysize);
776 ix = floor(rx / f->src->xsize);
780 iy = floor(ry / f->src->ysize);
782 rx -= ix * f->src->xsize;
783 ry -= iy * f->src->ysize;
785 for (dy = 0; dy < 2; ++dy) {
786 if ((int)rx == f->src->xsize-1) {
787 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
788 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
791 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
794 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
796 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
802 /* this should be possible to optimize to use i_glin() */
806 int ix = rx / f->src->xsize;
807 int iy = ry / f->src->ysize;
811 ix = rx / f->src->xsize;
815 iy = ry / f->src->xsize;
817 rx -= ix * f->src->xsize;
818 ry -= iy * f->src->ysize;
819 i_gpix(f->src, rx, ry, out);
824 if (f->src->channels == 3) {
825 /* just set the alpha */
826 for (i = 0; i < width; ++i) {
827 data->channel[3] = 255;
831 else if (f->src->channels == 2) {
832 /* copy the alpha to channel 3, duplicate the grey value */
833 for (i = 0; i < width; ++i) {
834 data->channel[3] = data->channel[1];
835 data->channel[1] = data->channel[2] = data->channel[0];
839 else if (f->src->channels == 1) {
840 /* set the alpha, duplicate grey */
841 for (i = 0; i < width; ++i) {
842 data->channel[3] = 255;
843 data->channel[1] = data->channel[2] = data->channel[0];
850 =item fill_image(fill, x, y, width, channels, data, work)
854 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
856 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
862 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
863 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
864 double ix = floor(rx / f->src->xsize);
865 double iy = floor(ry / f->src->ysize);
872 ix = floor(rx / f->src->xsize);
876 iy = floor(ry / f->src->ysize);
878 rx -= ix * f->src->xsize;
879 ry -= iy * f->src->ysize;
881 for (dy = 0; dy < 2; ++dy) {
882 if ((int)rx == f->src->xsize-1) {
883 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
884 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
887 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
890 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
892 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
898 /* this should be possible to optimize to use i_glin() */
902 int ix = rx / f->src->xsize;
903 int iy = ry / f->src->ysize;
907 ix = rx / f->src->xsize;
911 iy = ry / f->src->xsize;
913 rx -= ix * f->src->xsize;
914 ry -= iy * f->src->ysize;
915 i_gpixf(f->src, rx, ry, data);
920 if (f->src->channels == 3) {
921 /* just set the alpha */
922 for (i = 0; i < width; ++i) {
923 data->channel[3] = 1.0;
927 else if (f->src->channels == 2) {
928 /* copy the alpha to channel 3, duplicate the grey value */
929 for (i = 0; i < width; ++i) {
930 data->channel[3] = data->channel[1];
931 data->channel[1] = data->channel[2] = data->channel[0];
935 else if (f->src->channels == 1) {
936 /* set the alpha, duplicate grey */
937 for (i = 0; i < width; ++i) {
938 data->channel[3] = 1.0;
939 data->channel[1] = data->channel[2] = data->channel[0];
945 static void combine_replace(i_color *, i_color *, int, int);
946 static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
947 static void combine_alphablend(i_color *, i_color *, int, int);
948 static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
949 static void combine_mult(i_color *, i_color *, int, int);
950 static void combine_multf(i_fcolor *, i_fcolor *, int, int);
951 static void combine_dissolve(i_color *, i_color *, int, int);
952 static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
953 static void combine_add(i_color *, i_color *, int, int);
954 static void combine_addf(i_fcolor *, i_fcolor *, int, int);
955 static void combine_subtract(i_color *, i_color *, int, int);
956 static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
957 static void combine_diff(i_color *, i_color *, int, int);
958 static void combine_difff(i_fcolor *, i_fcolor *, int, int);
959 static void combine_darken(i_color *, i_color *, int, int);
960 static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
961 static void combine_lighten(i_color *, i_color *, int, int);
962 static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
963 static void combine_hue(i_color *, i_color *, int, int);
964 static void combine_huef(i_fcolor *, i_fcolor *, int, int);
965 static void combine_sat(i_color *, i_color *, int, int);
966 static void combine_satf(i_fcolor *, i_fcolor *, int, int);
967 static void combine_value(i_color *, i_color *, int, int);
968 static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
969 static void combine_color(i_color *, i_color *, int, int);
970 static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
972 static struct i_combines {
973 i_fill_combine_f combine;
974 i_fill_combinef_f combinef;
1037 =item i_get_combine(combine, color_func, fcolor_func)
1042 void i_get_combine(int combine, i_fill_combine_f *color_func,
1043 i_fill_combinef_f *fcolor_func) {
1044 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
1047 *color_func = combines[combine].combine;
1048 *fcolor_func = combines[combine].combinef;
1051 static void combine_replace(i_color *out, i_color *in, int channels, int count) {
1057 static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1063 static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
1065 COMBINE(*out, *in, channels);
1071 static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1073 COMBINEF(*out, *in, channels);
1079 static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1083 double mult[MAXCHANNELS];
1084 mult[3] = in->channel[3];
1085 for (ch = 0; ch < (channels); ++ch) {
1087 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1089 COMBINEA(*out, mult, channels);
1095 static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1100 for (ch = 0; ch < channels; ++ch) {
1102 c.channel[ch] = out->channel[ch] * in->channel[ch];
1104 COMBINEF(*out, c, channels);
1110 static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
1112 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1113 COMBINE(*out, *in, channels);
1119 static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1121 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1122 COMBINEF(*out, *in, channels);
1128 static void combine_add(i_color *out, i_color *in, int channels, int count) {
1133 for (ch = 0; ch < (channels); ++ch) {
1135 int total = out->channel[ch] + in->channel[ch];
1138 c.channel[ch] = total;
1141 COMBINE(*out, c, channels);
1147 static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1152 for (ch = 0; ch < (channels); ++ch) {
1154 double total = out->channel[ch] + in->channel[ch];
1157 out->channel[ch] = total;
1160 COMBINEF(*out, c, channels);
1166 static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1171 for (ch = 0; ch < (channels); ++ch) {
1173 int total = out->channel[ch] - in->channel[ch];
1176 c.channel[ch] = total;
1179 COMBINE(*out, c, channels);
1185 static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1190 for (ch = 0; ch < channels; ++ch) {
1192 double total = out->channel[ch] - in->channel[ch];
1195 c.channel[ch] = total;
1198 COMBINEF(*out, c, channels);
1204 static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1209 for (ch = 0; ch < (channels); ++ch) {
1211 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1213 COMBINE(*out, c, channels)
1219 static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1224 for (ch = 0; ch < (channels); ++ch) {
1226 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
1228 COMBINEF(*out, c, channels);
1234 static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1238 for (ch = 0; ch < channels; ++ch) {
1239 if (ch != 3 && out->channel[ch] < in->channel[ch])
1240 in->channel[ch] = out->channel[ch];
1242 COMBINE(*out, *in, channels);
1248 static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1252 for (ch = 0; ch < channels; ++ch) {
1253 if (ch != 3 && out->channel[ch] < in->channel[ch])
1254 in->channel[ch] = out->channel[ch];
1256 COMBINEF(*out, *in, channels);
1262 static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1266 for (ch = 0; ch < channels; ++ch) {
1267 if (ch != 3 && out->channel[ch] > in->channel[ch])
1268 in->channel[ch] = out->channel[ch];
1270 COMBINE(*out, *in, channels);
1276 static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1280 for (ch = 0; ch < channels; ++ch) {
1281 if (ch != 3 && out->channel[ch] > in->channel[ch])
1282 in->channel[ch] = out->channel[ch];
1284 COMBINEF(*out, *in, channels);
1290 static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1295 c.channel[0] = in->channel[0];
1297 c.channel[3] = in->channel[3];
1298 COMBINE(*out, c, channels);
1304 static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1309 c.channel[0] = in->channel[0];
1311 c.channel[3] = in->channel[3];
1312 COMBINEF(*out, c, channels);
1318 static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1323 c.channel[1] = in->channel[1];
1325 c.channel[3] = in->channel[3];
1326 COMBINE(*out, c, channels);
1332 static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1337 c.channel[1] = in->channel[1];
1339 c.channel[3] = in->channel[3];
1340 COMBINEF(*out, c, channels);
1346 static void combine_value(i_color *out, i_color *in, int channels, int count) {
1351 c.channel[2] = in->channel[2];
1353 c.channel[3] = in->channel[3];
1354 COMBINE(*out, c, channels);
1360 static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1366 c.channel[2] = in->channel[2];
1368 c.channel[3] = in->channel[3];
1369 COMBINEF(*out, c, channels);
1375 static void combine_color(i_color *out, i_color *in, int channels, int count) {
1380 c.channel[0] = in->channel[0];
1381 c.channel[1] = in->channel[1];
1383 c.channel[3] = in->channel[3];
1384 COMBINE(*out, c, channels);
1390 static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1396 c.channel[0] = in->channel[0];
1397 c.channel[1] = in->channel[1];
1399 c.channel[3] = in->channel[3];
1400 COMBINEF(*out, c, channels);
1412 Tony Cook <tony@develop-help.com>