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