+ }
+}
+
+static void combine_replace(i_color *, i_color *, int, int);
+static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
+static void combine_alphablend(i_color *, i_color *, int, int);
+static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
+static void combine_mult(i_color *, i_color *, int, int);
+static void combine_multf(i_fcolor *, i_fcolor *, int, int);
+static void combine_dissolve(i_color *, i_color *, int, int);
+static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
+static void combine_add(i_color *, i_color *, int, int);
+static void combine_addf(i_fcolor *, i_fcolor *, int, int);
+static void combine_subtract(i_color *, i_color *, int, int);
+static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
+static void combine_diff(i_color *, i_color *, int, int);
+static void combine_difff(i_fcolor *, i_fcolor *, int, int);
+static void combine_darken(i_color *, i_color *, int, int);
+static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
+static void combine_lighten(i_color *, i_color *, int, int);
+static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
+static void combine_hue(i_color *, i_color *, int, int);
+static void combine_huef(i_fcolor *, i_fcolor *, int, int);
+static void combine_sat(i_color *, i_color *, int, int);
+static void combine_satf(i_fcolor *, i_fcolor *, int, int);
+static void combine_value(i_color *, i_color *, int, int);
+static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
+static void combine_color(i_color *, i_color *, int, int);
+static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
+
+struct i_combines {
+ i_fill_combine_f combine;
+ i_fill_combinef_f combinef;
+} combines[] =
+{
+ { /* replace */
+ combine_replace,
+ combine_replacef,
+ },
+ { /* alpha blend */
+ combine_alphablend,
+ combine_alphablendf,
+ },
+ {
+ /* multiply */
+ combine_mult,
+ combine_multf,
+ },
+ {
+ /* dissolve */
+ combine_dissolve,
+ combine_dissolvef,
+ },
+ {
+ /* add */
+ combine_add,
+ combine_addf,
+ },
+ {
+ /* subtract */
+ combine_subtract,
+ combine_subtractf,
+ },
+ {
+ /* diff */
+ combine_diff,
+ combine_difff,
+ },
+ {
+ combine_lighten,
+ combine_lightenf,
+ },
+ {
+ combine_darken,
+ combine_darkenf,
+ },
+ {
+ combine_hue,
+ combine_huef,
+ },
+ {
+ combine_sat,
+ combine_satf,
+ },
+ {
+ combine_value,
+ combine_valuef,
+ },
+ {
+ combine_color,
+ combine_colorf,
+ },
+};
+
+/*
+=item i_get_combine(combine, color_func, fcolor_func)
+
+=cut
+*/
+
+void i_get_combine(int combine, i_fill_combine_f *color_func,
+ i_fill_combinef_f *fcolor_func) {
+ if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
+ combine = 0;
+
+ *color_func = combines[combine].combine;
+ *fcolor_func = combines[combine].combinef;
+}
+
+static void combine_replace(i_color *out, i_color *in, int channels, int count) {
+ while (count--) {
+ *out++ = *in++;
+ }
+}
+
+static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ while (count--) {
+ *out++ = *in++;
+ }
+}
+
+static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
+ while (count--) {
+ COMBINE(*out, *in, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ while (count--) {
+ COMBINEF(*out, *in, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_mult(i_color *out, i_color *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ i_color c = *in;
+ double mult[MAXCHANNELS];
+ mult[3] = in->channel[3];
+ for (ch = 0; ch < (channels); ++ch) {
+ if (ch != 3)
+ mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
+ }
+ COMBINEA(*out, mult, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ i_fcolor c = *in;
+ for (ch = 0; ch < channels; ++ch) {
+ if (ch != 3)
+ c.channel[ch] = out->channel[ch] * in->channel[ch];
+ }
+ COMBINEF(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ if (in->channel[3] > rand() * (255.0 / RAND_MAX))
+ COMBINE(*out, *in, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ if (in->channel[3] > rand() * (1.0 / RAND_MAX))
+ COMBINEF(*out, *in, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_add(i_color *out, i_color *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ i_color c = *in;
+ for (ch = 0; ch < (channels); ++ch) {
+ if (ch != 3) {
+ int total = out->channel[ch] + in->channel[ch];
+ if (total > 255)
+ total = 255;
+ c.channel[ch] = total;
+ }
+ }
+ COMBINE(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ i_fcolor c = *in;
+ for (ch = 0; ch < (channels); ++ch) {
+ if (ch != 3) {
+ double total = out->channel[ch] + in->channel[ch];
+ if (total > 1.0)
+ total = 1.0;
+ out->channel[ch] = total;
+ }
+ }
+ COMBINEF(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ i_color c = *in;
+ for (ch = 0; ch < (channels); ++ch) {
+ if (ch != 3) {
+ int total = out->channel[ch] - in->channel[ch];
+ if (total < 0)
+ total = 0;
+ c.channel[ch] = total;
+ }
+ }
+ COMBINE(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ i_fcolor c = *in;
+ for (ch = 0; ch < channels; ++ch) {
+ if (ch != 3) {
+ double total = out->channel[ch] - in->channel[ch];
+ if (total < 0)
+ total = 0;
+ c.channel[ch] = total;
+ }
+ }
+ COMBINEF(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_diff(i_color *out, i_color *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ i_color c = *in;
+ for (ch = 0; ch < (channels); ++ch) {
+ if (ch != 3)
+ c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
+ }
+ COMBINE(*out, c, channels)
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ i_fcolor c = *in;
+ for (ch = 0; ch < (channels); ++ch) {
+ if (ch != 3)
+ c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);