This is primarily a feature release:
[imager.git] / fills.c
CommitLineData
92bda632
TC
1#include "imager.h"
2#include "imageri.h"
f1ac5027
TC
3
4/*
773bc121 5=head1 NAME
f1ac5027 6
773bc121 7fills.c - implements the basic general fills
f1ac5027 8
773bc121
TC
9=head1 SYNOPSIS
10
11 i_fill_t *fill;
12 i_color c1, c2;
13 i_fcolor fc1, fc2;
14 int combine;
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);
f576ce7e 19 fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
773bc121
TC
20 i_fill_destroy(fill);
21
22=head1 DESCRIPTION
23
24Implements the basic general fills, which can be used for filling some
25shapes and for flood fills.
26
27Each fill can implement up to 3 functions:
28
29=over
30
31=item fill_with_color
32
33called for fills on 8-bit images. This can be NULL in which case the
34fill_with_colorf function is called.
35
36=item fill_with_fcolor
37
38called for fills on non-8-bit images or when fill_with_color is NULL.
39
40=item destroy
41
42called by i_fill_destroy() if non-NULL, to release any extra resources
43that the fill may need.
44
45=back
46
47fill_with_color and fill_with_fcolor are basically the same function
48except that the first works with lines of i_color and the second with
49lines of i_fcolor.
50
51If the combines member if non-zero the line data is populated from the
52target image before calling fill_with_*color.
53
54fill_with_color needs to fill the I<data> parameter with the fill
55pixels. If combines is non-zero it the fill pixels should be combined
56with the existing data.
57
58The current fills are:
59
60=over
61
62=item *
63
64solid fill
65
66=item *
67
68hatched fill
69
70=item *
71
72fountain fill
73
74=back
75
76Fountain fill is implemented by L<filters.c>.
77
efdc2568
TC
78Other fills that could be implemented include:
79
80=over
81
82=item *
83
84image - an image tiled over the fill area, with an offset either
85horizontally or vertically.
86
87=item *
88
89checkerboard - combine 2 fills in a checkerboard
90
91=item *
92
93combine - combine the levels of 2 other fills based in the levels of
94an image
95
96=item *
97
98regmach - use the register machine to generate colors
99
100=back
101
773bc121
TC
102=over
103
104=cut
f1ac5027
TC
105*/
106
97ac0a96 107static i_color fcolor_to_color(const i_fcolor *c) {
f1ac5027
TC
108 int ch;
109 i_color out;
110
111 for (ch = 0; ch < MAXCHANNELS; ++ch)
112 out.channel[ch] = SampleFTo8(c->channel[ch]);
976efad5
TC
113
114 return out;
f1ac5027
TC
115}
116
97ac0a96 117static i_fcolor color_to_fcolor(const i_color *c) {
f1ac5027 118 int ch;
976efad5 119 i_fcolor out;
f1ac5027
TC
120
121 for (ch = 0; ch < MAXCHANNELS; ++ch)
122 out.channel[ch] = Sample8ToF(c->channel[ch]);
976efad5
TC
123
124 return out;
f1ac5027
TC
125}
126
efdc2568 127/* alpha combine in with out */
f1ac5027
TC
128#define COMBINE(out, in, channels) \
129 { \
130 int ch; \
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; \
134 } \
135 }
136
efdc2568
TC
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
139 for accuracy */
140#define COMBINEA(out, in, channels) \
141 { \
142 int ch; \
143 for (ch = 0; ch < (channels); ++ch) { \
144 (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
145 + (in)[ch] * (in)[3]) / 255; \
146 } \
147 }
148
f1ac5027
TC
149#define COMBINEF(out, in, channels) \
150 { \
151 int ch; \
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]; \
155 } \
156 }
157
efdc2568
TC
158typedef struct
159{
160 i_fill_t base;
161 i_color c;
162 i_fcolor fc;
163} i_fill_solid_t;
164
f1ac5027 165static void fill_solid(i_fill_t *, int x, int y, int width, int channels,
43c5dacb 166 i_color *);
f1ac5027 167static void fill_solidf(i_fill_t *, int x, int y, int width, int channels,
43c5dacb 168 i_fcolor *);
f1ac5027 169static void fill_solid_comb(i_fill_t *, int x, int y, int width, int channels,
43c5dacb 170 i_color *);
f1ac5027 171static void fill_solidf_comb(i_fill_t *, int x, int y, int width,
43c5dacb 172 int channels, i_fcolor *);
f1ac5027
TC
173
174static i_fill_solid_t base_solid_fill =
175{
176 {
177 fill_solid,
178 fill_solidf,
179 NULL,
efdc2568
TC
180 NULL,
181 NULL,
f1ac5027
TC
182 },
183};
184static i_fill_solid_t base_solid_fill_comb =
185{
186 {
187 fill_solid_comb,
188 fill_solidf_comb,
189 NULL,
efdc2568
TC
190 NULL,
191 NULL,
f1ac5027
TC
192 },
193};
194
773bc121
TC
195/*
196=item i_fill_destroy(fill)
197
92bda632
TC
198=category Fills
199
773bc121
TC
200Call to destroy any fill object.
201
202=cut
203*/
204
f1ac5027
TC
205void
206i_fill_destroy(i_fill_t *fill) {
207 if (fill->destroy)
208 (fill->destroy)(fill);
209 myfree(fill);
210}
211
773bc121
TC
212/*
213=item i_new_fill_solidf(color, combine)
214
92bda632
TC
215=category Fills
216
773bc121
TC
217Create a solid fill based on a float color.
218
219If combine is non-zero then alpha values will be combined.
220
221=cut
222*/
223
f1ac5027 224i_fill_t *
97ac0a96 225i_new_fill_solidf(const i_fcolor *c, int combine) {
f1ac5027 226 int ch;
f0960b14 227 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
f1ac5027 228
141a6114 229 if (combine) {
f1ac5027 230 *fill = base_solid_fill_comb;
efdc2568
TC
231 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
232 }
f1ac5027
TC
233 else
234 *fill = base_solid_fill;
235 fill->fc = *c;
236 for (ch = 0; ch < MAXCHANNELS; ++ch) {
237 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
238 }
239
240 return &fill->base;
241}
242
773bc121
TC
243/*
244=item i_new_fill_solid(color, combine)
245
92bda632
TC
246=category Fills
247
248Create a solid fill based on an 8-bit color.
773bc121
TC
249
250If combine is non-zero then alpha values will be combined.
251
252=cut
253*/
254
f1ac5027 255i_fill_t *
97ac0a96 256i_new_fill_solid(const i_color *c, int combine) {
f1ac5027 257 int ch;
f0960b14 258 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
f1ac5027 259
141a6114 260 if (combine) {
f1ac5027 261 *fill = base_solid_fill_comb;
efdc2568
TC
262 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
263 }
f1ac5027
TC
264 else
265 *fill = base_solid_fill;
266 fill->c = *c;
267 for (ch = 0; ch < MAXCHANNELS; ++ch) {
268 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
269 }
270
271 return &fill->base;
272}
273
f1ac5027
TC
274static unsigned char
275builtin_hatches[][8] =
276{
277 {
278 /* 1x1 checkerboard */
279 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
280 },
281 {
282 /* 2x2 checkerboard */
283 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
284 },
285 {
286 /* 4 x 4 checkerboard */
287 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
288 },
289 {
290 /* single vertical lines */
291 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
292 },
293 {
294 /* double vertical lines */
295 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
296 },
297 {
298 /* quad vertical lines */
299 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
300 },
301 {
302 /* single hlines */
303 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 },
305 {
306 /* double hlines */
307 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
308 },
309 {
310 /* quad hlines */
311 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
312 },
313 {
314 /* single / */
315 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
316 },
317 {
318 /* single \ */
319 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
320 },
321 {
322 /* double / */
323 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
324 },
325 {
326 /* double \ */
327 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
328 },
329 {
330 /* single grid */
331 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
332 },
333 {
334 /* double grid */
335 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
336 },
337 {
338 /* quad grid */
339 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
340 },
341 {
342 /* single dots */
343 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 },
345 {
346 /* 4 dots */
347 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
348 },
349 {
350 /* 16 dots */
351 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
352 },
353 {
354 /* simple stipple */
355 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
356 },
357 {
358 /* weave */
359 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
360 },
361 {
362 /* single cross hatch */
363 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
364 },
365 {
366 /* double cross hatch */
367 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
368 },
369 {
370 /* vertical lozenge */
371 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
372 },
373 {
374 /* horizontal lozenge */
375 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
376 },
377 {
378 /* scales overlapping downwards */
7a606d29 379 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
f1ac5027
TC
380 },
381 {
382 /* scales overlapping upwards */
7a606d29 383 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
f1ac5027
TC
384 },
385 {
386 /* scales overlapping leftwards */
7a606d29 387 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
f1ac5027
TC
388 },
389 {
390 /* scales overlapping rightwards */
7a606d29 391 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
f1ac5027
TC
392 },
393 {
394 /* denser stipple */
395 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
396 },
397 {
398 /* L-shaped tiles */
399 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
400 },
cc6483e0
TC
401 {
402 /* wider stipple */
403 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
404 },
f1ac5027
TC
405};
406
407typedef struct
408{
409 i_fill_t base;
410 i_color fg, bg;
411 i_fcolor ffg, fbg;
412 unsigned char hatch[8];
413 int dx, dy;
414} i_fill_hatch_t;
415
416static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 417 i_color *data);
f1ac5027 418static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 419 i_fcolor *data);
773bc121
TC
420static
421i_fill_t *
97ac0a96
TC
422i_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,
773bc121
TC
424 int dx, int dy);
425
426/*
427=item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
428
92bda632
TC
429=category Fills
430
773bc121
TC
431Creates a new hatched fill with the fg color used for the 1 bits in
432the hatch and bg for the 0 bits. If combine is non-zero alpha values
433will be combined.
f1ac5027 434
773bc121
TC
435If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
436hash definition, with the high-bits to the left.
437
438If cust_hatch is NULL then one of the standard hatches is used.
439
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.
441
442=cut
443*/
444i_fill_t *
97ac0a96
TC
445i_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) {
773bc121
TC
447 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
448 dx, dy);
449}
450
451/*
452=item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
453
92bda632
TC
454=category Fills
455
773bc121
TC
456Creates a new hatched fill with the fg color used for the 1 bits in
457the hatch and bg for the 0 bits. If combine is non-zero alpha values
458will be combined.
459
460If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
461hash definition, with the high-bits to the left.
462
463If cust_hatch is NULL then one of the standard hatches is used.
464
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.
466
467=cut
468*/
469i_fill_t *
97ac0a96
TC
470i_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) {
773bc121
TC
472 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
473 dx, dy);
474}
475
f576ce7e 476static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 477 i_color *data);
f576ce7e 478static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 479 i_fcolor *data);
f576ce7e
TC
480struct i_fill_image_t {
481 i_fill_t base;
482 i_img *src;
483 int xoff, yoff;
484 int has_matrix;
485 double matrix[9];
486};
487
488/*
489=item i_new_fill_image(im, matrix, xoff, yoff, combine)
490
92bda632
TC
491=category Fills
492
f576ce7e
TC
493Create an image based fill.
494
92bda632
TC
495matrix is an array of 9 doubles representing a transformation matrix.
496
497xoff and yoff are the offset into the image to start filling from.
498
f576ce7e
TC
499=cut
500*/
501i_fill_t *
97ac0a96 502i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) {
f0960b14 503 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
f576ce7e
TC
504
505 fill->base.fill_with_color = fill_image;
506 fill->base.fill_with_fcolor = fill_imagef;
507 fill->base.destroy = NULL;
508
509 if (combine) {
510 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
511 }
512 else {
513 fill->base.combine = NULL;
514 fill->base.combinef = NULL;
515 }
516 fill->src = im;
517 if (xoff < 0)
518 xoff += im->xsize;
519 fill->xoff = xoff;
520 if (yoff < 0)
521 yoff += im->ysize;
522 fill->yoff = yoff;
523 if (matrix) {
524 fill->has_matrix = 1;
525 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
526 }
527 else
528 fill->has_matrix = 0;
529
530 return &fill->base;
531}
532
533
773bc121
TC
534#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
535
536/*
537=back
538
539=head1 INTERNAL FUNCTIONS
540
541=over
542
543=item fill_solid(fill, x, y, width, channels, data)
544
545The 8-bit sample fill function for non-combining solid fills.
546
547=cut
548*/
549static void
550fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 551 i_color *data) {
773bc121
TC
552 while (width-- > 0) {
553 *data++ = T_SOLID_FILL(fill)->c;
554 }
555}
556
557/*
558=item fill_solid(fill, x, y, width, channels, data)
559
560The floating sample fill function for non-combining solid fills.
561
562=cut
563*/
564static void
565fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 566 i_fcolor *data) {
773bc121
TC
567 while (width-- > 0) {
568 *data++ = T_SOLID_FILL(fill)->fc;
569 }
570}
571
572/*
573=item fill_solid_comb(fill, x, y, width, channels, data)
574
575The 8-bit sample fill function for combining solid fills.
576
577=cut
578*/
579static void
580fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 581 i_color *data) {
773bc121
TC
582 i_color c = T_SOLID_FILL(fill)->c;
583
584 while (width-- > 0) {
43c5dacb 585 *data++ = c;
773bc121
TC
586 }
587}
588
589/*
590=item fill_solidf_comb(fill, x, y, width, channels, data)
591
592The floating sample fill function for combining solid fills.
593
594=cut
595*/
596static void
597fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 598 i_fcolor *data) {
773bc121
TC
599 i_fcolor c = T_SOLID_FILL(fill)->fc;
600
601 while (width-- > 0) {
43c5dacb 602 *data++ = c;
773bc121
TC
603 }
604}
605
606/*
607=item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
608
609Implements creation of hatch fill objects.
610
611=cut
612*/
f1ac5027
TC
613static
614i_fill_t *
97ac0a96
TC
615i_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,
f1ac5027 618 int dx, int dy) {
f0960b14 619 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
f1ac5027
TC
620
621 fill->base.fill_with_color = fill_hatch;
622 fill->base.fill_with_fcolor = fill_hatchf;
623 fill->base.destroy = NULL;
624 fill->fg = fg ? *fg : fcolor_to_color(ffg);
625 fill->bg = bg ? *bg : fcolor_to_color(fbg);
626 fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
627 fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
141a6114 628 if (combine) {
efdc2568
TC
629 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
630 }
631 else {
632 fill->base.combine = NULL;
633 fill->base.combinef = NULL;
634 }
f1ac5027
TC
635 if (cust_hatch) {
636 memcpy(fill->hatch, cust_hatch, 8);
637 }
638 else {
639 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
640 hatch = 0;
641 memcpy(fill->hatch, builtin_hatches[hatch], 8);
642 }
643 fill->dx = dx & 7;
644 fill->dy = dy & 7;
645
646 return &fill->base;
647}
648
773bc121
TC
649/*
650=item fill_hatch(fill, x, y, width, channels, data)
f1ac5027 651
773bc121 652The 8-bit sample fill function for hatched fills.
f1ac5027 653
b8c2033e 654=cut
773bc121 655*/
f1ac5027 656static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 657 i_color *data) {
f1ac5027
TC
658 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
659 int byte = f->hatch[(y + f->dy) & 7];
660 int xpos = (x + f->dx) & 7;
661 int mask = 128 >> xpos;
662
43c5dacb
TC
663 while (width-- > 0) {
664 *data++ = (byte & mask) ? f->fg : f->bg;
665
666 if ((mask >>= 1) == 0)
667 mask = 128;
f1ac5027
TC
668 }
669}
670
773bc121
TC
671/*
672=item fill_hatchf(fill, x, y, width, channels, data)
673
674The floating sample fill function for hatched fills.
675
676=back
677*/
f1ac5027 678static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 679 i_fcolor *data) {
f1ac5027
TC
680 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
681 int byte = f->hatch[(y + f->dy) & 7];
682 int xpos = (x + f->dx) & 7;
683 int mask = 128 >> xpos;
684
43c5dacb
TC
685 while (width-- > 0) {
686 *data++ = (byte & mask) ? f->ffg : f->fbg;
687
688 if ((mask >>= 1) == 0)
689 mask = 128;
efdc2568
TC
690 }
691}
692
f576ce7e
TC
693/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
694/* linear interpolation */
695static i_color interp_i_color(i_color before, i_color after, double pos,
696 int channels) {
697 i_color out;
698 int ch;
699
700 pos -= floor(pos);
701 for (ch = 0; ch < channels; ++ch)
702 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
3efb0915 703 if (channels > 3 && out.channel[3])
f576ce7e
TC
704 for (ch = 0; ch < channels; ++ch)
705 if (ch != 3) {
706 int temp = out.channel[ch] * 255 / out.channel[3];
707 if (temp > 255)
708 temp = 255;
709 out.channel[ch] = temp;
710 }
711
712 return out;
713}
714
715/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
716/* linear interpolation */
717static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
718 int channels) {
719 i_fcolor out;
720 int ch;
721
722 pos -= floor(pos);
723 for (ch = 0; ch < channels; ++ch)
724 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
725 if (out.channel[3])
726 for (ch = 0; ch < channels; ++ch)
727 if (ch != 3) {
728 int temp = out.channel[ch] / out.channel[3];
729 if (temp > 1.0)
730 temp = 1.0;
731 out.channel[ch] = temp;
732 }
733
734 return out;
735}
736
737/*
738=item fill_image(fill, x, y, width, channels, data, work)
739
740=cut
741*/
742static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 743 i_color *data) {
f576ce7e 744 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e 745 int i = 0;
cde2dbc7 746 i_color *out = data;
f576ce7e
TC
747
748 if (f->has_matrix) {
749 /* the hard way */
750 while (i < width) {
751 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
752 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
753 double ix = floor(rx / f->src->xsize);
754 double iy = floor(ry / f->src->ysize);
755 i_color c[2][2];
756 i_color c2[2];
757 int dy;
758
759 if (f->xoff) {
760 rx += iy * f->xoff;
761 ix = floor(rx / f->src->xsize);
762 }
763 else if (f->yoff) {
764 ry += ix * f->yoff;
765 iy = floor(ry / f->src->ysize);
766 }
767 rx -= ix * f->src->xsize;
768 ry -= iy * f->src->ysize;
769
770 for (dy = 0; dy < 2; ++dy) {
771 if ((int)rx == f->src->xsize-1) {
772 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
773 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
774 }
775 else {
776 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
777 c[dy]);
778 }
779 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
780 }
cde2dbc7 781 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
782 ++i;
783 }
784 }
785 else {
786 /* the easy way */
787 /* this should be possible to optimize to use i_glin() */
788 while (i < width) {
789 int rx = x+i;
790 int ry = y;
791 int ix = rx / f->src->xsize;
792 int iy = ry / f->src->ysize;
793
794 if (f->xoff) {
795 rx += iy * f->xoff;
796 ix = rx / f->src->xsize;
797 }
798 else if (f->yoff) {
799 ry += ix * f->yoff;
800 iy = ry / f->src->xsize;
801 }
802 rx -= ix * f->src->xsize;
803 ry -= iy * f->src->ysize;
cde2dbc7
TC
804 i_gpix(f->src, rx, ry, out);
805 ++out;
f576ce7e
TC
806 ++i;
807 }
808 }
cde2dbc7
TC
809 if (f->src->channels == 3) {
810 /* just set the alpha */
811 for (i = 0; i < width; ++i) {
812 data->channel[3] = 255;
813 data++;
814 }
815 }
816 else if (f->src->channels == 2) {
817 /* copy the alpha to channel 3, duplicate the grey value */
818 for (i = 0; i < width; ++i) {
819 data->channel[3] = data->channel[1];
820 data->channel[1] = data->channel[2] = data->channel[0];
821 data++;
822 }
823 }
824 else if (f->src->channels == 1) {
825 /* set the alpha, duplicate grey */
826 for (i = 0; i < width; ++i) {
827 data->channel[3] = 255;
828 data->channel[1] = data->channel[2] = data->channel[0];
829 data++;
830 }
831 }
f576ce7e
TC
832}
833
834/*
835=item fill_image(fill, x, y, width, channels, data, work)
836
837=cut
838*/
839static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 840 i_fcolor *data) {
f576ce7e 841 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e 842 int i = 0;
f576ce7e
TC
843
844 if (f->has_matrix) {
845 /* the hard way */
846 while (i < width) {
847 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
848 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
849 double ix = floor(rx / f->src->xsize);
850 double iy = floor(ry / f->src->ysize);
851 i_fcolor c[2][2];
852 i_fcolor c2[2];
853 int dy;
854
855 if (f->xoff) {
856 rx += iy * f->xoff;
857 ix = floor(rx / f->src->xsize);
858 }
859 else if (f->yoff) {
860 ry += ix * f->yoff;
861 iy = floor(ry / f->src->ysize);
862 }
863 rx -= ix * f->src->xsize;
864 ry -= iy * f->src->ysize;
865
866 for (dy = 0; dy < 2; ++dy) {
867 if ((int)rx == f->src->xsize-1) {
868 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
869 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
870 }
871 else {
872 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
873 c[dy]);
874 }
875 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
876 }
43c5dacb 877 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
878 ++i;
879 }
880 }
881 else {
882 /* the easy way */
883 /* this should be possible to optimize to use i_glin() */
884 while (i < width) {
885 int rx = x+i;
886 int ry = y;
887 int ix = rx / f->src->xsize;
888 int iy = ry / f->src->ysize;
889
890 if (f->xoff) {
891 rx += iy * f->xoff;
892 ix = rx / f->src->xsize;
893 }
894 else if (f->yoff) {
895 ry += ix * f->yoff;
896 iy = ry / f->src->xsize;
897 }
898 rx -= ix * f->src->xsize;
899 ry -= iy * f->src->ysize;
43c5dacb
TC
900 i_gpixf(f->src, rx, ry, data);
901 ++data;
f576ce7e
TC
902 ++i;
903 }
904 }
cde2dbc7
TC
905 if (f->src->channels == 3) {
906 /* just set the alpha */
907 for (i = 0; i < width; ++i) {
908 data->channel[3] = 1.0;
909 data++;
910 }
911 }
912 else if (f->src->channels == 2) {
913 /* copy the alpha to channel 3, duplicate the grey value */
914 for (i = 0; i < width; ++i) {
915 data->channel[3] = data->channel[1];
916 data->channel[1] = data->channel[2] = data->channel[0];
917 data++;
918 }
919 }
920 else if (f->src->channels == 1) {
921 /* set the alpha, duplicate grey */
922 for (i = 0; i < width; ++i) {
923 data->channel[3] = 1.0;
924 data->channel[1] = data->channel[2] = data->channel[0];
925 data++;
926 }
927 }
f576ce7e
TC
928}
929
efdc2568
TC
930static void combine_replace(i_color *, i_color *, int, int);
931static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
932static void combine_alphablend(i_color *, i_color *, int, int);
933static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
934static void combine_mult(i_color *, i_color *, int, int);
935static void combine_multf(i_fcolor *, i_fcolor *, int, int);
936static void combine_dissolve(i_color *, i_color *, int, int);
937static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
938static void combine_add(i_color *, i_color *, int, int);
939static void combine_addf(i_fcolor *, i_fcolor *, int, int);
940static void combine_subtract(i_color *, i_color *, int, int);
941static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
942static void combine_diff(i_color *, i_color *, int, int);
943static void combine_difff(i_fcolor *, i_fcolor *, int, int);
944static void combine_darken(i_color *, i_color *, int, int);
945static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
946static void combine_lighten(i_color *, i_color *, int, int);
947static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
948static void combine_hue(i_color *, i_color *, int, int);
949static void combine_huef(i_fcolor *, i_fcolor *, int, int);
950static void combine_sat(i_color *, i_color *, int, int);
951static void combine_satf(i_fcolor *, i_fcolor *, int, int);
952static void combine_value(i_color *, i_color *, int, int);
953static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
954static void combine_color(i_color *, i_color *, int, int);
955static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
956
b33c08f8 957static struct i_combines {
efdc2568
TC
958 i_fill_combine_f combine;
959 i_fill_combinef_f combinef;
960} combines[] =
961{
962 { /* replace */
963 combine_replace,
964 combine_replacef,
965 },
966 { /* alpha blend */
967 combine_alphablend,
968 combine_alphablendf,
969 },
970 {
971 /* multiply */
972 combine_mult,
973 combine_multf,
974 },
975 {
976 /* dissolve */
977 combine_dissolve,
978 combine_dissolvef,
979 },
980 {
981 /* add */
982 combine_add,
983 combine_addf,
984 },
985 {
986 /* subtract */
987 combine_subtract,
988 combine_subtractf,
989 },
990 {
991 /* diff */
992 combine_diff,
993 combine_difff,
994 },
995 {
996 combine_lighten,
997 combine_lightenf,
998 },
999 {
1000 combine_darken,
1001 combine_darkenf,
1002 },
1003 {
1004 combine_hue,
1005 combine_huef,
1006 },
1007 {
1008 combine_sat,
1009 combine_satf,
1010 },
1011 {
1012 combine_value,
1013 combine_valuef,
1014 },
1015 {
1016 combine_color,
1017 combine_colorf,
1018 },
1019};
1020
1021/*
1022=item i_get_combine(combine, color_func, fcolor_func)
1023
1024=cut
1025*/
1026
1027void i_get_combine(int combine, i_fill_combine_f *color_func,
1028 i_fill_combinef_f *fcolor_func) {
1029 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
1030 combine = 0;
1031
1032 *color_func = combines[combine].combine;
1033 *fcolor_func = combines[combine].combinef;
1034}
1035
1036static void combine_replace(i_color *out, i_color *in, int channels, int count) {
1037 while (count--) {
1038 *out++ = *in++;
1039 }
1040}
1041
1042static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1043 while (count--) {
1044 *out++ = *in++;
1045 }
1046}
1047
1048static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
1049 while (count--) {
1050 COMBINE(*out, *in, channels);
1051 ++out;
1052 ++in;
1053 }
1054}
1055
1056static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1057 while (count--) {
1058 COMBINEF(*out, *in, channels);
1059 ++out;
1060 ++in;
1061 }
1062}
1063
1064static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1065 int ch;
1066
1067 while (count--) {
efdc2568
TC
1068 double mult[MAXCHANNELS];
1069 mult[3] = in->channel[3];
1070 for (ch = 0; ch < (channels); ++ch) {
1071 if (ch != 3)
1072 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1073 }
1074 COMBINEA(*out, mult, channels);
1075 ++out;
1076 ++in;
1077 }
1078}
1079
1080static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1081 int ch;
1082
1083 while (count--) {
1084 i_fcolor c = *in;
1085 for (ch = 0; ch < channels; ++ch) {
1086 if (ch != 3)
1087 c.channel[ch] = out->channel[ch] * in->channel[ch];
1088 }
1089 COMBINEF(*out, c, channels);
1090 ++out;
1091 ++in;
1092 }
1093}
1094
1095static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
efdc2568
TC
1096 while (count--) {
1097 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1098 COMBINE(*out, *in, channels);
1099 ++out;
1100 ++in;
1101 }
1102}
1103
1104static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
efdc2568
TC
1105 while (count--) {
1106 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1107 COMBINEF(*out, *in, channels);
1108 ++out;
1109 ++in;
1110 }
1111}
1112
1113static void combine_add(i_color *out, i_color *in, int channels, int count) {
1114 int ch;
1115
1116 while (count--) {
1117 i_color c = *in;
1118 for (ch = 0; ch < (channels); ++ch) {
1119 if (ch != 3) {
1120 int total = out->channel[ch] + in->channel[ch];
1121 if (total > 255)
1122 total = 255;
1123 c.channel[ch] = total;
1124 }
1125 }
1126 COMBINE(*out, c, channels);
1127 ++out;
1128 ++in;
1129 }
1130}
1131
1132static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1133 int ch;
1134
1135 while (count--) {
1136 i_fcolor c = *in;
1137 for (ch = 0; ch < (channels); ++ch) {
1138 if (ch != 3) {
1139 double total = out->channel[ch] + in->channel[ch];
1140 if (total > 1.0)
1141 total = 1.0;
1142 out->channel[ch] = total;
1143 }
1144 }
1145 COMBINEF(*out, c, channels);
1146 ++out;
1147 ++in;
1148 }
1149}
1150
1151static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1152 int ch;
1153
1154 while (count--) {
1155 i_color c = *in;
1156 for (ch = 0; ch < (channels); ++ch) {
1157 if (ch != 3) {
1158 int total = out->channel[ch] - in->channel[ch];
1159 if (total < 0)
1160 total = 0;
1161 c.channel[ch] = total;
1162 }
1163 }
1164 COMBINE(*out, c, channels);
1165 ++out;
1166 ++in;
1167 }
1168}
1169
1170static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1171 int ch;
1172
1173 while (count--) {
1174 i_fcolor c = *in;
1175 for (ch = 0; ch < channels; ++ch) {
1176 if (ch != 3) {
1177 double total = out->channel[ch] - in->channel[ch];
1178 if (total < 0)
1179 total = 0;
1180 c.channel[ch] = total;
1181 }
1182 }
1183 COMBINEF(*out, c, channels);
1184 ++out;
1185 ++in;
1186 }
1187}
1188
1189static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1190 int ch;
1191
1192 while (count--) {
1193 i_color c = *in;
1194 for (ch = 0; ch < (channels); ++ch) {
1195 if (ch != 3)
1196 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1197 }
1198 COMBINE(*out, c, channels)
1199 ++out;
1200 ++in;
1201 }
1202}
1203
1204static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1205 int ch;
1206
1207 while (count--) {
1208 i_fcolor c = *in;
1209 for (ch = 0; ch < (channels); ++ch) {
1210 if (ch != 3)
1211 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
f1ac5027 1212 }
efdc2568
TC
1213 COMBINEF(*out, c, channels);
1214 ++out;
1215 ++in;
f1ac5027
TC
1216 }
1217}
773bc121 1218
efdc2568
TC
1219static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1220 int ch;
1221
1222 while (count--) {
1223 for (ch = 0; ch < channels; ++ch) {
1224 if (ch != 3 && out->channel[ch] < in->channel[ch])
1225 in->channel[ch] = out->channel[ch];
1226 }
1227 COMBINE(*out, *in, channels);
1228 ++out;
1229 ++in;
1230 }
1231}
1232
1233static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1234 int ch;
1235
1236 while (count--) {
1237 for (ch = 0; ch < channels; ++ch) {
1238 if (ch != 3 && out->channel[ch] < in->channel[ch])
1239 in->channel[ch] = out->channel[ch];
1240 }
1241 COMBINEF(*out, *in, channels);
1242 ++out;
1243 ++in;
1244 }
1245}
1246
1247static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1248 int ch;
1249
1250 while (count--) {
1251 for (ch = 0; ch < channels; ++ch) {
1252 if (ch != 3 && out->channel[ch] > in->channel[ch])
1253 in->channel[ch] = out->channel[ch];
1254 }
1255 COMBINE(*out, *in, channels);
1256 ++out;
1257 ++in;
1258 }
1259}
1260
1261static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1262 int ch;
1263
1264 while (count--) {
1265 for (ch = 0; ch < channels; ++ch) {
1266 if (ch != 3 && out->channel[ch] > in->channel[ch])
1267 in->channel[ch] = out->channel[ch];
1268 }
1269 COMBINEF(*out, *in, channels);
1270 ++out;
1271 ++in;
1272 }
1273}
1274
1275static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1276 while (count--) {
1277 i_color c = *out;
1278 i_rgb_to_hsv(&c);
1279 i_rgb_to_hsv(in);
1280 c.channel[0] = in->channel[0];
1281 i_hsv_to_rgb(&c);
976efad5 1282 c.channel[3] = in->channel[3];
efdc2568
TC
1283 COMBINE(*out, c, channels);
1284 ++out;
1285 ++in;
1286 }
1287}
1288
1289static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1290 while (count--) {
1291 i_fcolor c = *out;
1292 i_rgb_to_hsvf(&c);
1293 i_rgb_to_hsvf(in);
1294 c.channel[0] = in->channel[0];
1295 i_hsv_to_rgbf(&c);
1296 c.channel[3] = in->channel[3];
1297 COMBINEF(*out, c, channels);
1298 ++out;
1299 ++in;
1300 }
1301}
1302
1303static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1304 while (count--) {
1305 i_color c = *out;
1306 i_rgb_to_hsv(&c);
1307 i_rgb_to_hsv(in);
1308 c.channel[1] = in->channel[1];
1309 i_hsv_to_rgb(&c);
1310 c.channel[3] = in->channel[3];
1311 COMBINE(*out, c, channels);
1312 ++out;
1313 ++in;
1314 }
1315}
1316
1317static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1318 while (count--) {
1319 i_fcolor c = *out;
1320 i_rgb_to_hsvf(&c);
1321 i_rgb_to_hsvf(in);
1322 c.channel[1] = in->channel[1];
1323 i_hsv_to_rgbf(&c);
1324 c.channel[3] = in->channel[3];
1325 COMBINEF(*out, c, channels);
1326 ++out;
1327 ++in;
1328 }
1329}
1330
1331static void combine_value(i_color *out, i_color *in, int channels, int count) {
1332 while (count--) {
1333 i_color c = *out;
1334 i_rgb_to_hsv(&c);
1335 i_rgb_to_hsv(in);
1336 c.channel[2] = in->channel[2];
1337 i_hsv_to_rgb(&c);
1338 c.channel[3] = in->channel[3];
1339 COMBINE(*out, c, channels);
1340 ++out;
1341 ++in;
1342 }
1343}
1344
1345static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1346 int count) {
1347 while (count--) {
1348 i_fcolor c = *out;
1349 i_rgb_to_hsvf(&c);
1350 i_rgb_to_hsvf(in);
1351 c.channel[2] = in->channel[2];
1352 i_hsv_to_rgbf(&c);
1353 c.channel[3] = in->channel[3];
1354 COMBINEF(*out, c, channels);
1355 ++out;
1356 ++in;
1357 }
1358}
1359
1360static void combine_color(i_color *out, i_color *in, int channels, int count) {
1361 while (count--) {
1362 i_color c = *out;
1363 i_rgb_to_hsv(&c);
1364 i_rgb_to_hsv(in);
1365 c.channel[0] = in->channel[0];
1366 c.channel[1] = in->channel[1];
1367 i_hsv_to_rgb(&c);
1368 c.channel[3] = in->channel[3];
1369 COMBINE(*out, c, channels);
1370 ++out;
1371 ++in;
1372 }
1373}
1374
1375static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1376 int count) {
1377 while (count--) {
1378 i_fcolor c = *out;
1379 i_rgb_to_hsvf(&c);
1380 i_rgb_to_hsvf(in);
1381 c.channel[0] = in->channel[0];
1382 c.channel[1] = in->channel[1];
1383 i_hsv_to_rgbf(&c);
1384 c.channel[3] = in->channel[3];
1385 COMBINEF(*out, c, channels);
1386 ++out;
1387 ++in;
1388 }
1389}
1390
1391
773bc121
TC
1392/*
1393=back
1394
1395=head1 AUTHOR
1396
1397Tony Cook <tony@develop-help.com>
1398
1399=head1 SEE ALSO
1400
1401Imager(3)
1402
1403=cut
1404*/