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) {
684 if ((mask >>= 1) == 0)
690 =item fill_hatchf(fill, x, y, width, channels, data)
692 The floating sample fill function for hatched fills.
696 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
698 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
699 int byte = f->hatch[(y + f->dy) & 7];
700 int xpos = (x + f->dx) & 7;
701 int mask = 128 >> xpos;
703 while (width-- > 0) {
709 if ((mask >>= 1) == 0)
714 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
715 /* linear interpolation */
716 static i_color interp_i_color(i_color before, i_color after, double pos,
722 for (ch = 0; ch < channels; ++ch)
723 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
724 if (channels > 3 && out.channel[3])
725 for (ch = 0; ch < channels; ++ch)
727 int temp = out.channel[ch] * 255 / out.channel[3];
730 out.channel[ch] = temp;
736 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
737 /* linear interpolation */
738 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
744 for (ch = 0; ch < channels; ++ch)
745 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
747 for (ch = 0; ch < channels; ++ch)
749 int temp = out.channel[ch] / out.channel[3];
752 out.channel[ch] = temp;
759 =item fill_image(fill, x, y, width, channels, data, work)
763 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
765 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
772 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
773 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
774 double ix = floor(rx / f->src->xsize);
775 double iy = floor(ry / f->src->ysize);
782 ix = floor(rx / f->src->xsize);
786 iy = floor(ry / f->src->ysize);
788 rx -= ix * f->src->xsize;
789 ry -= iy * f->src->ysize;
791 for (dy = 0; dy < 2; ++dy) {
792 if ((int)rx == f->src->xsize-1) {
793 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
794 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
797 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
800 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
802 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
808 /* this should be possible to optimize to use i_glin() */
812 int ix = rx / f->src->xsize;
813 int iy = ry / f->src->ysize;
817 ix = rx / f->src->xsize;
821 iy = ry / f->src->xsize;
823 rx -= ix * f->src->xsize;
824 ry -= iy * f->src->ysize;
825 i_gpix(f->src, rx, ry, out);
830 if (f->src->channels == 3) {
831 /* just set the alpha */
832 for (i = 0; i < width; ++i) {
833 data->channel[3] = 255;
837 else if (f->src->channels == 2) {
838 /* copy the alpha to channel 3, duplicate the grey value */
839 for (i = 0; i < width; ++i) {
840 data->channel[3] = data->channel[1];
841 data->channel[1] = data->channel[2] = data->channel[0];
845 else if (f->src->channels == 1) {
846 /* set the alpha, duplicate grey */
847 for (i = 0; i < width; ++i) {
848 data->channel[3] = 255;
849 data->channel[1] = data->channel[2] = data->channel[0];
856 =item fill_image(fill, x, y, width, channels, data, work)
860 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
862 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
868 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
869 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
870 double ix = floor(rx / f->src->xsize);
871 double iy = floor(ry / f->src->ysize);
878 ix = floor(rx / f->src->xsize);
882 iy = floor(ry / f->src->ysize);
884 rx -= ix * f->src->xsize;
885 ry -= iy * f->src->ysize;
887 for (dy = 0; dy < 2; ++dy) {
888 if ((int)rx == f->src->xsize-1) {
889 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
890 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
893 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
896 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
898 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
904 /* this should be possible to optimize to use i_glin() */
908 int ix = rx / f->src->xsize;
909 int iy = ry / f->src->ysize;
913 ix = rx / f->src->xsize;
917 iy = ry / f->src->xsize;
919 rx -= ix * f->src->xsize;
920 ry -= iy * f->src->ysize;
921 i_gpixf(f->src, rx, ry, data);
926 if (f->src->channels == 3) {
927 /* just set the alpha */
928 for (i = 0; i < width; ++i) {
929 data->channel[3] = 1.0;
933 else if (f->src->channels == 2) {
934 /* copy the alpha to channel 3, duplicate the grey value */
935 for (i = 0; i < width; ++i) {
936 data->channel[3] = data->channel[1];
937 data->channel[1] = data->channel[2] = data->channel[0];
941 else if (f->src->channels == 1) {
942 /* set the alpha, duplicate grey */
943 for (i = 0; i < width; ++i) {
944 data->channel[3] = 1.0;
945 data->channel[1] = data->channel[2] = data->channel[0];
951 static void combine_replace(i_color *, i_color *, int, int);
952 static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
953 static void combine_alphablend(i_color *, i_color *, int, int);
954 static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
955 static void combine_mult(i_color *, i_color *, int, int);
956 static void combine_multf(i_fcolor *, i_fcolor *, int, int);
957 static void combine_dissolve(i_color *, i_color *, int, int);
958 static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
959 static void combine_add(i_color *, i_color *, int, int);
960 static void combine_addf(i_fcolor *, i_fcolor *, int, int);
961 static void combine_subtract(i_color *, i_color *, int, int);
962 static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
963 static void combine_diff(i_color *, i_color *, int, int);
964 static void combine_difff(i_fcolor *, i_fcolor *, int, int);
965 static void combine_darken(i_color *, i_color *, int, int);
966 static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
967 static void combine_lighten(i_color *, i_color *, int, int);
968 static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
969 static void combine_hue(i_color *, i_color *, int, int);
970 static void combine_huef(i_fcolor *, i_fcolor *, int, int);
971 static void combine_sat(i_color *, i_color *, int, int);
972 static void combine_satf(i_fcolor *, i_fcolor *, int, int);
973 static void combine_value(i_color *, i_color *, int, int);
974 static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
975 static void combine_color(i_color *, i_color *, int, int);
976 static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
978 static struct i_combines {
979 i_fill_combine_f combine;
980 i_fill_combinef_f combinef;
1043 =item i_get_combine(combine, color_func, fcolor_func)
1048 void i_get_combine(int combine, i_fill_combine_f *color_func,
1049 i_fill_combinef_f *fcolor_func) {
1050 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
1053 *color_func = combines[combine].combine;
1054 *fcolor_func = combines[combine].combinef;
1057 static void combine_replace(i_color *out, i_color *in, int channels, int count) {
1063 static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1069 static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
1071 COMBINE(*out, *in, channels);
1077 static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1079 COMBINEF(*out, *in, channels);
1085 static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1089 double mult[MAXCHANNELS];
1090 mult[3] = in->channel[3];
1091 for (ch = 0; ch < (channels); ++ch) {
1093 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1095 COMBINEA(*out, mult, channels);
1101 static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1106 for (ch = 0; ch < channels; ++ch) {
1108 c.channel[ch] = out->channel[ch] * in->channel[ch];
1110 COMBINEF(*out, c, channels);
1116 static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
1118 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1119 COMBINE(*out, *in, channels);
1125 static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1127 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1128 COMBINEF(*out, *in, channels);
1134 static void combine_add(i_color *out, i_color *in, int channels, int count) {
1139 for (ch = 0; ch < (channels); ++ch) {
1141 int total = out->channel[ch] + in->channel[ch];
1144 c.channel[ch] = total;
1147 COMBINE(*out, c, channels);
1153 static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1158 for (ch = 0; ch < (channels); ++ch) {
1160 double total = out->channel[ch] + in->channel[ch];
1163 out->channel[ch] = total;
1166 COMBINEF(*out, c, channels);
1172 static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1177 for (ch = 0; ch < (channels); ++ch) {
1179 int total = out->channel[ch] - in->channel[ch];
1182 c.channel[ch] = total;
1185 COMBINE(*out, c, channels);
1191 static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1196 for (ch = 0; ch < channels; ++ch) {
1198 double total = out->channel[ch] - in->channel[ch];
1201 c.channel[ch] = total;
1204 COMBINEF(*out, c, channels);
1210 static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1215 for (ch = 0; ch < (channels); ++ch) {
1217 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1219 COMBINE(*out, c, channels)
1225 static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1230 for (ch = 0; ch < (channels); ++ch) {
1232 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
1234 COMBINEF(*out, c, channels);
1240 static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1244 for (ch = 0; ch < channels; ++ch) {
1245 if (ch != 3 && out->channel[ch] < in->channel[ch])
1246 in->channel[ch] = out->channel[ch];
1248 COMBINE(*out, *in, channels);
1254 static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1258 for (ch = 0; ch < channels; ++ch) {
1259 if (ch != 3 && out->channel[ch] < in->channel[ch])
1260 in->channel[ch] = out->channel[ch];
1262 COMBINEF(*out, *in, channels);
1268 static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1272 for (ch = 0; ch < channels; ++ch) {
1273 if (ch != 3 && out->channel[ch] > in->channel[ch])
1274 in->channel[ch] = out->channel[ch];
1276 COMBINE(*out, *in, channels);
1282 static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1286 for (ch = 0; ch < channels; ++ch) {
1287 if (ch != 3 && out->channel[ch] > in->channel[ch])
1288 in->channel[ch] = out->channel[ch];
1290 COMBINEF(*out, *in, channels);
1296 static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1301 c.channel[0] = in->channel[0];
1303 c.channel[3] = in->channel[3];
1304 COMBINE(*out, c, channels);
1310 static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1315 c.channel[0] = in->channel[0];
1317 c.channel[3] = in->channel[3];
1318 COMBINEF(*out, c, channels);
1324 static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1329 c.channel[1] = in->channel[1];
1331 c.channel[3] = in->channel[3];
1332 COMBINE(*out, c, channels);
1338 static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1343 c.channel[1] = in->channel[1];
1345 c.channel[3] = in->channel[3];
1346 COMBINEF(*out, c, channels);
1352 static void combine_value(i_color *out, i_color *in, int channels, int count) {
1357 c.channel[2] = in->channel[2];
1359 c.channel[3] = in->channel[3];
1360 COMBINE(*out, c, channels);
1366 static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1372 c.channel[2] = in->channel[2];
1374 c.channel[3] = in->channel[3];
1375 COMBINEF(*out, c, channels);
1381 static void combine_color(i_color *out, i_color *in, int channels, int count) {
1386 c.channel[0] = in->channel[0];
1387 c.channel[1] = in->channel[1];
1389 c.channel[3] = in->channel[3];
1390 COMBINE(*out, c, channels);
1396 static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1402 c.channel[0] = in->channel[0];
1403 c.channel[1] = in->channel[1];
1405 c.channel[3] = in->channel[3];
1406 COMBINEF(*out, c, channels);
1418 Tony Cook <tony@develop-help.com>