fill = i_new_fill_solid(&c1, combine);
fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
+ fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
i_fill_destroy(fill);
=head1 DESCRIPTION
Fountain fill is implemented by L<filters.c>.
+Other fills that could be implemented include:
+
+=over
+
+=item *
+
+image - an image tiled over the fill area, with an offset either
+horizontally or vertically.
+
+=item *
+
+checkerboard - combine 2 fills in a checkerboard
+
+=item *
+
+combine - combine the levels of 2 other fills based in the levels of
+an image
+
+=item *
+
+regmach - use the register machine to generate colors
+
+=back
+
=over
=cut
for (ch = 0; ch < MAXCHANNELS; ++ch)
out.channel[ch] = SampleFTo8(c->channel[ch]);
+
+ return out;
}
static i_fcolor color_to_fcolor(i_color *c) {
int ch;
- i_color out;
+ i_fcolor out;
for (ch = 0; ch < MAXCHANNELS; ++ch)
out.channel[ch] = Sample8ToF(c->channel[ch]);
-}
-typedef struct
-{
- i_fill_t base;
- i_color c;
- i_fcolor fc;
-} i_fill_solid_t;
+ return out;
+}
+/* alpha combine in with out */
#define COMBINE(out, in, channels) \
{ \
int ch; \
} \
}
+/* alpha combine in with out, in this case in is a simple array of
+ samples, potentially not integers - the mult combiner uses doubles
+ for accuracy */
+#define COMBINEA(out, in, channels) \
+ { \
+ int ch; \
+ for (ch = 0; ch < (channels); ++ch) { \
+ (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
+ + (in)[ch] * (in)[3]) / 255; \
+ } \
+ }
+
#define COMBINEF(out, in, channels) \
{ \
int ch; \
} \
}
+typedef struct
+{
+ i_fill_t base;
+ i_color c;
+ i_fcolor fc;
+} i_fill_solid_t;
+
static void fill_solid(i_fill_t *, int x, int y, int width, int channels,
i_color *);
static void fill_solidf(i_fill_t *, int x, int y, int width, int channels,
fill_solid,
fill_solidf,
NULL,
- 0
+ NULL,
+ NULL,
},
};
static i_fill_solid_t base_solid_fill_comb =
fill_solid_comb,
fill_solidf_comb,
NULL,
- 1
+ NULL,
+ NULL,
},
};
int ch;
i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
- if (combine && c->channel[3] < 1.0)
+ if (combine) {
*fill = base_solid_fill_comb;
+ i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
+ }
else
*fill = base_solid_fill;
fill->fc = *c;
int ch;
i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
- if (combine && c->channel[3] < 255)
+ if (combine) {
*fill = base_solid_fill_comb;
+ i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
+ }
else
*fill = base_solid_fill;
fill->c = *c;
dx, dy);
}
+static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
+ i_color *data);
+static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
+ i_fcolor *data);
+struct i_fill_image_t {
+ i_fill_t base;
+ i_img *src;
+ int xoff, yoff;
+ int has_matrix;
+ double matrix[9];
+};
+
+/*
+=item i_new_fill_image(im, matrix, xoff, yoff, combine)
+
+Create an image based fill.
+
+=cut
+*/
+i_fill_t *
+i_new_fill_image(i_img *im, double *matrix, int xoff, int yoff, int combine) {
+ struct i_fill_image_t *fill = mymalloc(sizeof(*fill));
+
+ fill->base.fill_with_color = fill_image;
+ fill->base.fill_with_fcolor = fill_imagef;
+ fill->base.destroy = NULL;
+
+ if (combine) {
+ i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
+ }
+ else {
+ fill->base.combine = NULL;
+ fill->base.combinef = NULL;
+ }
+ fill->src = im;
+ if (xoff < 0)
+ xoff += im->xsize;
+ fill->xoff = xoff;
+ if (yoff < 0)
+ yoff += im->ysize;
+ fill->yoff = yoff;
+ if (matrix) {
+ fill->has_matrix = 1;
+ memcpy(fill->matrix, matrix, sizeof(fill->matrix));
+ }
+ else
+ fill->has_matrix = 0;
+
+ return &fill->base;
+}
+
+
#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
/*
*/
static void
fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels,
- i_color *data) {
+ i_color *data) {
i_color c = T_SOLID_FILL(fill)->c;
while (width-- > 0) {
- COMBINE(*data, c, channels);
- ++data;
+ *data++ = c;
}
}
i_fcolor c = T_SOLID_FILL(fill)->fc;
while (width-- > 0) {
- COMBINEF(*data, c, channels);
- ++data;
+ *data++ = c;
}
}
fill->bg = bg ? *bg : fcolor_to_color(fbg);
fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
- fill->base.combines =
- combine && (fill->ffg.channel[0] < 1 || fill->fbg.channel[0] < 1);
+ if (combine) {
+ i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
+ }
+ else {
+ fill->base.combine = NULL;
+ fill->base.combinef = NULL;
+ }
if (cust_hatch) {
memcpy(fill->hatch, cust_hatch, 8);
}
The 8-bit sample fill function for hatched fills.
-=back
+=cut
*/
static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
i_color *data) {
int mask = 128 >> xpos;
while (width-- > 0) {
- i_color c = (byte & mask) ? f->fg : f->bg;
-
- if (f->base.combines) {
- COMBINE(*data, c, channels);
- }
- else {
- *data = c;
- }
- ++data;
+ *data++ = (byte & mask) ? f->fg : f->bg;
+
if ((mask >>= 1) == 0)
mask = 128;
}
int mask = 128 >> xpos;
while (width-- > 0) {
- i_fcolor c = (byte & mask) ? f->ffg : f->fbg;
+ *data++ = (byte & mask) ? f->ffg : f->fbg;
+
+ if ((mask >>= 1) == 0)
+ mask = 128;
+ }
+}
+
+/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
+/* linear interpolation */
+static i_color interp_i_color(i_color before, i_color after, double pos,
+ int channels) {
+ i_color out;
+ int ch;
+
+ pos -= floor(pos);
+ for (ch = 0; ch < channels; ++ch)
+ out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
+ if (out.channel[3])
+ for (ch = 0; ch < channels; ++ch)
+ if (ch != 3) {
+ int temp = out.channel[ch] * 255 / out.channel[3];
+ if (temp > 255)
+ temp = 255;
+ out.channel[ch] = temp;
+ }
+
+ return out;
+}
+
+/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
+/* linear interpolation */
+static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
+ int channels) {
+ i_fcolor out;
+ int ch;
+
+ pos -= floor(pos);
+ for (ch = 0; ch < channels; ++ch)
+ out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
+ if (out.channel[3])
+ for (ch = 0; ch < channels; ++ch)
+ if (ch != 3) {
+ int temp = out.channel[ch] / out.channel[3];
+ if (temp > 1.0)
+ temp = 1.0;
+ out.channel[ch] = temp;
+ }
+
+ return out;
+}
+
+/*
+=item fill_image(fill, x, y, width, channels, data, work)
+
+=cut
+*/
+static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
+ i_color *data) {
+ struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
+ int i = 0;
+ i_color c;
+
+ if (f->has_matrix) {
+ /* the hard way */
+ while (i < width) {
+ double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
+ double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
+ double ix = floor(rx / f->src->xsize);
+ double iy = floor(ry / f->src->ysize);
+ i_color c[2][2];
+ i_color c2[2];
+ int dy;
+
+ if (f->xoff) {
+ rx += iy * f->xoff;
+ ix = floor(rx / f->src->xsize);
+ }
+ else if (f->yoff) {
+ ry += ix * f->yoff;
+ iy = floor(ry / f->src->ysize);
+ }
+ rx -= ix * f->src->xsize;
+ ry -= iy * f->src->ysize;
+
+ for (dy = 0; dy < 2; ++dy) {
+ if ((int)rx == f->src->xsize-1) {
+ i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
+ i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
+ }
+ else {
+ i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
+ c[dy]);
+ }
+ c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
+ }
+ *data++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
+ ++i;
+ }
+ }
+ else {
+ /* the easy way */
+ /* this should be possible to optimize to use i_glin() */
+ while (i < width) {
+ int rx = x+i;
+ int ry = y;
+ int ix = rx / f->src->xsize;
+ int iy = ry / f->src->ysize;
+
+ if (f->xoff) {
+ rx += iy * f->xoff;
+ ix = rx / f->src->xsize;
+ }
+ else if (f->yoff) {
+ ry += ix * f->yoff;
+ iy = ry / f->src->xsize;
+ }
+ rx -= ix * f->src->xsize;
+ ry -= iy * f->src->ysize;
+ i_gpix(f->src, rx, ry, data);
+ ++data;
+ ++i;
+ }
+ }
+}
- if (f->base.combines) {
- COMBINE(*data, c, channels);
+/*
+=item fill_image(fill, x, y, width, channels, data, work)
+
+=cut
+*/
+static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
+ i_fcolor *data) {
+ struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
+ int i = 0;
+ i_fcolor c;
+
+ if (f->has_matrix) {
+ /* the hard way */
+ while (i < width) {
+ double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
+ double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
+ double ix = floor(rx / f->src->xsize);
+ double iy = floor(ry / f->src->ysize);
+ i_fcolor c[2][2];
+ i_fcolor c2[2];
+ int dy;
+
+ if (f->xoff) {
+ rx += iy * f->xoff;
+ ix = floor(rx / f->src->xsize);
+ }
+ else if (f->yoff) {
+ ry += ix * f->yoff;
+ iy = floor(ry / f->src->ysize);
+ }
+ rx -= ix * f->src->xsize;
+ ry -= iy * f->src->ysize;
+
+ for (dy = 0; dy < 2; ++dy) {
+ if ((int)rx == f->src->xsize-1) {
+ i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
+ i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
+ }
+ else {
+ i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
+ c[dy]);
+ }
+ c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
+ }
+ *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
+ ++i;
}
- else {
- *data = c;
+ }
+ else {
+ /* the easy way */
+ /* this should be possible to optimize to use i_glin() */
+ while (i < width) {
+ int rx = x+i;
+ int ry = y;
+ int ix = rx / f->src->xsize;
+ int iy = ry / f->src->ysize;
+
+ if (f->xoff) {
+ rx += iy * f->xoff;
+ ix = rx / f->src->xsize;
+ }
+ else if (f->yoff) {
+ ry += ix * f->yoff;
+ iy = ry / f->src->xsize;
+ }
+ rx -= ix * f->src->xsize;
+ ry -= iy * f->src->ysize;
+ i_gpixf(f->src, rx, ry, data);
+ ++data;
+ ++i;
}
- ++data;
- if ((mask >>= 1) == 0)
- mask = 128;
}
}
+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]);
+ }
+ COMBINEF(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_darken(i_color *out, i_color *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ for (ch = 0; ch < channels; ++ch) {
+ if (ch != 3 && out->channel[ch] < in->channel[ch])
+ in->channel[ch] = out->channel[ch];
+ }
+ COMBINE(*out, *in, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ for (ch = 0; ch < channels; ++ch) {
+ if (ch != 3 && out->channel[ch] < in->channel[ch])
+ in->channel[ch] = out->channel[ch];
+ }
+ COMBINEF(*out, *in, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ for (ch = 0; ch < channels; ++ch) {
+ if (ch != 3 && out->channel[ch] > in->channel[ch])
+ in->channel[ch] = out->channel[ch];
+ }
+ COMBINE(*out, *in, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ int ch;
+
+ while (count--) {
+ for (ch = 0; ch < channels; ++ch) {
+ if (ch != 3 && out->channel[ch] > in->channel[ch])
+ in->channel[ch] = out->channel[ch];
+ }
+ COMBINEF(*out, *in, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_hue(i_color *out, i_color *in, int channels, int count) {
+ while (count--) {
+ i_color c = *out;
+ i_rgb_to_hsv(&c);
+ i_rgb_to_hsv(in);
+ c.channel[0] = in->channel[0];
+ i_hsv_to_rgb(&c);
+ c.channel[3] = in->channel[3];
+ COMBINE(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ while (count--) {
+ i_fcolor c = *out;
+ i_rgb_to_hsvf(&c);
+ i_rgb_to_hsvf(in);
+ c.channel[0] = in->channel[0];
+ i_hsv_to_rgbf(&c);
+ c.channel[3] = in->channel[3];
+ COMBINEF(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_sat(i_color *out, i_color *in, int channels, int count) {
+ while (count--) {
+ i_color c = *out;
+ i_rgb_to_hsv(&c);
+ i_rgb_to_hsv(in);
+ c.channel[1] = in->channel[1];
+ i_hsv_to_rgb(&c);
+ c.channel[3] = in->channel[3];
+ COMBINE(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
+ while (count--) {
+ i_fcolor c = *out;
+ i_rgb_to_hsvf(&c);
+ i_rgb_to_hsvf(in);
+ c.channel[1] = in->channel[1];
+ i_hsv_to_rgbf(&c);
+ c.channel[3] = in->channel[3];
+ COMBINEF(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_value(i_color *out, i_color *in, int channels, int count) {
+ while (count--) {
+ i_color c = *out;
+ i_rgb_to_hsv(&c);
+ i_rgb_to_hsv(in);
+ c.channel[2] = in->channel[2];
+ i_hsv_to_rgb(&c);
+ c.channel[3] = in->channel[3];
+ COMBINE(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
+ int count) {
+ while (count--) {
+ i_fcolor c = *out;
+ i_rgb_to_hsvf(&c);
+ i_rgb_to_hsvf(in);
+ c.channel[2] = in->channel[2];
+ i_hsv_to_rgbf(&c);
+ c.channel[3] = in->channel[3];
+ COMBINEF(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_color(i_color *out, i_color *in, int channels, int count) {
+ while (count--) {
+ i_color c = *out;
+ i_rgb_to_hsv(&c);
+ i_rgb_to_hsv(in);
+ c.channel[0] = in->channel[0];
+ c.channel[1] = in->channel[1];
+ i_hsv_to_rgb(&c);
+ c.channel[3] = in->channel[3];
+ COMBINE(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
+ int count) {
+ while (count--) {
+ i_fcolor c = *out;
+ i_rgb_to_hsvf(&c);
+ i_rgb_to_hsvf(in);
+ c.channel[0] = in->channel[0];
+ c.channel[1] = in->channel[1];
+ i_hsv_to_rgbf(&c);
+ c.channel[3] = in->channel[3];
+ COMBINEF(*out, c, channels);
+ ++out;
+ ++in;
+ }
+}
+
+
/*
=back