various
[imager.git] / filters.c
CommitLineData
02d1d628
AMH
1#include "image.h"
2#include <stdlib.h>
3#include <math.h>
4
5
6/*
7=head1 NAME
8
9filters.c - implements filters that operate on images
10
11=head1 SYNOPSIS
12
13
14 i_contrast(im, 0.8);
15 i_hardinvert(im);
16 // and more
17
18=head1 DESCRIPTION
19
20filters.c implements basic filters for Imager. These filters
21should be accessible from the filter interface as defined in
22the pod for Imager.
23
24=head1 FUNCTION REFERENCE
25
26Some of these functions are internal.
27
28=over 4
29
30=cut
31*/
32
33
34
35
36
37
38
39/*
40=item i_contrast(im, intensity)
41
42Scales the pixel values by the amount specified.
43
44 im - image object
45 intensity - scalefactor
46
47=cut
48*/
49
50void
51i_contrast(i_img *im, float intensity) {
52 int x, y;
53 unsigned char ch;
54 unsigned int new_color;
55 i_color rcolor;
56
57 mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
58
59 if(intensity < 0) return;
60
61 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
62 i_gpix(im, x, y, &rcolor);
63
64 for(ch = 0; ch < im->channels; ch++) {
65 new_color = (unsigned int) rcolor.channel[ch];
66 new_color *= intensity;
67
68 if(new_color > 255) {
69 new_color = 255;
70 }
71 rcolor.channel[ch] = (unsigned char) new_color;
72 }
73 i_ppix(im, x, y, &rcolor);
74 }
75}
76
77
78/*
79=item i_hardinvert(im)
80
81Inverts the pixel values of the input image.
82
83 im - image object
84
85=cut
86*/
87
88void
89i_hardinvert(i_img *im) {
90 int x, y;
91 unsigned char ch;
92
93 i_color rcolor;
94
95 mm_log((1,"i_hardinvert(im %p)\n", im));
96
97 for(y = 0; y < im->ysize; y++) {
98 for(x = 0; x < im->xsize; x++) {
99 i_gpix(im, x, y, &rcolor);
100
101 for(ch = 0; ch < im->channels; ch++) {
102 rcolor.channel[ch] = 255 - rcolor.channel[ch];
103 }
104
105 i_ppix(im, x, y, &rcolor);
106 }
107 }
108}
109
110
111
112/*
113=item i_noise(im, amount, type)
114
115Inverts the pixel values by the amount specified.
116
117 im - image object
118 amount - deviation in pixel values
119 type - noise individual for each channel if true
120
121=cut
122*/
123
124#ifdef _MSC_VER
125/* random() is non-ASCII, even if it is better than rand() */
126#define random() rand()
127#endif
128
129void
130i_noise(i_img *im, float amount, unsigned char type) {
131 int x, y;
132 unsigned char ch;
133 int new_color;
134 float damount = amount * 2;
135 i_color rcolor;
136 int color_inc = 0;
137
138 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
139
140 if(amount < 0) return;
141
142 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
143 i_gpix(im, x, y, &rcolor);
144
145 if(type == 0) {
146 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
147 }
148
149 for(ch = 0; ch < im->channels; ch++) {
150 new_color = (int) rcolor.channel[ch];
151
152 if(type != 0) {
153 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
154 } else {
155 new_color += color_inc;
156 }
157
158 if(new_color < 0) {
159 new_color = 0;
160 }
161 if(new_color > 255) {
162 new_color = 255;
163 }
164
165 rcolor.channel[ch] = (unsigned char) new_color;
166 }
167
168 i_ppix(im, x, y, &rcolor);
169 }
170}
171
172
173/*
174=item i_noise(im, amount, type)
175
176Inverts the pixel values by the amount specified.
177
178 im - image object
179 amount - deviation in pixel values
180 type - noise individual for each channel if true
181
182=cut
183*/
184
185
186/*
187=item i_applyimage(im, add_im, mode)
188
189Apply's an image to another image
190
191 im - target image
192 add_im - image that is applied to target
193 mode - what method is used in applying:
194
195 0 Normal
196 1 Multiply
197 2 Screen
198 3 Overlay
199 4 Soft Light
200 5 Hard Light
201 6 Color dodge
202 7 Color Burn
203 8 Darker
204 9 Lighter
205 10 Add
206 11 Subtract
207 12 Difference
208 13 Exclusion
209
210=cut
211*/
212
213void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
214 int x, y;
215 int mx, my;
216
217 mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
218
219 mx = (add_im->xsize <= im->xsize) ? add_im->xsize : add_im->xsize;
220 my = (add_im->ysize <= im->ysize) ? add_im->ysize : add_im->ysize;
221
222 for(x = 0; x < mx; x++) {
223 for(y = 0; y < my; y++) {
224 }
225 }
226}
227
228
229/*
230=item i_bumpmap(im, bump, channel, light_x, light_y, st)
231
232Makes a bumpmap on image im using the bump image as the elevation map.
233
234 im - target image
235 bump - image that contains the elevation info
236 channel - to take the elevation information from
237 light_x - x coordinate of light source
238 light_y - y coordinate of light source
239 st - length of shadow
240
241=cut
242*/
243
244void
245i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
246 int x, y, ch;
247 int mx, my;
248 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
249 double nX, nY;
250 double tX, tY, tZ;
251 double aX, aY, aL;
252 double fZ;
253 unsigned char px1, px2, py1, py2;
254
255 i_img new_im;
256
257 mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light_x %d, light_y %d, st %d)\n",
258 im, bump, channel, light_x, light_y, st));
259
260
261 if(channel >= bump->channels) {
262 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
263 return;
264 }
265
266 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
267 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
268
269 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
270
271 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
272 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
273
274 aL = sqrt((aX * aX) + (aY * aY));
275
276 for(y = 1; y < my - 1; y++) {
277 for(x = 1; x < mx - 1; x++) {
278 i_gpix(bump, x + st, y, &x1_color);
279 i_gpix(bump, x, y + st, &y1_color);
280 i_gpix(bump, x - st, y, &x2_color);
281 i_gpix(bump, x, y - st, &y2_color);
282
283 i_gpix(im, x, y, &dst_color);
284
285 px1 = x1_color.channel[channel];
286 py1 = y1_color.channel[channel];
287 px2 = x2_color.channel[channel];
288 py2 = y2_color.channel[channel];
289
290 nX = px1 - px2;
291 nY = py1 - py2;
292
293 nX += 128;
294 nY += 128;
295
296 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
297
298 tX = abs(x - light_x) / aL;
299 tY = abs(y - light_y) / aL;
300
301 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
302
303 if(tZ < 0) tZ = 0;
304 if(tZ > 2) tZ = 2;
305
306 for(ch = 0; ch < im->channels; ch++)
307 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
308
309 i_ppix(&new_im, x, y, &dst_color);
310 }
311 }
312
313 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
314
315 i_img_exorcise(&new_im);
316}
317
318
319
320/*
321=item i_postlevels(im, levels)
322
323Quantizes Images to fewer levels.
324
325 im - target image
326 levels - number of levels
327
328=cut
329*/
330
331void
332i_postlevels(i_img *im, int levels) {
333 int x, y, ch;
334 float pv;
335 int rv;
336 float av;
337
338 i_color rcolor;
339
340 rv = (int) ((float)(256 / levels));
341 av = (float)levels;
342
343 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
344 i_gpix(im, x, y, &rcolor);
345
346 for(ch = 0; ch < im->channels; ch++) {
347 pv = (((float)rcolor.channel[ch] / 255)) * av;
348 pv = (int) ((int)pv * rv);
349
350 if(pv < 0) pv = 0;
351 else if(pv > 255) pv = 255;
352
353 rcolor.channel[ch] = (unsigned char) pv;
354 }
355 i_ppix(im, x, y, &rcolor);
356 }
357}
358
359
360/*
361=item i_mosaic(im, size)
362
363Makes an image looks like a mosaic with tilesize of size
364
365 im - target image
366 size - size of tiles
367
368=cut
369*/
370
371void
372i_mosaic(i_img *im, int size) {
373 int x, y, ch;
374 int lx, ly, z;
375 long sqrsize;
376
377 i_color rcolor;
378 long col[256];
379
380 sqrsize = size * size;
381
382 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
383 for(z = 0; z < 256; z++) col[z] = 0;
384
385 for(lx = 0; lx < size; lx++) {
386 for(ly = 0; ly < size; ly++) {
387 i_gpix(im, (x + lx), (y + ly), &rcolor);
388
389 for(ch = 0; ch < im->channels; ch++) {
390 col[ch] += rcolor.channel[ch];
391 }
392 }
393 }
394
395 for(ch = 0; ch < im->channels; ch++)
396 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
397
398
399 for(lx = 0; lx < size; lx++)
400 for(ly = 0; ly < size; ly++)
401 i_ppix(im, (x + lx), (y + ly), &rcolor);
402
403 }
404}
405
406/*
407=item saturate(in)
408
409Clamps the input value between 0 and 255. (internal)
410
411 in - input integer
412
413=cut
414*/
415
416static
417unsigned char
418saturate(int in) {
419 if (in>255) { return 255; }
420 else if (in>0) return in;
421 return 0;
422}
423
424
425/*
426=item i_watermark(im, wmark, tx, ty, pixdiff)
427
428Applies a watermark to the target image
429
430 im - target image
431 wmark - watermark image
432 tx - x coordinate of where watermark should be applied
433 ty - y coordinate of where watermark should be applied
434 pixdiff - the magnitude of the watermark, controls how visible it is
435
436=cut
437*/
438
439void
440i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
441 int vx, vy, ch;
442 i_color val, wval;
443
444 for(vx=0;vx<128;vx++) for(vy=0;vy<110;vy++) {
445
446 i_gpix(im, tx+vx, ty+vy,&val );
447 i_gpix(wmark, vx, vy, &wval);
448
449 for(ch=0;ch<im->channels;ch++)
450 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
451
452 i_ppix(im,tx+vx,ty+vy,&val);
453 }
454}
455
456
457/*
458=item i_autolevels(im, lsat, usat, skew)
459
460Scales and translates each color such that it fills the range completely.
461Skew is not implemented yet - purpose is to control the color skew that can
462occur when changing the contrast.
463
464 im - target image
465 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
466 usat - fraction of pixels that will be truncated at the higher end of the spectrum
467 skew - not used yet
468
469=cut
470*/
471
472void
473i_autolevels(i_img *im, float lsat, float usat, float skew) {
474 i_color val;
475 int i, x, y, rhist[256], ghist[256], bhist[256];
476 int rsum, rmin, rmax;
477 int gsum, gmin, gmax;
478 int bsum, bmin, bmax;
479 int rcl, rcu, gcl, gcu, bcl, bcu;
480
481 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
482
483 rsum=gsum=bsum=0;
484 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
485 /* create histogram for each channel */
486 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
487 i_gpix(im, x, y, &val);
488 rhist[val.channel[0]]++;
489 ghist[val.channel[1]]++;
490 bhist[val.channel[2]]++;
491 }
492
493 for(i=0;i<256;i++) {
494 rsum+=rhist[i];
495 gsum+=ghist[i];
496 bsum+=bhist[i];
497 }
498
499 rmin = gmin = bmin = 0;
500 rmax = gmax = bmax = 255;
501
502 rcu = rcl = gcu = gcl = bcu = bcl = 0;
503
504 for(i=0; i<256; i++) {
505 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
506 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
507
508 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
509 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
510
511 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
512 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
513 }
514
515 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
516 i_gpix(im, x, y, &val);
517 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
518 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
519 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
520 i_ppix(im, x, y, &val);
521 }
522}
523
524/*
525=item Noise(x,y)
526
527Pseudo noise utility function used to generate perlin noise. (internal)
528
529 x - x coordinate
530 y - y coordinate
531
532=cut
533*/
534
535static
536float
537Noise(int x, int y) {
538 int n = x + y * 57;
539 n = (n<<13) ^ n;
540 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
541}
542
543/*
544=item SmoothedNoise1(x,y)
545
546Pseudo noise utility function used to generate perlin noise. (internal)
547
548 x - x coordinate
549 y - y coordinate
550
551=cut
552*/
553
554static
555float
556SmoothedNoise1(float x, float y) {
557 float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
558 float sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
559 float center = Noise(x, y) / 4;
560 return corners + sides + center;
561}
562
563
564/*
565=item G_Interpolate(a, b, x)
566
567Utility function used to generate perlin noise. (internal)
568
569=cut
570*/
571
572static
573float C_Interpolate(float a, float b, float x) {
574 /* float ft = x * 3.1415927; */
575 float ft = x * PI;
576 float f = (1 - cos(ft)) * .5;
577 return a*(1-f) + b*f;
578}
579
580
581/*
582=item InterpolatedNoise(x, y)
583
584Utility function used to generate perlin noise. (internal)
585
586=cut
587*/
588
589static
590float
591InterpolatedNoise(float x, float y) {
592
593 int integer_X = x;
594 float fractional_X = x - integer_X;
595 int integer_Y = y;
596 float fractional_Y = y - integer_Y;
597
598 float v1 = SmoothedNoise1(integer_X, integer_Y);
599 float v2 = SmoothedNoise1(integer_X + 1, integer_Y);
600 float v3 = SmoothedNoise1(integer_X, integer_Y + 1);
601 float v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
602
603 float i1 = C_Interpolate(v1 , v2 , fractional_X);
604 float i2 = C_Interpolate(v3 , v4 , fractional_X);
605
606 return C_Interpolate(i1 , i2 , fractional_Y);
607}
608
609
610
611/*
612=item PerlinNoise_2D(x, y)
613
614Utility function used to generate perlin noise. (internal)
615
616=cut
617*/
618
619static
620float
621PerlinNoise_2D(float x, float y) {
622 int i,frequency;
623 float amplitude;
624 float total = 0;
625 int Number_Of_Octaves=6;
626 int n = Number_Of_Octaves - 1;
627
628 for(i=0;i<n;i++) {
629 frequency = 2*i;
630 amplitude = PI;
631 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
632 }
633
634 return total;
635}
636
637
638/*
639=item i_radnoise(im, xo, yo, rscale, ascale)
640
641Perlin-like radial noise.
642
643 im - target image
644 xo - x coordinate of center
645 yo - y coordinate of center
646 rscale - radial scale
647 ascale - angular scale
648
649=cut
650*/
651
652void
653i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
654 int x, y, ch;
655 i_color val;
656 unsigned char v;
657 float xc, yc, r;
658 double a;
659
660 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
661 xc = (float)x-xo+0.5;
662 yc = (float)y-yo+0.5;
663 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
664 a = (PI+atan2(yc,xc))*ascale;
665 v = saturate(128+100*(PerlinNoise_2D(a,r)));
666 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
667 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
668 i_ppix(im, x, y, &val);
669 }
670}
671
672
673/*
674=item i_turbnoise(im, xo, yo, scale)
675
676Perlin-like 2d noise noise.
677
678 im - target image
679 xo - x coordinate translation
680 yo - y coordinate translation
681 scale - scale of noise
682
683=cut
684*/
685
686void
687i_turbnoise(i_img *im, float xo, float yo, float scale) {
688 int x,y,ch;
689 unsigned char v;
690 i_color val;
691
692 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
693 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
694 v = saturate(120*(1.0+sin(xo+(float)x/scale+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))));
695 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
696 i_ppix(im, x, y, &val);
697 }
698}
699
700
701
702/*
703=item i_gradgen(im, num, xo, yo, ival, dmeasure)
704
705Gradient generating function.
706
707 im - target image
708 num - number of points given
709 xo - array of x coordinates
710 yo - array of y coordinates
711 ival - array of i_color objects
712 dmeasure - distance measure to be used.
713 0 = Euclidean
714 1 = Euclidean squared
715 2 = Manhattan distance
716
717=cut
718*/
719
720
721void
722i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
723
724 i_color val;
725 int p, x, y, ch;
726 int channels = im->channels;
727 int xsize = im->xsize;
728 int ysize = im->ysize;
729
730 float *fdist;
731
732 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
733
734 for(p = 0; p<num; p++) {
735 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
736 ICL_info(&ival[p]);
737 }
738
739 fdist = mymalloc( sizeof(float) * num );
740
741 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
742 float cs = 0;
743 float csd = 0;
744 for(p = 0; p<num; p++) {
745 int xd = x-xo[p];
746 int yd = y-yo[p];
747 switch (dmeasure) {
748 case 0: /* euclidean */
749 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
750 break;
751 case 1: /* euclidean squared */
752 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
753 break;
754 case 2: /* euclidean squared */
755 fdist[p] = max(xd*xd, yd*yd); /* manhattan distance */
756 break;
757 default:
758 m_fatal(3,"i_gradgen: Unknown distance measure\n");
759 }
760 cs += fdist[p];
761 }
762
763 csd = 1/((num-1)*cs);
764
765 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
766
767 for(ch = 0; ch<channels; ch++) {
768 int tres = 0;
769 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
770 val.channel[ch] = saturate(tres);
771 }
772 i_ppix(im, x, y, &val);
773 }
774
775}
776
02d1d628
AMH
777void
778i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
779
a743c0a6 780 int p, x, y;
02d1d628
AMH
781 int xsize = im->xsize;
782 int ysize = im->ysize;
783
784 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
785
786 for(p = 0; p<num; p++) {
787 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
788 ICL_info(&ival[p]);
789 }
790
791 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
792 int midx = 0;
793 float mindist = 0;
794 float curdist = 0;
795
796 int xd = x-xo[0];
797 int yd = y-yo[0];
798
799 switch (dmeasure) {
800 case 0: /* euclidean */
801 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
802 break;
803 case 1: /* euclidean squared */
804 mindist = xd*xd + yd*yd; /* euclidean distance */
805 break;
806 case 2: /* euclidean squared */
807 mindist = max(xd*xd, yd*yd); /* manhattan distance */
808 break;
809 default:
810 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
811 }
812
813 for(p = 1; p<num; p++) {
814 xd = x-xo[p];
815 yd = y-yo[p];
816 switch (dmeasure) {
817 case 0: /* euclidean */
818 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
819 break;
820 case 1: /* euclidean squared */
821 curdist = xd*xd + yd*yd; /* euclidean distance */
822 break;
823 case 2: /* euclidean squared */
824 curdist = max(xd*xd, yd*yd); /* manhattan distance */
825 break;
826 default:
827 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
828 }
829 if (curdist < mindist) {
830 mindist = curdist;
831 midx = p;
832 }
833 }
834 i_ppix(im, x, y, &ival[midx]);
835 }
836}
837
02d1d628
AMH
838void
839i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
840 i_color *ival;
841 float *tval;
842 float c1, c2;
843 i_color val;
844 int p, x, y, ch;
02d1d628
AMH
845 int xsize = im->xsize;
846 int ysize = im->ysize;
847 int *cmatch;
848
d7f707d8 849 mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
02d1d628
AMH
850
851 tval = mymalloc( sizeof(float)*num*im->channels );
852 ival = mymalloc( sizeof(i_color)*num );
853 cmatch = mymalloc( sizeof(int)*num );
854
855 for(p = 0; p<num; p++) {
856 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
857 cmatch[p] = 0;
858 }
859
860
861 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
862 int midx = 0;
863 float mindist = 0;
864 float curdist = 0;
865
866 int xd = x-xo[0];
867 int yd = y-yo[0];
868
869 switch (dmeasure) {
870 case 0: /* euclidean */
871 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
872 break;
873 case 1: /* euclidean squared */
874 mindist = xd*xd + yd*yd; /* euclidean distance */
875 break;
876 case 2: /* euclidean squared */
877 mindist = max(xd*xd, yd*yd); /* manhattan distance */
878 break;
879 default:
880 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
881 }
882
883 for(p = 1; p<num; p++) {
884 xd = x-xo[p];
885 yd = y-yo[p];
886 switch (dmeasure) {
887 case 0: /* euclidean */
888 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
889 break;
890 case 1: /* euclidean squared */
891 curdist = xd*xd + yd*yd; /* euclidean distance */
892 break;
893 case 2: /* euclidean squared */
894 curdist = max(xd*xd, yd*yd); /* manhattan distance */
895 break;
896 default:
897 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
898 }
899 if (curdist < mindist) {
900 mindist = curdist;
901 midx = p;
902 }
903 }
904
905 cmatch[midx]++;
906 i_gpix(im, x, y, &val);
907 c2 = 1.0/(float)(cmatch[midx]);
908 c1 = 1.0-c2;
909
02d1d628
AMH
910 for(ch = 0; ch<im->channels; ch++)
911 tval[midx*im->channels + ch] = c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
3bb1c1f3 912
02d1d628
AMH
913
914 }
915
916 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++) ival[p].channel[ch] = tval[p*im->channels + ch];
917
918 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
919}
6607600c 920
f1ac5027 921struct fount_state;
6607600c
TC
922static double linear_fount_f(double x, double y, struct fount_state *state);
923static double bilinear_fount_f(double x, double y, struct fount_state *state);
924static double radial_fount_f(double x, double y, struct fount_state *state);
925static double square_fount_f(double x, double y, struct fount_state *state);
926static double revolution_fount_f(double x, double y,
927 struct fount_state *state);
928static double conical_fount_f(double x, double y, struct fount_state *state);
929
930typedef double (*fount_func)(double, double, struct fount_state *);
931static fount_func fount_funcs[] =
932{
933 linear_fount_f,
934 bilinear_fount_f,
935 radial_fount_f,
936 square_fount_f,
937 revolution_fount_f,
938 conical_fount_f,
939};
940
941static double linear_interp(double pos, i_fountain_seg *seg);
942static double sine_interp(double pos, i_fountain_seg *seg);
943static double sphereup_interp(double pos, i_fountain_seg *seg);
944static double spheredown_interp(double pos, i_fountain_seg *seg);
945typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
946static fount_interp fount_interps[] =
947{
948 linear_interp,
949 linear_interp,
950 sine_interp,
951 sphereup_interp,
952 spheredown_interp,
953};
954
955static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
956static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
957static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
958typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
959static fount_cinterp fount_cinterps[] =
960{
961 direct_cinterp,
962 hue_up_cinterp,
963 hue_down_cinterp,
964};
965
966typedef double (*fount_repeat)(double v);
967static double fount_r_none(double v);
968static double fount_r_sawtooth(double v);
969static double fount_r_triangle(double v);
970static double fount_r_saw_both(double v);
971static double fount_r_tri_both(double v);
972static fount_repeat fount_repeats[] =
973{
974 fount_r_none,
975 fount_r_sawtooth,
976 fount_r_triangle,
977 fount_r_saw_both,
978 fount_r_tri_both,
979};
980
f1ac5027
TC
981static int simple_ssample(i_fcolor *out, double x, double y,
982 struct fount_state *state);
983static int random_ssample(i_fcolor *out, double x, double y,
984 struct fount_state *state);
985static int circle_ssample(i_fcolor *out, double x, double y,
986 struct fount_state *state);
987typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
988 struct fount_state *state);
6607600c
TC
989static fount_ssample fount_ssamples[] =
990{
991 NULL,
992 simple_ssample,
993 random_ssample,
994 circle_ssample,
995};
996
997static int
f1ac5027
TC
998fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
999
1000/*
1001 Keep state information used by each type of fountain fill
1002*/
1003struct fount_state {
1004 /* precalculated for the equation of the line perpendicular to the line AB */
1005 double lA, lB, lC;
1006 double AB;
1007 double sqrtA2B2;
1008 double mult;
1009 double cos;
1010 double sin;
1011 double theta;
1012 int xa, ya;
1013 void *ssample_data;
1014 fount_func ffunc;
1015 fount_repeat rpfunc;
1016 fount_ssample ssfunc;
1017 double parm;
1018 i_fountain_seg *segs;
1019 int count;
1020};
1021
1022static void
1023fount_init_state(struct fount_state *state, double xa, double ya,
1024 double xb, double yb, i_fountain_type type,
1025 i_fountain_repeat repeat, int combine, int super_sample,
1026 double ssample_param, int count, i_fountain_seg *segs);
1027
1028static void
1029fount_finish_state(struct fount_state *state);
6607600c
TC
1030
1031#define EPSILON (1e-6)
1032
1033/*
1034=item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1035
1036Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1037
1038I<type> controls how the reference points are used:
1039
1040=over
1041
1042=item i_ft_linear
1043
1044linear, where A is 0 and B is 1.
1045
1046=item i_ft_bilinear
1047
1048linear in both directions from A.
1049
1050=item i_ft_radial
1051
1052circular, where A is the centre of the fill, and B is a point
1053on the radius.
1054
1055=item i_ft_radial_square
1056
1057where A is the centre of the fill and B is the centre of
1058one side of the square.
1059
1060=item i_ft_revolution
1061
1062where A is the centre of the fill and B defines the 0/1.0
1063angle of the fill.
1064
1065=item i_ft_conical
1066
1067similar to i_ft_revolution, except that the revolution goes in both
1068directions
1069
1070=back
1071
1072I<repeat> can be one of:
1073
1074=over
1075
1076=item i_fr_none
1077
1078values < 0 are treated as zero, values > 1 are treated as 1.
1079
1080=item i_fr_sawtooth
1081
1082negative values are treated as 0, positive values are modulo 1.0
1083
1084=item i_fr_triangle
1085
1086negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1087mod 1.0), otherwise the same as for sawtooth.
1088
1089=item i_fr_saw_both
1090
1091like i_fr_sawtooth, except that the sawtooth pattern repeats into
1092negative values.
1093
1094=item i_fr_tri_both
1095
1096Like i_fr_triangle, except that negative values are handled as their
1097absolute values.
1098
1099=back
1100
1101If combine is non-zero then non-opaque values are combined with the
1102underlying color.
1103
1104I<super_sample> controls super sampling, if any. At some point I'll
1105probably add a adaptive super-sampler. Current possible values are:
1106
1107=over
1108
1109=item i_fts_none
1110
1111No super-sampling is done.
1112
1113=item i_fts_grid
1114
1115A square grid of points withing the pixel are sampled.
1116
1117=item i_fts_random
1118
1119Random points within the pixel are sampled.
1120
1121=item i_fts_circle
1122
1123Points on the radius of a circle are sampled. This produces fairly
1124good results, but is fairly slow since sin() and cos() are evaluated
1125for each point.
1126
1127=back
1128
1129I<ssample_param> is intended to be roughly the number of points
1130sampled within the pixel.
1131
1132I<count> and I<segs> define the segments of the fill.
1133
1134=cut
1135
1136*/
1137
1138void
1139i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1140 i_fountain_type type, i_fountain_repeat repeat,
1141 int combine, int super_sample, double ssample_param,
1142 int count, i_fountain_seg *segs) {
1143 struct fount_state state;
6607600c
TC
1144 int x, y;
1145 i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize);
f1ac5027
TC
1146 int ch;
1147 i_fountain_seg *my_segs;
1148
1149 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1150 super_sample, ssample_param, count, segs);
1151 my_segs = state.segs;
1152
1153 for (y = 0; y < im->ysize; ++y) {
1154 i_glinf(im, 0, im->xsize, y, line);
1155 for (x = 0; x < im->xsize; ++x) {
1156 i_fcolor c;
1157 int got_one;
1158 double v;
1159 if (super_sample == i_fts_none)
1160 got_one = fount_getat(&c, x, y, &state);
1161 else
1162 got_one = state.ssfunc(&c, x, y, &state);
1163 if (got_one) {
1164 if (combine) {
1165 for (ch = 0; ch < im->channels; ++ch) {
1166 line[x].channel[ch] = line[x].channel[ch] * (1.0 - c.channel[3])
1167 + c.channel[ch] * c.channel[3];
1168 }
1169 }
1170 else
1171 line[x] = c;
1172 }
1173 }
1174 i_plinf(im, 0, im->xsize, y, line);
1175 }
1176 fount_finish_state(&state);
1177 myfree(line);
1178}
1179
1180typedef struct {
1181 i_fill_t base;
1182 struct fount_state state;
1183} i_fill_fountain_t;
1184
1185static void
1186fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
1187 i_fcolor *data);
1188static void
1189fount_fill_destroy(i_fill_t *fill);
1190
1191/*
1192=item i_new_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1193
773bc121
TC
1194Creates a new general fill which fills with a fountain fill.
1195
f1ac5027
TC
1196=cut
1197*/
1198
1199i_fill_t *
1200i_new_fill_fount(double xa, double ya, double xb, double yb,
1201 i_fountain_type type, i_fountain_repeat repeat,
1202 int combine, int super_sample, double ssample_param,
1203 int count, i_fountain_seg *segs) {
1204 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1205
1206 fill->base.fill_with_color = NULL;
1207 fill->base.fill_with_fcolor = fill_fountf;
1208 fill->base.destroy = fount_fill_destroy;
1209 fill->base.combines = combine;
1210 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1211 super_sample, ssample_param, count, segs);
1212
1213 return &fill->base;
1214}
1215
1216/*
1217=back
1218
1219=head1 INTERNAL FUNCTIONS
1220
1221=over
1222
1223=item fount_init_state(...)
1224
1225Used by both the fountain fill filter and the fountain fill.
1226
1227=cut
1228*/
1229
1230static void
1231fount_init_state(struct fount_state *state, double xa, double ya,
1232 double xb, double yb, i_fountain_type type,
1233 i_fountain_repeat repeat, int combine, int super_sample,
1234 double ssample_param, int count, i_fountain_seg *segs) {
6607600c
TC
1235 int i, j;
1236 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count);
f1ac5027 1237 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
6607600c 1238 int ch;
f1ac5027
TC
1239
1240 memset(state, 0, sizeof(*state));
6607600c
TC
1241 /* we keep a local copy that we can adjust for speed */
1242 for (i = 0; i < count; ++i) {
1243 i_fountain_seg *seg = my_segs + i;
1244
1245 *seg = segs[i];
1246 if (seg->type < 0 || type >= i_ft_end)
1247 seg->type = i_ft_linear;
1248 if (seg->color < 0 || seg->color >= i_fc_end)
1249 seg->color = i_fc_direct;
1250 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1251 /* so we don't have to translate to HSV on each request, do it here */
1252 for (j = 0; j < 2; ++j) {
1253 i_rgb_to_hsvf(seg->c+j);
1254 }
1255 if (seg->color == i_fc_hue_up) {
1256 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1257 seg->c[1].channel[0] += 1.0;
1258 }
1259 else {
1260 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1261 seg->c[0].channel[0] += 1.0;
1262 }
1263 }
1264 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1265 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1266 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1267 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1268 seg->c[1].channel[3], seg->type, seg->color);*/
1269
1270 }
1271
1272 /* initialize each engine */
1273 /* these are so common ... */
f1ac5027
TC
1274 state->lA = xb - xa;
1275 state->lB = yb - ya;
1276 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1277 state->xa = xa;
1278 state->ya = ya;
6607600c
TC
1279 switch (type) {
1280 default:
1281 type = i_ft_linear; /* make the invalid value valid */
1282 case i_ft_linear:
1283 case i_ft_bilinear:
f1ac5027
TC
1284 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1285 state->mult = 1;
1286 state->mult = 1/linear_fount_f(xb, yb, state);
6607600c
TC
1287 break;
1288
1289 case i_ft_radial:
f1ac5027
TC
1290 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1291 + (double)(yb-ya)*(yb-ya));
6607600c
TC
1292 break;
1293
1294 case i_ft_radial_square:
f1ac5027
TC
1295 state->cos = state->lA / state->AB;
1296 state->sin = state->lB / state->AB;
1297 state->mult = 1.0 / state->AB;
6607600c
TC
1298 break;
1299
1300 case i_ft_revolution:
f1ac5027
TC
1301 state->theta = atan2(yb-ya, xb-xa);
1302 state->mult = 1.0 / (PI * 2);
6607600c
TC
1303 break;
1304
1305 case i_ft_conical:
f1ac5027
TC
1306 state->theta = atan2(yb-ya, xb-xa);
1307 state->mult = 1.0 / PI;
6607600c
TC
1308 break;
1309 }
f1ac5027 1310 state->ffunc = fount_funcs[type];
6607600c
TC
1311 if (super_sample < 0
1312 || super_sample >= (sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1313 super_sample = 0;
1314 }
f1ac5027 1315 state->ssample_data = NULL;
6607600c
TC
1316 switch (super_sample) {
1317 case i_fts_grid:
1318 ssample_param = floor(0.5 + sqrt(ssample_param));
f1ac5027 1319 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param);
6607600c
TC
1320 break;
1321
1322 case i_fts_random:
1323 case i_fts_circle:
1324 ssample_param = floor(0.5+ssample_param);
f1ac5027 1325 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
6607600c
TC
1326 break;
1327 }
f1ac5027
TC
1328 state->parm = ssample_param;
1329 state->ssfunc = fount_ssamples[super_sample];
6607600c
TC
1330 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1331 repeat = 0;
f1ac5027
TC
1332 state->rpfunc = fount_repeats[repeat];
1333 state->segs = my_segs;
1334 state->count = count;
6607600c
TC
1335}
1336
f1ac5027
TC
1337static void
1338fount_finish_state(struct fount_state *state) {
1339 if (state->ssample_data)
1340 myfree(state->ssample_data);
1341 myfree(state->segs);
1342}
6607600c 1343
6607600c 1344
f1ac5027 1345/*
6607600c
TC
1346=item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1347
1348Evaluates the fountain fill at the given point.
1349
1350This is called by both the non-super-sampling and super-sampling code.
1351
1352You might think that it would make sense to sample the fill parameter
1353instead, and combine those, but this breaks badly.
1354
1355=cut
1356*/
1357
1358static int
f1ac5027
TC
1359fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1360 double v = (state->rpfunc)((state->ffunc)(x, y, state));
6607600c
TC
1361 int i;
1362
1363 i = 0;
f1ac5027
TC
1364 while (i < state->count
1365 && (v < state->segs[i].start || v > state->segs[i].end)) {
6607600c
TC
1366 ++i;
1367 }
f1ac5027
TC
1368 if (i < state->count) {
1369 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1370 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
6607600c
TC
1371 return 1;
1372 }
1373 else
1374 return 0;
1375}
1376
1377/*
1378=item linear_fount_f(x, y, state)
1379
1380Calculate the fill parameter for a linear fountain fill.
1381
1382Uses the point to line distance function, with some precalculation
1383done in i_fountain().
1384
1385=cut
1386*/
1387static double
1388linear_fount_f(double x, double y, struct fount_state *state) {
1389 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1390}
1391
1392/*
1393=item bilinear_fount_f(x, y, state)
1394
1395Calculate the fill parameter for a bi-linear fountain fill.
1396
1397=cut
1398*/
1399static double
1400bilinear_fount_f(double x, double y, struct fount_state *state) {
1401 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1402}
1403
1404/*
1405=item radial_fount_f(x, y, state)
1406
1407Calculate the fill parameter for a radial fountain fill.
1408
1409Simply uses the distance function.
1410
1411=cut
1412 */
1413static double
1414radial_fount_f(double x, double y, struct fount_state *state) {
1415 return sqrt((double)(state->xa-x)*(state->xa-x)
1416 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1417}
1418
1419/*
1420=item square_fount_f(x, y, state)
1421
1422Calculate the fill parameter for a square fountain fill.
1423
1424Works by rotating the reference co-ordinate around the centre of the
1425square.
1426
1427=cut
1428*/
1429static double
1430square_fount_f(double x, double y, struct fount_state *state) {
1431 int xc, yc; /* centred on A */
1432 double xt, yt; /* rotated by theta */
1433 xc = x - state->xa;
1434 yc = y - state->ya;
1435 xt = fabs(xc * state->cos + yc * state->sin);
1436 yt = fabs(-xc * state->sin + yc * state->cos);
1437 return (xt > yt ? xt : yt) * state->mult;
1438}
1439
1440/*
1441=item revolution_fount_f(x, y, state)
1442
1443Calculates the fill parameter for the revolution fountain fill.
1444
1445=cut
1446*/
1447static double
1448revolution_fount_f(double x, double y, struct fount_state *state) {
1449 double angle = atan2(y - state->ya, x - state->xa);
1450
1451 angle -= state->theta;
1452 if (angle < 0) {
1453 angle = fmod(angle+ PI * 4, PI*2);
1454 }
1455
1456 return angle * state->mult;
1457}
1458
1459/*
1460=item conical_fount_f(x, y, state)
1461
1462Calculates the fill parameter for the conical fountain fill.
1463
1464=cut
1465*/
1466static double
1467conical_fount_f(double x, double y, struct fount_state *state) {
1468 double angle = atan2(y - state->ya, x - state->xa);
1469
1470 angle -= state->theta;
1471 if (angle < -PI)
1472 angle += PI * 2;
1473 else if (angle > PI)
1474 angle -= PI * 2;
1475
1476 return fabs(angle) * state->mult;
1477}
1478
1479/*
1480=item linear_interp(pos, seg)
1481
1482Calculates linear interpolation on the fill parameter. Breaks the
1483segment into 2 regions based in the I<middle> value.
1484
1485=cut
1486*/
1487static double
1488linear_interp(double pos, i_fountain_seg *seg) {
1489 if (pos < seg->middle) {
1490 double len = seg->middle - seg->start;
1491 if (len < EPSILON)
1492 return 0.0;
1493 else
1494 return (pos - seg->start) / len / 2;
1495 }
1496 else {
1497 double len = seg->end - seg->middle;
1498 if (len < EPSILON)
1499 return 1.0;
1500 else
1501 return 0.5 + (pos - seg->middle) / len / 2;
1502 }
1503}
1504
1505/*
1506=item sine_interp(pos, seg)
1507
1508Calculates sine function interpolation on the fill parameter.
1509
1510=cut
1511*/
1512static double
1513sine_interp(double pos, i_fountain_seg *seg) {
1514 /* I wonder if there's a simple way to smooth the transition for this */
1515 double work = linear_interp(pos, seg);
1516
1517 return (1-cos(work * PI))/2;
1518}
1519
1520/*
1521=item sphereup_interp(pos, seg)
1522
1523Calculates spherical interpolation on the fill parameter, with the cusp
1524at the low-end.
1525
1526=cut
1527*/
1528static double
1529sphereup_interp(double pos, i_fountain_seg *seg) {
1530 double work = linear_interp(pos, seg);
1531
1532 return sqrt(1.0 - (1-work) * (1-work));
1533}
1534
1535/*
1536=item spheredown_interp(pos, seg)
1537
1538Calculates spherical interpolation on the fill parameter, with the cusp
1539at the high-end.
1540
1541=cut
1542*/
1543static double
1544spheredown_interp(double pos, i_fountain_seg *seg) {
1545 double work = linear_interp(pos, seg);
1546
1547 return 1-sqrt(1.0 - work * work);
1548}
1549
1550/*
1551=item direct_cinterp(out, pos, seg)
1552
1553Calculates the fountain color based on direct scaling of the channels
1554of the color channels.
1555
1556=cut
1557*/
1558static void
1559direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1560 int ch;
1561 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1562 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1563 + seg->c[1].channel[ch] * pos;
1564 }
1565}
1566
1567/*
1568=item hue_up_cinterp(put, pos, seg)
1569
1570Calculates the fountain color based on scaling a HSV value. The hue
1571increases as the fill parameter increases.
1572
1573=cut
1574*/
1575static void
1576hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1577 int ch;
1578 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1579 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1580 + seg->c[1].channel[ch] * pos;
1581 }
1582 i_hsv_to_rgbf(out);
1583}
1584
1585/*
1586=item hue_down_cinterp(put, pos, seg)
1587
1588Calculates the fountain color based on scaling a HSV value. The hue
1589decreases as the fill parameter increases.
1590
1591=cut
1592*/
1593static void
1594hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1595 int ch;
1596 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1597 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1598 + seg->c[1].channel[ch] * pos;
1599 }
1600 i_hsv_to_rgbf(out);
1601}
1602
1603/*
1604=item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1605
1606Simple grid-based super-sampling.
1607
1608=cut
1609*/
1610static int
f1ac5027 1611simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
6607600c
TC
1612 i_fcolor *work = state->ssample_data;
1613 int dx, dy;
f1ac5027 1614 int grid = state->parm;
6607600c
TC
1615 double base = -0.5 + 0.5 / grid;
1616 double step = 1.0 / grid;
1617 int ch, i;
1618 int samp_count = 0;
1619
1620 for (dx = 0; dx < grid; ++dx) {
1621 for (dy = 0; dy < grid; ++dy) {
1622 if (fount_getat(work+samp_count, x + base + step * dx,
f1ac5027 1623 y + base + step * dy, state)) {
6607600c
TC
1624 ++samp_count;
1625 }
1626 }
1627 }
1628 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1629 out->channel[ch] = 0;
1630 for (i = 0; i < samp_count; ++i) {
1631 out->channel[ch] += work[i].channel[ch];
1632 }
1633 /* we divide by 4 rather than samp_count since if there's only one valid
1634 sample it should be mostly transparent */
1635 out->channel[ch] /= grid * grid;
1636 }
1637 return samp_count;
1638}
1639
1640/*
1641=item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1642
1643Random super-sampling.
1644
1645=cut
1646*/
1647static int
f1ac5027
TC
1648random_ssample(i_fcolor *out, double x, double y,
1649 struct fount_state *state) {
6607600c
TC
1650 i_fcolor *work = state->ssample_data;
1651 int i, ch;
f1ac5027 1652 int maxsamples = state->parm;
6607600c
TC
1653 double rand_scale = 1.0 / RAND_MAX;
1654 int samp_count = 0;
1655 for (i = 0; i < maxsamples; ++i) {
1656 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
f1ac5027 1657 y - 0.5 + rand() * rand_scale, state)) {
6607600c
TC
1658 ++samp_count;
1659 }
1660 }
1661 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1662 out->channel[ch] = 0;
1663 for (i = 0; i < samp_count; ++i) {
1664 out->channel[ch] += work[i].channel[ch];
1665 }
1666 /* we divide by maxsamples rather than samp_count since if there's
1667 only one valid sample it should be mostly transparent */
1668 out->channel[ch] /= maxsamples;
1669 }
1670 return samp_count;
1671}
1672
1673/*
1674=item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1675
1676Super-sampling around the circumference of a circle.
1677
1678I considered saving the sin()/cos() values and transforming step-size
1679around the circle, but that's inaccurate, though it may not matter
1680much.
1681
1682=cut
1683 */
1684static int
f1ac5027
TC
1685circle_ssample(i_fcolor *out, double x, double y,
1686 struct fount_state *state) {
6607600c
TC
1687 i_fcolor *work = state->ssample_data;
1688 int i, ch;
f1ac5027 1689 int maxsamples = state->parm;
6607600c
TC
1690 double angle = 2 * PI / maxsamples;
1691 double radius = 0.3; /* semi-random */
1692 int samp_count = 0;
1693 for (i = 0; i < maxsamples; ++i) {
1694 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
f1ac5027 1695 y + radius * sin(angle * i), state)) {
6607600c
TC
1696 ++samp_count;
1697 }
1698 }
1699 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1700 out->channel[ch] = 0;
1701 for (i = 0; i < samp_count; ++i) {
1702 out->channel[ch] += work[i].channel[ch];
1703 }
1704 /* we divide by maxsamples rather than samp_count since if there's
1705 only one valid sample it should be mostly transparent */
1706 out->channel[ch] /= maxsamples;
1707 }
1708 return samp_count;
1709}
1710
1711/*
1712=item fount_r_none(v)
1713
1714Implements no repeats. Simply clamps the fill value.
1715
1716=cut
1717*/
1718static double
1719fount_r_none(double v) {
1720 return v < 0 ? 0 : v > 1 ? 1 : v;
1721}
1722
1723/*
1724=item fount_r_sawtooth(v)
1725
1726Implements sawtooth repeats. Clamps negative values and uses fmod()
1727on others.
1728
1729=cut
1730*/
1731static double
1732fount_r_sawtooth(double v) {
1733 return v < 0 ? 0 : fmod(v, 1.0);
1734}
1735
1736/*
1737=item fount_r_triangle(v)
1738
1739Implements triangle repeats. Clamps negative values, uses fmod to get
1740a range 0 through 2 and then adjusts values > 1.
1741
1742=cut
1743*/
1744static double
1745fount_r_triangle(double v) {
1746 if (v < 0)
1747 return 0;
1748 else {
1749 v = fmod(v, 2.0);
1750 return v > 1.0 ? 2.0 - v : v;
1751 }
1752}
1753
1754/*
1755=item fount_r_saw_both(v)
1756
1757Implements sawtooth repeats in the both postive and negative directions.
1758
1759Adjusts the value to be postive and then just uses fmod().
1760
1761=cut
1762*/
1763static double
1764fount_r_saw_both(double v) {
1765 if (v < 0)
1766 v += 1+(int)(-v);
1767 return fmod(v, 1.0);
1768}
1769
1770/*
1771=item fount_r_tri_both(v)
1772
1773Implements triangle repeats in the both postive and negative directions.
1774
1775Uses fmod on the absolute value, and then adjusts values > 1.
1776
1777=cut
1778*/
1779static double
1780fount_r_tri_both(double v) {
1781 v = fmod(fabs(v), 2.0);
1782 return v > 1.0 ? 2.0 - v : v;
1783}
1784
f1ac5027
TC
1785/*
1786=item fill_fountf(fill, x, y, width, channels, data)
1787
1788The fill function for fountain fills.
1789
1790=cut
1791*/
1792static void
1793fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
1794 i_fcolor *data) {
1795 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
1796 int ch;
1797
1798 while (width--) {
1799 i_fcolor c;
1800 int got_one;
1801 double v;
1802 if (f->state.ssfunc)
1803 got_one = f->state.ssfunc(&c, x, y, &f->state);
1804 else
1805 got_one = fount_getat(&c, x, y, &f->state);
1806
1807 if (got_one) {
1808 if (f->base.combines) {
1809 for (ch = 0; ch < channels; ++ch) {
1810 data->channel[ch] = data->channel[ch] * (1.0 - c.channel[3])
1811 + c.channel[ch] * c.channel[3];
1812 }
1813 }
1814 else
1815 *data = c;
1816 }
1817
1818 ++x;
1819 ++data;
1820 }
1821}
1822
1823/*
1824=item fount_fill_destroy(fill)
1825
1826=cut
1827*/
1828static void
1829fount_fill_destroy(i_fill_t *fill) {
1830 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
1831 fount_finish_state(&f->state);
1832}
1833
6607600c
TC
1834/*
1835=back
1836
1837=head1 AUTHOR
1838
1839Arnar M. Hrafnkelsson <addi@umich.edu>
1840
1841Tony Cook <tony@develop-help.com> (i_fountain())
1842
1843=head1 SEE ALSO
1844
1845Imager(3)
1846
1847=cut
1848*/