]> git.imager.perl.org - imager.git/blob - filters.im
0.73 release
[imager.git] / filters.im
1 #include "imager.h"
2 #include "imageri.h"
3 #include <stdlib.h>
4 #include <math.h>
5
6
7 /*
8 =head1 NAME
9
10 filters.im - implements filters that operate on images
11
12 =head1 SYNOPSIS
13
14   
15   i_contrast(im, 0.8);
16   i_hardinvert(im);
17   i_unsharp_mask(im, 2.0, 1.0);
18   // and more
19
20 =head1 DESCRIPTION
21
22 filters.c implements basic filters for Imager.  These filters
23 should be accessible from the filter interface as defined in 
24 the pod for Imager.
25
26 =head1 FUNCTION REFERENCE
27
28 Some of these functions are internal.
29
30 =over
31
32 =cut
33 */
34
35
36
37
38 /*
39 =item saturate(in) 
40
41 Clamps the input value between 0 and 255. (internal)
42
43   in - input integer
44
45 =cut
46 */
47
48 static
49 unsigned char
50 saturate(int in) {
51   if (in>255) { return 255; }
52   else if (in>0) return in;
53   return 0;
54 }
55
56
57
58 /* 
59 =item i_contrast(im, intensity)
60
61 Scales the pixel values by the amount specified.
62
63   im        - image object
64   intensity - scalefactor
65
66 =cut
67 */
68
69 void
70 i_contrast(i_img *im, float intensity) {
71   int x, y;
72   unsigned char ch;
73   unsigned int new_color;
74   i_color rcolor;
75   
76   mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
77   
78   if(intensity < 0) return;
79   
80   for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
81     i_gpix(im, x, y, &rcolor);
82       
83     for(ch = 0; ch < im->channels; ch++) {
84       new_color = (unsigned int) rcolor.channel[ch];
85       new_color *= intensity;
86         
87       if(new_color > 255) {
88         new_color = 255;
89       }
90       rcolor.channel[ch] = (unsigned char) new_color;
91     }
92     i_ppix(im, x, y, &rcolor);
93   }
94 }
95
96
97 /* 
98 =item i_hardinvert(im)
99
100 Inverts the pixel values of the input image.
101
102   im        - image object
103
104 =cut
105 */
106
107 void
108 i_hardinvert(i_img *im) {
109   int x, y;
110   int ch;
111   int color_channels = i_img_color_channels(im);
112
113   mm_log((1,"i_hardinvert(im %p)\n", im));
114   
115 #code im->bits <= 8  
116   IM_COLOR *row, *entry;
117   
118   /* always rooms to allocate a single line of i_color */
119   row = mymalloc(sizeof(IM_COLOR) * im->xsize); /* checked 17feb2005 tonyc */
120
121   for(y = 0; y < im->ysize; y++) {
122     IM_GLIN(im, 0, im->xsize, y, row);
123     entry = row;
124     for(x = 0; x < im->xsize; x++) {
125       for(ch = 0; ch < color_channels; ch++) {
126         entry->channel[ch] = IM_SAMPLE_MAX - entry->channel[ch];
127       }
128       ++entry;
129     }
130     IM_PLIN(im, 0, im->xsize, y, row);
131   }  
132   myfree(row);
133 #/code
134 }
135
136
137
138 /*
139 =item i_noise(im, amount, type)
140
141 Inverts the pixel values by the amount specified.
142
143   im     - image object
144   amount - deviation in pixel values
145   type   - noise individual for each channel if true
146
147 =cut
148 */
149
150 #ifdef WIN32
151 /* random() is non-ASCII, even if it is better than rand() */
152 #define random() rand()
153 #endif
154
155 void
156 i_noise(i_img *im, float amount, unsigned char type) {
157   int x, y;
158   unsigned char ch;
159   int new_color;
160   float damount = amount * 2;
161   i_color rcolor;
162   int color_inc = 0;
163   
164   mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
165   
166   if(amount < 0) return;
167   
168   for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
169     i_gpix(im, x, y, &rcolor);
170     
171     if(type == 0) {
172       color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
173     }
174     
175     for(ch = 0; ch < im->channels; ch++) {
176       new_color = (int) rcolor.channel[ch];
177       
178       if(type != 0) {
179         new_color += (amount - (damount * ((float)random() / RAND_MAX)));
180       } else {
181         new_color += color_inc;
182       }
183       
184       if(new_color < 0) {
185         new_color = 0;
186       }
187       if(new_color > 255) {
188         new_color = 255;
189       }
190       
191       rcolor.channel[ch] = (unsigned char) new_color;
192     }
193     
194     i_ppix(im, x, y, &rcolor);
195   }
196 }
197
198
199 /* 
200 =item i_noise(im, amount, type)
201
202 Inverts the pixel values by the amount specified.
203
204   im     - image object
205   amount - deviation in pixel values
206   type   - noise individual for each channel if true
207
208 =cut
209 */
210
211
212 /*
213 =item i_applyimage(im, add_im, mode)
214
215 Apply's an image to another image
216
217   im     - target image
218   add_im - image that is applied to target
219   mode   - what method is used in applying:
220
221   0   Normal    
222   1   Multiply
223   2   Screen
224   3   Overlay
225   4   Soft Light
226   5   Hard Light
227   6   Color dodge
228   7   Color Burn
229   8   Darker
230   9   Lighter
231   10  Add
232   11  Subtract
233   12  Difference
234   13  Exclusion
235         
236 =cut
237 */
238
239 void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
240   int x, y;
241   int mx, my;
242
243   mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
244   
245   mx = (add_im->xsize <= im->xsize) ? add_im->xsize : add_im->xsize;
246   my = (add_im->ysize <= im->ysize) ? add_im->ysize : add_im->ysize;
247   
248   for(x = 0; x < mx; x++) {             
249     for(y = 0; y < my; y++) {
250     }
251   }
252 }
253
254
255 /* 
256 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
257
258 Makes a bumpmap on image im using the bump image as the elevation map.
259
260   im      - target image
261   bump    - image that contains the elevation info
262   channel - to take the elevation information from
263   light_x - x coordinate of light source
264   light_y - y coordinate of light source
265   st      - length of shadow
266
267 =cut
268 */
269
270 void
271 i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
272   int x, y, ch;
273   int mx, my;
274   i_color x1_color, y1_color, x2_color, y2_color, dst_color;
275   double nX, nY;
276   double tX, tY, tZ;
277   double aX, aY, aL;
278   double fZ;
279   unsigned char px1, px2, py1, py2;
280   
281   i_img new_im;
282
283   mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light_x %d, light_y %d, st %d)\n",
284           im, bump, channel, light_x, light_y, st));
285
286
287   if(channel >= bump->channels) {
288     mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
289     return;
290   }
291
292   mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
293   my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
294
295   i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
296   
297   aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
298   aY = (light_y > (my >> 1)) ? light_y : my - light_y;
299
300   aL = sqrt((aX * aX) + (aY * aY));
301
302   for(y = 1; y < my - 1; y++) {         
303     for(x = 1; x < mx - 1; x++) {
304       i_gpix(bump, x + st, y, &x1_color);
305       i_gpix(bump, x, y + st, &y1_color);
306       i_gpix(bump, x - st, y, &x2_color);
307       i_gpix(bump, x, y - st, &y2_color);
308
309       i_gpix(im, x, y, &dst_color);
310
311       px1 = x1_color.channel[channel];
312       py1 = y1_color.channel[channel];
313       px2 = x2_color.channel[channel];
314       py2 = y2_color.channel[channel];
315
316       nX = px1 - px2;
317       nY = py1 - py2;
318
319       nX += 128;
320       nY += 128;
321
322       fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
323  
324       tX = abs(x - light_x) / aL;
325       tY = abs(y - light_y) / aL;
326
327       tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
328       
329       if(tZ < 0) tZ = 0;
330       if(tZ > 2) tZ = 2;
331
332       for(ch = 0; ch < im->channels; ch++)
333         dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
334       
335       i_ppix(&new_im, x, y, &dst_color);
336     }
337   }
338
339   i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
340   
341   i_img_exorcise(&new_im);
342 }
343
344
345
346
347 typedef struct {
348   float x,y,z;
349 } fvec;
350
351
352 static
353 float
354 dotp(fvec *a, fvec *b) {
355   return a->x*b->x+a->y*b->y+a->z*b->z;
356 }
357
358 static
359 void
360 normalize(fvec *a) {
361   double d = sqrt(dotp(a,a));
362   a->x /= d;
363   a->y /= d;
364   a->z /= d;
365 }
366
367
368 /*
369   positive directions:
370   
371   x - right, 
372   y - down
373   z - out of the plane
374   
375   I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
376   
377   Here, the variables are:
378   
379   * Ia   - ambient colour
380   * Ip   - intensity of the point light source
381   * cd   - diffuse coefficient
382   * Scol - surface colour
383   * cs   - specular coefficient
384   * n    - objects shinyness
385   * N    - normal vector
386   * L    - lighting vector
387   * R    - reflection vector
388   * V    - vision vector
389
390   static void fvec_dump(fvec *x) {
391     printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
392   }
393 */
394
395 /* XXX: Should these return a code for success? */
396
397
398
399
400 /* 
401 =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
402
403 Makes a bumpmap on image im using the bump image as the elevation map.
404
405   im      - target image
406   bump    - image that contains the elevation info
407   channel - to take the elevation information from
408   tx      - shift in x direction of where to start applying bumpmap
409   ty      - shift in y direction of where to start applying bumpmap
410   Lx      - x position/direction of light
411   Ly      - y position/direction of light
412   Lz      - z position/direction of light
413   Ip      - light intensity
414   cd      - diffuse coefficient
415   cs      - specular coefficient
416   n       - surface shinyness
417   Ia      - ambient colour
418   Il      - light colour
419   Is      - specular colour
420
421 if z<0 then the L is taken to be the direction the light is shining in.  Otherwise
422 the L is taken to be the position of the Light, Relative to the image.
423
424 =cut
425 */
426
427
428 void
429 i_bumpmap_complex(i_img *im,
430                   i_img *bump,
431                   int channel,
432                   int tx,
433                   int ty,
434                   float Lx,
435                   float Ly,
436                   float Lz,
437                   float cd,
438                   float cs,
439                   float n,
440                   i_color *Ia,
441                   i_color *Il,
442                   i_color *Is) {
443   i_img new_im;
444   
445   int inflight;
446   int x, y, ch;
447   int mx, Mx, my, My;
448   
449   float cdc[MAXCHANNELS];
450   float csc[MAXCHANNELS];
451
452   i_color x1_color, y1_color, x2_color, y2_color;
453
454   i_color Scol;   /* Surface colour       */
455
456   fvec L;         /* Light vector */
457   fvec N;         /* surface normal       */
458   fvec R;         /* Reflection vector    */
459   fvec V;         /* Vision vector        */
460
461   mm_log((1, "i_bumpmap_complex(im %p, bump %p, channel %d, tx %d, ty %d, Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n",
462           im, bump, channel, tx, ty, Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
463   
464   if (channel >= bump->channels) {
465     mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
466     return;
467   }
468
469   for(ch=0; ch<im->channels; ch++) {
470     cdc[ch] = (float)Il->channel[ch]*cd/255.f;
471     csc[ch] = (float)Is->channel[ch]*cs/255.f;
472   }
473
474   mx = 1;
475   my = 1;
476   Mx = bump->xsize-1;
477   My = bump->ysize-1;
478   
479   V.x = 0;
480   V.y = 0;
481   V.z = 1;
482   
483   if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
484     L.x = -Lx;
485     L.y = -Ly;
486     L.z = -Lz;
487     normalize(&L);
488   } else {      /* Light is the position of the light source */
489     inflight = 0;
490     L.x = -0.2;
491     L.y = -0.4;
492     L.z =  1;
493     normalize(&L);
494   }
495
496   i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
497
498   for(y = 0; y < im->ysize; y++) {              
499     for(x = 0; x < im->xsize; x++) {
500       double dp1, dp2;
501       double dx = 0, dy = 0;
502
503       /* Calculate surface normal */
504       if (mx<x && x<Mx && my<y && y<My) {
505         i_gpix(bump, x + 1, y,     &x1_color);
506         i_gpix(bump, x - 1, y,     &x2_color);
507         i_gpix(bump, x,     y + 1, &y1_color);
508         i_gpix(bump, x,     y - 1, &y2_color);
509         dx = x2_color.channel[channel] - x1_color.channel[channel];
510         dy = y2_color.channel[channel] - y1_color.channel[channel];
511       } else {
512         dx = 0;
513         dy = 0;
514       }
515       N.x = -dx * 0.015;
516       N.y = -dy * 0.015;
517       N.z = 1;
518       normalize(&N);
519
520       /* Calculate Light vector if needed */
521       if (Lz>=0) {
522         L.x = Lx - x;
523         L.y = Ly - y;
524         L.z = Lz;
525         normalize(&L);
526       }
527       
528       dp1 = dotp(&L,&N);
529       R.x = -L.x + 2*dp1*N.x;
530       R.y = -L.y + 2*dp1*N.y;
531       R.z = -L.z + 2*dp1*N.z;
532       
533       dp2 = dotp(&R,&V);
534
535       dp1 = dp1<0 ?0 : dp1;
536       dp2 = pow(dp2<0 ?0 : dp2,n);
537
538       i_gpix(im, x, y, &Scol);
539
540       for(ch = 0; ch < im->channels; ch++)
541         Scol.channel[ch] = 
542           saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
543       
544       i_ppix(&new_im, x, y, &Scol);
545     }
546   }
547   
548   i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
549   i_img_exorcise(&new_im);
550 }
551
552
553 /* 
554 =item i_postlevels(im, levels)
555
556 Quantizes Images to fewer levels.
557
558   im      - target image
559   levels  - number of levels
560
561 =cut
562 */
563
564 void
565 i_postlevels(i_img *im, int levels) {
566   int x, y, ch;
567   float pv;
568   int rv;
569   float av;
570
571   i_color rcolor;
572
573   rv = (int) ((float)(256 / levels));
574   av = (float)levels;
575
576   for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
577     i_gpix(im, x, y, &rcolor);
578
579     for(ch = 0; ch < im->channels; ch++) {
580       pv = (((float)rcolor.channel[ch] / 255)) * av;
581       pv = (int) ((int)pv * rv);
582
583       if(pv < 0) pv = 0;
584       else if(pv > 255) pv = 255;
585
586       rcolor.channel[ch] = (unsigned char) pv;
587     }
588     i_ppix(im, x, y, &rcolor);
589   }
590 }
591
592
593 /* 
594 =item i_mosaic(im, size)
595
596 Makes an image looks like a mosaic with tilesize of size
597
598   im      - target image
599   size    - size of tiles
600
601 =cut
602 */
603
604 void
605 i_mosaic(i_img *im, int size) {
606   int x, y, ch;
607   int lx, ly, z;
608   long sqrsize;
609
610   i_color rcolor;
611   long col[256];
612   
613   sqrsize = size * size;
614   
615   for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
616     for(z = 0; z < 256; z++) col[z] = 0;
617     
618     for(lx = 0; lx < size; lx++) {
619       for(ly = 0; ly < size; ly++) {
620         i_gpix(im, (x + lx), (y + ly), &rcolor);
621           
622         for(ch = 0; ch < im->channels; ch++) {
623           col[ch] += rcolor.channel[ch];
624         }
625       }
626     }
627       
628     for(ch = 0; ch < im->channels; ch++)
629       rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
630     
631     
632     for(lx = 0; lx < size; lx++)
633       for(ly = 0; ly < size; ly++)
634       i_ppix(im, (x + lx), (y + ly), &rcolor);
635     
636   }
637 }
638
639
640 /*
641 =item i_watermark(im, wmark, tx, ty, pixdiff) 
642
643 Applies a watermark to the target image
644
645   im      - target image
646   wmark   - watermark image
647   tx      - x coordinate of where watermark should be applied
648   ty      - y coordinate of where watermark should be applied
649   pixdiff - the magnitude of the watermark, controls how visible it is
650
651 =cut
652 */
653
654 void
655 i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
656   int vx, vy, ch;
657   i_color val, wval;
658
659         int mx = wmark->xsize;
660         int my = wmark->ysize;
661
662   for(vx=0;vx<mx;vx++) for(vy=0;vy<my;vy++) {
663     
664     i_gpix(im,    tx+vx, ty+vy,&val );
665     i_gpix(wmark, vx,    vy,   &wval);
666     
667     for(ch=0;ch<im->channels;ch++) 
668       val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
669     
670     i_ppix(im,tx+vx,ty+vy,&val);
671   }
672 }
673
674
675 /*
676 =item i_autolevels(im, lsat, usat, skew)
677
678 Scales and translates each color such that it fills the range completely.
679 Skew is not implemented yet - purpose is to control the color skew that can
680 occur when changing the contrast.
681
682   im   - target image
683   lsat - fraction of pixels that will be truncated at the lower end of the spectrum
684   usat - fraction of pixels that will be truncated at the higher end of the spectrum
685   skew - not used yet
686
687 =cut
688 */
689
690 void
691 i_autolevels(i_img *im, float lsat, float usat, float skew) {
692   i_color val;
693   int i, x, y, rhist[256], ghist[256], bhist[256];
694   int rsum, rmin, rmax;
695   int gsum, gmin, gmax;
696   int bsum, bmin, bmax;
697   int rcl, rcu, gcl, gcu, bcl, bcu;
698
699   mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
700
701   rsum=gsum=bsum=0;
702   for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
703   /* create histogram for each channel */
704   for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
705     i_gpix(im, x, y, &val);
706     rhist[val.channel[0]]++;
707     ghist[val.channel[1]]++;
708     bhist[val.channel[2]]++;
709   }
710
711   for(i=0;i<256;i++) {
712     rsum+=rhist[i];
713     gsum+=ghist[i];
714     bsum+=bhist[i];
715   }
716   
717   rmin = gmin = bmin = 0;
718   rmax = gmax = bmax = 255;
719   
720   rcu = rcl = gcu = gcl = bcu = bcl = 0;
721   
722   for(i=0; i<256; i++) { 
723     rcl += rhist[i];     if ( (rcl<rsum*lsat) ) rmin=i;
724     rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
725
726     gcl += ghist[i];     if ( (gcl<gsum*lsat) ) gmin=i;
727     gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
728
729     bcl += bhist[i];     if ( (bcl<bsum*lsat) ) bmin=i;
730     bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
731   }
732
733   for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
734     i_gpix(im, x, y, &val);
735     val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
736     val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
737     val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
738     i_ppix(im, x, y, &val);
739   }
740 }
741
742 /*
743 =item Noise(x,y)
744
745 Pseudo noise utility function used to generate perlin noise. (internal)
746
747   x - x coordinate
748   y - y coordinate
749
750 =cut
751 */
752
753 static
754 float
755 Noise(int x, int y) {
756   int n = x + y * 57; 
757   n = (n<<13) ^ n;
758   return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
759 }
760
761 /*
762 =item SmoothedNoise1(x,y)
763
764 Pseudo noise utility function used to generate perlin noise. (internal)
765
766   x - x coordinate
767   y - y coordinate
768
769 =cut
770 */
771
772 static
773 float
774 SmoothedNoise1(float x, float y) {
775   float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
776   float sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8;
777   float center  =  Noise(x, y) / 4;
778   return corners + sides + center;
779 }
780
781
782 /*
783 =item G_Interpolate(a, b, x)
784
785 Utility function used to generate perlin noise. (internal)
786
787 =cut
788 */
789
790 static
791 float C_Interpolate(float a, float b, float x) {
792   /*  float ft = x * 3.1415927; */
793   float ft = x * PI;
794   float f = (1 - cos(ft)) * .5;
795   return  a*(1-f) + b*f;
796 }
797
798
799 /*
800 =item InterpolatedNoise(x, y)
801
802 Utility function used to generate perlin noise. (internal)
803
804 =cut
805 */
806
807 static
808 float
809 InterpolatedNoise(float x, float y) {
810
811   int integer_X = x;
812   float fractional_X = x - integer_X;
813   int integer_Y = y;
814   float fractional_Y = y - integer_Y;
815
816   float v1 = SmoothedNoise1(integer_X,     integer_Y);
817   float v2 = SmoothedNoise1(integer_X + 1, integer_Y);
818   float v3 = SmoothedNoise1(integer_X,     integer_Y + 1);
819   float v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
820
821   float i1 = C_Interpolate(v1 , v2 , fractional_X);
822   float i2 = C_Interpolate(v3 , v4 , fractional_X);
823
824   return C_Interpolate(i1 , i2 , fractional_Y);
825 }
826
827
828
829 /*
830 =item PerlinNoise_2D(x, y)
831
832 Utility function used to generate perlin noise. (internal)
833
834 =cut
835 */
836
837 static
838 float
839 PerlinNoise_2D(float x, float y) {
840   int i,frequency;
841   float amplitude;
842   float total = 0;
843   int Number_Of_Octaves=6;
844   int n = Number_Of_Octaves - 1;
845
846   for(i=0;i<n;i++) {
847     frequency = 2*i;
848     amplitude = PI;
849     total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
850   }
851
852   return total;
853 }
854
855
856 /*
857 =item i_radnoise(im, xo, yo, rscale, ascale)
858
859 Perlin-like radial noise.
860
861   im     - target image
862   xo     - x coordinate of center
863   yo     - y coordinate of center
864   rscale - radial scale
865   ascale - angular scale
866
867 =cut
868 */
869
870 void
871 i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
872   int x, y, ch;
873   i_color val;
874   unsigned char v;
875   float xc, yc, r;
876   double a;
877   
878   for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
879     xc = (float)x-xo+0.5;
880     yc = (float)y-yo+0.5;
881     r = rscale*sqrt(xc*xc+yc*yc)+1.2;
882     a = (PI+atan2(yc,xc))*ascale;
883     v = saturate(128+100*(PerlinNoise_2D(a,r)));
884     /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale));  Good soft marble */ 
885     for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
886     i_ppix(im, x, y, &val);
887   }
888 }
889
890
891 /*
892 =item i_turbnoise(im, xo, yo, scale)
893
894 Perlin-like 2d noise noise.
895
896   im     - target image
897   xo     - x coordinate translation
898   yo     - y coordinate translation
899   scale  - scale of noise
900
901 =cut
902 */
903
904 void
905 i_turbnoise(i_img *im, float xo, float yo, float scale) {
906   int x,y,ch;
907   unsigned char v;
908   i_color val;
909
910   for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
911     /*    v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
912     v = saturate(120*(1.0+sin(xo+(float)x/scale+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))));
913     for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
914     i_ppix(im, x, y, &val);
915   }
916 }
917
918
919
920 /*
921 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
922
923 Gradient generating function.
924
925   im     - target image
926   num    - number of points given
927   xo     - array of x coordinates
928   yo     - array of y coordinates
929   ival   - array of i_color objects
930   dmeasure - distance measure to be used.  
931     0 = Euclidean
932     1 = Euclidean squared
933     2 = Manhattan distance
934
935 =cut
936 */
937
938
939 void
940 i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
941   
942   i_color val;
943   int p, x, y, ch;
944   int channels = im->channels;
945   int xsize    = im->xsize;
946   int ysize    = im->ysize;
947   int bytes;
948
949   float *fdist;
950
951   mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
952   
953   for(p = 0; p<num; p++) {
954     mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
955     ICL_info(&ival[p]);
956   }
957
958   /* on the systems I have sizeof(float) == sizeof(int) and thus
959      this would be same size as the arrays xo and yo point at, but this
960      may not be true for other systems
961
962      since the arrays here are caller controlled, I assume that on
963      overflow is a programming error rather than an end-user error, so
964      calling exit() is justified.
965   */
966   bytes = sizeof(float) * num;
967   if (bytes / num != sizeof(float)) {
968     fprintf(stderr, "integer overflow calculating memory allocation");
969     exit(1);
970   }
971   fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
972   
973   for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
974     float cs = 0;
975     float csd = 0;
976     for(p = 0; p<num; p++) {
977       int xd    = x-xo[p];
978       int yd    = y-yo[p];
979       switch (dmeasure) {
980       case 0: /* euclidean */
981         fdist[p]  = sqrt(xd*xd + yd*yd); /* euclidean distance */
982         break;
983       case 1: /* euclidean squared */
984         fdist[p]  = xd*xd + yd*yd; /* euclidean distance */
985         break;
986       case 2: /* euclidean squared */
987         fdist[p]  = i_max(xd*xd, yd*yd); /* manhattan distance */
988         break;
989       default:
990         i_fatal(3,"i_gradgen: Unknown distance measure\n");
991       }
992       cs += fdist[p];
993     }
994     
995     csd = 1/((num-1)*cs);
996
997     for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
998     
999     for(ch = 0; ch<channels; ch++) {
1000       int tres = 0;
1001       for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
1002       val.channel[ch] = saturate(tres);
1003     }
1004     i_ppix(im, x, y, &val); 
1005   }
1006   myfree(fdist);
1007   
1008 }
1009
1010 void
1011 i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
1012
1013   int p, x, y;
1014   int xsize    = im->xsize;
1015   int ysize    = im->ysize;
1016
1017   mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
1018   
1019   for(p = 0; p<num; p++) {
1020     mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
1021     ICL_info(&ival[p]);
1022   }
1023
1024   for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1025     int   midx    = 0;
1026     float mindist = 0;
1027     float curdist = 0;
1028
1029     int xd        = x-xo[0];
1030     int yd        = y-yo[0];
1031
1032     switch (dmeasure) {
1033     case 0: /* euclidean */
1034       mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1035       break;
1036     case 1: /* euclidean squared */
1037       mindist = xd*xd + yd*yd; /* euclidean distance */
1038       break;
1039     case 2: /* euclidean squared */
1040       mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1041       break;
1042     default:
1043       i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1044     }
1045
1046     for(p = 1; p<num; p++) {
1047       xd = x-xo[p];
1048       yd = y-yo[p];
1049       switch (dmeasure) {
1050       case 0: /* euclidean */
1051         curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1052         break;
1053       case 1: /* euclidean squared */
1054         curdist = xd*xd + yd*yd; /* euclidean distance */
1055         break;
1056       case 2: /* euclidean squared */
1057         curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1058         break;
1059       default:
1060         i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1061       }
1062       if (curdist < mindist) {
1063         mindist = curdist;
1064         midx = p;
1065       }
1066     }
1067     i_ppix(im, x, y, &ival[midx]); 
1068   }
1069 }
1070
1071 /*
1072 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1073
1074 This wasn't document - quoth Addi:
1075
1076   An arty type of filter
1077
1078 FIXME: check IRC logs for actual text.
1079
1080 Inputs:
1081
1082 =over
1083
1084 =item *
1085
1086 i_img *im - image to render on.
1087
1088 =item *
1089
1090 int num - number of points/colors in xo, yo, oval
1091
1092 =item *
1093
1094 int *xo - array of I<num> x positions
1095
1096 =item *
1097
1098 int *yo - array of I<num> y positions
1099
1100 =item *
1101
1102 i_color *oval - array of I<num> colors
1103
1104 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1105 color something like oval[i], at least closer to that color than other
1106 points.
1107
1108 =item *
1109
1110 int dmeasure - how we measure the distance from some point P(x,y) to
1111 any (xo[i], yo[i]).
1112
1113 Valid values are:
1114
1115 =over
1116
1117 =item 0
1118
1119 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1120
1121 =item 1
1122
1123 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1124
1125 =item 2
1126
1127 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1128
1129 =back
1130
1131 An invalid value causes an error exit (the program is aborted).
1132
1133 =back
1134
1135 =cut
1136  */
1137
1138 int
1139 i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
1140   i_color *ival;
1141   float *tval;
1142   float c1, c2;
1143   i_color val;
1144   int p, x, y, ch;
1145   int xsize    = im->xsize;
1146   int ysize    = im->ysize;
1147   int *cmatch;
1148   int ival_bytes, tval_bytes;
1149
1150   mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
1151
1152   i_clear_error();
1153
1154   if (num <= 0) {
1155     i_push_error(0, "no points supplied to nearest_color filter");
1156     return 0;
1157   }
1158
1159   if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1160     i_push_error(0, "distance measure invalid");
1161     return 0;
1162   }
1163
1164   tval_bytes = sizeof(float)*num*im->channels;
1165   if (tval_bytes / num != sizeof(float) * im->channels) {
1166     i_push_error(0, "integer overflow calculating memory allocation");
1167     return 0;
1168   }
1169   ival_bytes  = sizeof(i_color) * num;
1170   if (ival_bytes / sizeof(i_color) != num) {
1171     i_push_error(0, "integer overflow calculating memory allocation");
1172     return 0;
1173   }
1174   tval   = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1175   ival   = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1176   cmatch = mymalloc( sizeof(int)*num     ); /* checked 17feb2005 tonyc */
1177
1178   for(p = 0; p<num; p++) {
1179     for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1180     cmatch[p] = 0;
1181   }
1182
1183   
1184   for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1185     int   midx    = 0;
1186     float mindist = 0;
1187     float curdist = 0;
1188     
1189     int xd        = x-xo[0];
1190     int yd        = y-yo[0];
1191
1192     switch (dmeasure) {
1193     case 0: /* euclidean */
1194       mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1195       break;
1196     case 1: /* euclidean squared */
1197       mindist = xd*xd + yd*yd; /* euclidean distance */
1198       break;
1199     case 2: /* manhatten distance */
1200       mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1201       break;
1202     default:
1203       i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1204     }
1205     
1206     for(p = 1; p<num; p++) {
1207       xd = x-xo[p];
1208       yd = y-yo[p];
1209       switch (dmeasure) {
1210       case 0: /* euclidean */
1211         curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1212         break;
1213       case 1: /* euclidean squared */
1214         curdist = xd*xd + yd*yd; /* euclidean distance */
1215         break;
1216       case 2: /* euclidean squared */
1217         curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1218         break;
1219       default:
1220         i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1221       }
1222       if (curdist < mindist) {
1223         mindist = curdist;
1224         midx = p;
1225       }
1226     }
1227
1228     cmatch[midx]++;
1229     i_gpix(im, x, y, &val);
1230     c2 = 1.0/(float)(cmatch[midx]);
1231     c1 = 1.0-c2;
1232     
1233     for(ch = 0; ch<im->channels; ch++) 
1234       tval[midx*im->channels + ch] = 
1235         c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1236   
1237   }
1238
1239   for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++)
1240     ival[p].channel[ch] = tval[p*im->channels + ch];
1241
1242   i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1243
1244   return 1;
1245 }
1246
1247 /*
1248 =item i_unsharp_mask(im, stddev, scale)
1249
1250 Perform an usharp mask, which is defined as subtracting the blurred
1251 image from double the original.
1252
1253 =cut
1254 */
1255
1256 void
1257 i_unsharp_mask(i_img *im, double stddev, double scale) {
1258   i_img *copy;
1259   int x, y, ch;
1260
1261   if (scale < 0)
1262     return;
1263   /* it really shouldn't ever be more than 1.0, but maybe ... */
1264   if (scale > 100)
1265     scale = 100;
1266
1267   copy = i_copy(im);
1268   i_gaussian(copy, stddev);
1269   if (im->bits == i_8_bits) {
1270     i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1271     i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1272
1273     for (y = 0; y < im->ysize; ++y) {
1274       i_glin(copy, 0, copy->xsize, y, blur);
1275       i_glin(im, 0, im->xsize, y, out);
1276       for (x = 0; x < im->xsize; ++x) {
1277         for (ch = 0; ch < im->channels; ++ch) {
1278           /*int temp = out[x].channel[ch] + 
1279             scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1280           int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1281           if (temp < 0)
1282             temp = 0;
1283           else if (temp > 255)
1284             temp = 255;
1285           out[x].channel[ch] = temp;
1286         }
1287       }
1288       i_plin(im, 0, im->xsize, y, out);
1289     }
1290
1291     myfree(blur);
1292     myfree(out);
1293   }
1294   else {
1295     i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1296     i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1297
1298     for (y = 0; y < im->ysize; ++y) {
1299       i_glinf(copy, 0, copy->xsize, y, blur);
1300       i_glinf(im, 0, im->xsize, y, out);
1301       for (x = 0; x < im->xsize; ++x) {
1302         for (ch = 0; ch < im->channels; ++ch) {
1303           double temp = out[x].channel[ch] +
1304             scale * (out[x].channel[ch] - blur[x].channel[ch]);
1305           if (temp < 0)
1306             temp = 0;
1307           else if (temp > 1.0)
1308             temp = 1.0;
1309           out[x].channel[ch] = temp;
1310         }
1311       }
1312       i_plinf(im, 0, im->xsize, y, out);
1313     }
1314
1315     myfree(blur);
1316     myfree(out);
1317   }
1318   i_img_destroy(copy);
1319 }
1320
1321 /*
1322 =item i_diff_image(im1, im2, mindist)
1323
1324 Creates a new image that is transparent, except where the pixel in im2
1325 is different from im1, where it is the pixel from im2.
1326
1327 The samples must differ by at least mindiff to be considered different.
1328
1329 =cut
1330 */
1331
1332 i_img *
1333 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1334   i_img *out;
1335   int outchans, diffchans;
1336   int xsize, ysize;
1337
1338   i_clear_error();
1339   if (im1->channels != im2->channels) {
1340     i_push_error(0, "different number of channels");
1341     return NULL;
1342   }
1343
1344   outchans = diffchans = im1->channels;
1345   if (outchans == 1 || outchans == 3)
1346     ++outchans;
1347
1348   xsize = i_min(im1->xsize, im2->xsize);
1349   ysize = i_min(im1->ysize, im2->ysize);
1350
1351   out = i_sametype_chans(im1, xsize, ysize, outchans);
1352   
1353   if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1354     i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1355     i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1356     i_color empty;
1357     int x, y, ch;
1358     int imindist = (int)mindist;
1359
1360     for (ch = 0; ch < MAXCHANNELS; ++ch)
1361       empty.channel[ch] = 0;
1362
1363     for (y = 0; y < ysize; ++y) {
1364       i_glin(im1, 0, xsize, y, line1);
1365       i_glin(im2, 0, xsize, y, line2);
1366       if (outchans != diffchans) {
1367         /* give the output an alpha channel since it doesn't have one */
1368         for (x = 0; x < xsize; ++x)
1369           line2[x].channel[diffchans] = 255;
1370       }
1371       for (x = 0; x < xsize; ++x) {
1372         int diff = 0;
1373         for (ch = 0; ch < diffchans; ++ch) {
1374           if (line1[x].channel[ch] != line2[x].channel[ch]
1375               && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1376             diff = 1;
1377             break;
1378           }
1379         }
1380         if (!diff)
1381           line2[x] = empty;
1382       }
1383       i_plin(out, 0, xsize, y, line2);
1384     }
1385     myfree(line1);
1386     myfree(line2);
1387   }
1388   else {
1389     i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1390     i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1391     i_fcolor empty;
1392     int x, y, ch;
1393     double dist = mindist / 255.0;
1394
1395     for (ch = 0; ch < MAXCHANNELS; ++ch)
1396       empty.channel[ch] = 0;
1397
1398     for (y = 0; y < ysize; ++y) {
1399       i_glinf(im1, 0, xsize, y, line1);
1400       i_glinf(im2, 0, xsize, y, line2);
1401       if (outchans != diffchans) {
1402         /* give the output an alpha channel since it doesn't have one */
1403         for (x = 0; x < xsize; ++x)
1404           line2[x].channel[diffchans] = 1.0;
1405       }
1406       for (x = 0; x < xsize; ++x) {
1407         int diff = 0;
1408         for (ch = 0; ch < diffchans; ++ch) {
1409           if (line1[x].channel[ch] != line2[x].channel[ch]
1410               && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1411             diff = 1;
1412             break;
1413           }
1414         }
1415         if (!diff)
1416           line2[x] = empty;
1417       }
1418       i_plinf(out, 0, xsize, y, line2);
1419     }
1420     myfree(line1);
1421     myfree(line2);
1422   }
1423
1424   return out;
1425 }
1426
1427 struct fount_state;
1428 static double linear_fount_f(double x, double y, struct fount_state *state);
1429 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1430 static double radial_fount_f(double x, double y, struct fount_state *state);
1431 static double square_fount_f(double x, double y, struct fount_state *state);
1432 static double revolution_fount_f(double x, double y, 
1433                                  struct fount_state *state);
1434 static double conical_fount_f(double x, double y, struct fount_state *state);
1435
1436 typedef double (*fount_func)(double, double, struct fount_state *);
1437 static fount_func fount_funcs[] =
1438 {
1439   linear_fount_f,
1440   bilinear_fount_f,
1441   radial_fount_f,
1442   square_fount_f,
1443   revolution_fount_f,
1444   conical_fount_f,
1445 };
1446
1447 static double linear_interp(double pos, i_fountain_seg *seg);
1448 static double sine_interp(double pos, i_fountain_seg *seg);
1449 static double sphereup_interp(double pos, i_fountain_seg *seg);
1450 static double spheredown_interp(double pos, i_fountain_seg *seg);
1451 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1452 static fount_interp fount_interps[] =
1453 {
1454   linear_interp,
1455   linear_interp,
1456   sine_interp,
1457   sphereup_interp,
1458   spheredown_interp,
1459 };
1460
1461 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1462 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1463 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1464 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1465 static fount_cinterp fount_cinterps[] =
1466 {
1467   direct_cinterp,
1468   hue_up_cinterp,
1469   hue_down_cinterp,
1470 };
1471
1472 typedef double (*fount_repeat)(double v);
1473 static double fount_r_none(double v);
1474 static double fount_r_sawtooth(double v);
1475 static double fount_r_triangle(double v);
1476 static double fount_r_saw_both(double v);
1477 static double fount_r_tri_both(double v);
1478 static fount_repeat fount_repeats[] =
1479 {
1480   fount_r_none,
1481   fount_r_sawtooth,
1482   fount_r_triangle,
1483   fount_r_saw_both,
1484   fount_r_tri_both,
1485 };
1486
1487 static int simple_ssample(i_fcolor *out, double x, double y, 
1488                            struct fount_state *state);
1489 static int random_ssample(i_fcolor *out, double x, double y, 
1490                            struct fount_state *state);
1491 static int circle_ssample(i_fcolor *out, double x, double y, 
1492                            struct fount_state *state);
1493 typedef int (*fount_ssample)(i_fcolor *out, double x, double y, 
1494                               struct fount_state *state);
1495 static fount_ssample fount_ssamples[] =
1496 {
1497   NULL,
1498   simple_ssample,
1499   random_ssample,
1500   circle_ssample,
1501 };
1502
1503 static int
1504 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1505
1506 /*
1507   Keep state information used by each type of fountain fill
1508 */
1509 struct fount_state {
1510   /* precalculated for the equation of the line perpendicular to the line AB */
1511   double lA, lB, lC;
1512   double AB;
1513   double sqrtA2B2;
1514   double mult;
1515   double cos;
1516   double sin;
1517   double theta;
1518   int xa, ya;
1519   void *ssample_data;
1520   fount_func ffunc;
1521   fount_repeat rpfunc;
1522   fount_ssample ssfunc;
1523   double parm;
1524   i_fountain_seg *segs;
1525   int count;
1526 };
1527
1528 static void
1529 fount_init_state(struct fount_state *state, double xa, double ya, 
1530                  double xb, double yb, i_fountain_type type, 
1531                  i_fountain_repeat repeat, int combine, int super_sample, 
1532                  double ssample_param, int count, i_fountain_seg *segs);
1533
1534 static void
1535 fount_finish_state(struct fount_state *state);
1536
1537 #define EPSILON (1e-6)
1538
1539 /*
1540 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1541
1542 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1543
1544 I<type> controls how the reference points are used:
1545
1546 =over
1547
1548 =item i_ft_linear
1549
1550 linear, where A is 0 and B is 1.
1551
1552 =item i_ft_bilinear
1553
1554 linear in both directions from A.
1555
1556 =item i_ft_radial
1557
1558 circular, where A is the centre of the fill, and B is a point
1559 on the radius.
1560
1561 =item i_ft_radial_square
1562
1563 where A is the centre of the fill and B is the centre of
1564 one side of the square.
1565
1566 =item i_ft_revolution
1567
1568 where A is the centre of the fill and B defines the 0/1.0
1569 angle of the fill.
1570
1571 =item i_ft_conical
1572
1573 similar to i_ft_revolution, except that the revolution goes in both
1574 directions
1575
1576 =back
1577
1578 I<repeat> can be one of:
1579
1580 =over
1581
1582 =item i_fr_none
1583
1584 values < 0 are treated as zero, values > 1 are treated as 1.
1585
1586 =item i_fr_sawtooth
1587
1588 negative values are treated as 0, positive values are modulo 1.0
1589
1590 =item i_fr_triangle
1591
1592 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1593 mod 1.0), otherwise the same as for sawtooth.
1594
1595 =item i_fr_saw_both
1596
1597 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1598 negative values.
1599
1600 =item i_fr_tri_both
1601
1602 Like i_fr_triangle, except that negative values are handled as their
1603 absolute values.
1604
1605 =back
1606
1607 If combine is non-zero then non-opaque values are combined with the
1608 underlying color.
1609
1610 I<super_sample> controls super sampling, if any.  At some point I'll
1611 probably add a adaptive super-sampler.  Current possible values are:
1612
1613 =over
1614
1615 =item i_fts_none
1616
1617 No super-sampling is done.
1618
1619 =item i_fts_grid
1620
1621 A square grid of points withing the pixel are sampled.
1622
1623 =item i_fts_random
1624
1625 Random points within the pixel are sampled.
1626
1627 =item i_fts_circle
1628
1629 Points on the radius of a circle are sampled.  This produces fairly
1630 good results, but is fairly slow since sin() and cos() are evaluated
1631 for each point.
1632
1633 =back
1634
1635 I<ssample_param> is intended to be roughly the number of points
1636 sampled within the pixel.
1637
1638 I<count> and I<segs> define the segments of the fill.
1639
1640 =cut
1641
1642 */
1643
1644 int
1645 i_fountain(i_img *im, double xa, double ya, double xb, double yb, 
1646            i_fountain_type type, i_fountain_repeat repeat, 
1647            int combine, int super_sample, double ssample_param, 
1648            int count, i_fountain_seg *segs) {
1649   struct fount_state state;
1650   int x, y;
1651   i_fcolor *line = NULL;
1652   i_fcolor *work = NULL;
1653   int line_bytes;
1654   i_fountain_seg *my_segs;
1655   i_fill_combine_f combine_func = NULL;
1656   i_fill_combinef_f combinef_func = NULL;
1657
1658   i_clear_error();
1659
1660   /* i_fountain() allocates floating colors even for 8-bit images,
1661      so we need to do this check */
1662   line_bytes = sizeof(i_fcolor) * im->xsize;
1663   if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1664     i_push_error(0, "integer overflow calculating memory allocation");
1665     return 0;
1666   }
1667   
1668   line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1669
1670   i_get_combine(combine, &combine_func, &combinef_func);
1671   if (combinef_func)
1672     work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1673
1674   fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine, 
1675                    super_sample, ssample_param, count, segs);
1676   my_segs = state.segs;
1677
1678   for (y = 0; y < im->ysize; ++y) {
1679     i_glinf(im, 0, im->xsize, y, line);
1680     for (x = 0; x < im->xsize; ++x) {
1681       i_fcolor c;
1682       int got_one;
1683       if (super_sample == i_fts_none)
1684         got_one = fount_getat(&c, x, y, &state);
1685       else
1686         got_one = state.ssfunc(&c, x, y, &state);
1687       if (got_one) {
1688         if (combine)
1689           work[x] = c;
1690         else 
1691           line[x] = c;
1692       }
1693     }
1694     if (combine)
1695       combinef_func(line, work, im->channels, im->xsize);
1696     i_plinf(im, 0, im->xsize, y, line);
1697   }
1698   fount_finish_state(&state);
1699   if (work) myfree(work);
1700   myfree(line);
1701
1702   return 1;
1703 }
1704
1705 typedef struct {
1706   i_fill_t base;
1707   struct fount_state state;
1708 } i_fill_fountain_t;
1709
1710 static void
1711 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels, 
1712             i_fcolor *data);
1713 static void
1714 fount_fill_destroy(i_fill_t *fill);
1715
1716 static i_fill_fountain_t
1717 fount_fill_proto =
1718   {
1719     {
1720       NULL,
1721       fill_fountf,
1722       fount_fill_destroy
1723     }
1724   };
1725
1726
1727 /*
1728 =item i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1729
1730 =category Fills
1731 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear, 
1732 =synopsis                         i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1733
1734
1735 Creates a new general fill which fills with a fountain fill.
1736
1737 =cut
1738 */
1739
1740 i_fill_t *
1741 i_new_fill_fount(double xa, double ya, double xb, double yb, 
1742                  i_fountain_type type, i_fountain_repeat repeat, 
1743                  int combine, int super_sample, double ssample_param, 
1744                  int count, i_fountain_seg *segs) {
1745   i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1746   
1747   *fill = fount_fill_proto;
1748   if (combine)
1749     i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1750   else {
1751     fill->base.combine = NULL;
1752     fill->base.combinef = NULL;
1753   }
1754   fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine, 
1755                    super_sample, ssample_param, count, segs);
1756
1757   return &fill->base;
1758 }
1759
1760 /*
1761 =back
1762
1763 =head1 INTERNAL FUNCTIONS
1764
1765 =over
1766
1767 =item fount_init_state(...)
1768
1769 Used by both the fountain fill filter and the fountain fill.
1770
1771 =cut
1772 */
1773
1774 static void
1775 fount_init_state(struct fount_state *state, double xa, double ya, 
1776                  double xb, double yb, i_fountain_type type, 
1777                  i_fountain_repeat repeat, int combine, int super_sample, 
1778                  double ssample_param, int count, i_fountain_seg *segs) {
1779   int i, j;
1780   int bytes;
1781   i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1782   /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1783   
1784   memset(state, 0, sizeof(*state));
1785   /* we keep a local copy that we can adjust for speed */
1786   for (i = 0; i < count; ++i) {
1787     i_fountain_seg *seg = my_segs + i;
1788
1789     *seg = segs[i];
1790     if (seg->type < 0 || seg->type >= i_fst_end)
1791       seg->type = i_fst_linear;
1792     if (seg->color < 0 || seg->color >= i_fc_end)
1793       seg->color = i_fc_direct;
1794     if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1795       /* so we don't have to translate to HSV on each request, do it here */
1796       for (j = 0; j < 2; ++j) {
1797         i_rgb_to_hsvf(seg->c+j);
1798       }
1799       if (seg->color == i_fc_hue_up) {
1800         if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1801           seg->c[1].channel[0] += 1.0;
1802       }
1803       else {
1804         if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1805           seg->c[0].channel[0] += 1.0;
1806       }
1807     }
1808     /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n", 
1809            seg->start, seg->middle, seg->end, seg->c[0].channel[0], 
1810            seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1811            seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2], 
1812            seg->c[1].channel[3], seg->type, seg->color);*/
1813            
1814   }
1815
1816   /* initialize each engine */
1817   /* these are so common ... */
1818   state->lA = xb - xa;
1819   state->lB = yb - ya;
1820   state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1821   state->xa = xa;
1822   state->ya = ya;
1823   switch (type) {
1824   default:
1825     type = i_ft_linear; /* make the invalid value valid */
1826   case i_ft_linear:
1827   case i_ft_bilinear:
1828     state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1829     state->mult = 1;
1830     state->mult = 1/linear_fount_f(xb, yb, state);
1831     break;
1832
1833   case i_ft_radial:
1834     state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa) 
1835                              + (double)(yb-ya)*(yb-ya));
1836     break;
1837
1838   case i_ft_radial_square:
1839     state->cos = state->lA / state->AB;
1840     state->sin = state->lB / state->AB;
1841     state->mult = 1.0 / state->AB;
1842     break;
1843
1844   case i_ft_revolution:
1845     state->theta = atan2(yb-ya, xb-xa);
1846     state->mult = 1.0 / (PI * 2);
1847     break;
1848
1849   case i_ft_conical:
1850     state->theta = atan2(yb-ya, xb-xa);
1851     state->mult = 1.0 / PI;
1852     break;
1853   }
1854   state->ffunc = fount_funcs[type];
1855   if (super_sample < 0 
1856       || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1857     super_sample = 0;
1858   }
1859   state->ssample_data = NULL;
1860   switch (super_sample) {
1861   case i_fts_grid:
1862     ssample_param = floor(0.5 + sqrt(ssample_param));
1863     bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1864     if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1865       state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1866     }
1867     else {
1868       super_sample = i_fts_none;
1869     }
1870     break;
1871
1872   case i_fts_random:
1873   case i_fts_circle:
1874     ssample_param = floor(0.5+ssample_param);
1875     bytes = sizeof(i_fcolor) * ssample_param;
1876     if (bytes / sizeof(i_fcolor) == ssample_param) {
1877       state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1878     }
1879     else {
1880       super_sample = i_fts_none;
1881     }
1882     break;
1883   }
1884   state->parm = ssample_param;
1885   state->ssfunc = fount_ssamples[super_sample];
1886   if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1887     repeat = 0;
1888   state->rpfunc = fount_repeats[repeat];
1889   state->segs = my_segs;
1890   state->count = count;
1891 }
1892
1893 static void
1894 fount_finish_state(struct fount_state *state) {
1895   if (state->ssample_data)
1896     myfree(state->ssample_data);
1897   myfree(state->segs);
1898 }
1899
1900
1901 /*
1902 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1903
1904 Evaluates the fountain fill at the given point.
1905
1906 This is called by both the non-super-sampling and super-sampling code.
1907
1908 You might think that it would make sense to sample the fill parameter
1909 instead, and combine those, but this breaks badly.
1910
1911 =cut
1912 */
1913
1914 static int
1915 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1916   double v = (state->rpfunc)((state->ffunc)(x, y, state));
1917   int i;
1918
1919   i = 0;
1920   while (i < state->count 
1921          && (v < state->segs[i].start || v > state->segs[i].end)) {
1922     ++i;
1923   }
1924   if (i < state->count) {
1925     v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1926     (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1927     return 1;
1928   }
1929   else
1930     return 0;
1931 }
1932
1933 /*
1934 =item linear_fount_f(x, y, state)
1935
1936 Calculate the fill parameter for a linear fountain fill.
1937
1938 Uses the point to line distance function, with some precalculation
1939 done in i_fountain().
1940
1941 =cut
1942 */
1943 static double
1944 linear_fount_f(double x, double y, struct fount_state *state) {
1945   return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1946 }
1947
1948 /*
1949 =item bilinear_fount_f(x, y, state)
1950
1951 Calculate the fill parameter for a bi-linear fountain fill.
1952
1953 =cut
1954 */
1955 static double
1956 bilinear_fount_f(double x, double y, struct fount_state *state) {
1957   return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1958 }
1959
1960 /*
1961 =item radial_fount_f(x, y, state)
1962
1963 Calculate the fill parameter for a radial fountain fill.
1964
1965 Simply uses the distance function.
1966
1967 =cut
1968  */
1969 static double
1970 radial_fount_f(double x, double y, struct fount_state *state) {
1971   return sqrt((double)(state->xa-x)*(state->xa-x) 
1972               + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1973 }
1974
1975 /*
1976 =item square_fount_f(x, y, state)
1977
1978 Calculate the fill parameter for a square fountain fill.
1979
1980 Works by rotating the reference co-ordinate around the centre of the
1981 square.
1982
1983 =cut
1984 */
1985 static double
1986 square_fount_f(double x, double y, struct fount_state *state) {
1987   int xc, yc; /* centred on A */
1988   double xt, yt; /* rotated by theta */
1989   xc = x - state->xa;
1990   yc = y - state->ya;
1991   xt = fabs(xc * state->cos + yc * state->sin);
1992   yt = fabs(-xc * state->sin + yc * state->cos);
1993   return (xt > yt ? xt : yt) * state->mult;
1994 }
1995
1996 /*
1997 =item revolution_fount_f(x, y, state)
1998
1999 Calculates the fill parameter for the revolution fountain fill.
2000
2001 =cut
2002 */
2003 static double
2004 revolution_fount_f(double x, double y, struct fount_state *state) {
2005   double angle = atan2(y - state->ya, x - state->xa);
2006   
2007   angle -= state->theta;
2008   if (angle < 0) {
2009     angle = fmod(angle+ PI * 4, PI*2);
2010   }
2011
2012   return angle * state->mult;
2013 }
2014
2015 /*
2016 =item conical_fount_f(x, y, state)
2017
2018 Calculates the fill parameter for the conical fountain fill.
2019
2020 =cut
2021 */
2022 static double
2023 conical_fount_f(double x, double y, struct fount_state *state) {
2024   double angle = atan2(y - state->ya, x - state->xa);
2025   
2026   angle -= state->theta;
2027   if (angle < -PI)
2028     angle += PI * 2;
2029   else if (angle > PI) 
2030     angle -= PI * 2;
2031
2032   return fabs(angle) * state->mult;
2033 }
2034
2035 /*
2036 =item linear_interp(pos, seg)
2037
2038 Calculates linear interpolation on the fill parameter.  Breaks the
2039 segment into 2 regions based in the I<middle> value.
2040
2041 =cut
2042 */
2043 static double
2044 linear_interp(double pos, i_fountain_seg *seg) {
2045   if (pos < seg->middle) {
2046     double len = seg->middle - seg->start;
2047     if (len < EPSILON)
2048       return 0.0;
2049     else
2050       return (pos - seg->start) / len / 2;
2051   }
2052   else {
2053     double len = seg->end - seg->middle;
2054     if (len < EPSILON)
2055       return 1.0;
2056     else
2057       return 0.5 + (pos - seg->middle) / len / 2;
2058   }
2059 }
2060
2061 /*
2062 =item sine_interp(pos, seg)
2063
2064 Calculates sine function interpolation on the fill parameter.
2065
2066 =cut
2067 */
2068 static double
2069 sine_interp(double pos, i_fountain_seg *seg) {
2070   /* I wonder if there's a simple way to smooth the transition for this */
2071   double work = linear_interp(pos, seg);
2072
2073   return (1-cos(work * PI))/2;
2074 }
2075
2076 /*
2077 =item sphereup_interp(pos, seg)
2078
2079 Calculates spherical interpolation on the fill parameter, with the cusp 
2080 at the low-end.
2081
2082 =cut
2083 */
2084 static double
2085 sphereup_interp(double pos, i_fountain_seg *seg) {
2086   double work = linear_interp(pos, seg);
2087
2088   return sqrt(1.0 - (1-work) * (1-work));
2089 }
2090
2091 /*
2092 =item spheredown_interp(pos, seg)
2093
2094 Calculates spherical interpolation on the fill parameter, with the cusp 
2095 at the high-end.
2096
2097 =cut
2098 */
2099 static double
2100 spheredown_interp(double pos, i_fountain_seg *seg) {
2101   double work = linear_interp(pos, seg);
2102
2103   return 1-sqrt(1.0 - work * work);
2104 }
2105
2106 /*
2107 =item direct_cinterp(out, pos, seg)
2108
2109 Calculates the fountain color based on direct scaling of the channels
2110 of the color channels.
2111
2112 =cut
2113 */
2114 static void
2115 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2116   int ch;
2117   for (ch = 0; ch < MAXCHANNELS; ++ch) {
2118     out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) 
2119       + seg->c[1].channel[ch] * pos;
2120   }
2121 }
2122
2123 /*
2124 =item hue_up_cinterp(put, pos, seg)
2125
2126 Calculates the fountain color based on scaling a HSV value.  The hue
2127 increases as the fill parameter increases.
2128
2129 =cut
2130 */
2131 static void
2132 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2133   int ch;
2134   for (ch = 0; ch < MAXCHANNELS; ++ch) {
2135     out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) 
2136       + seg->c[1].channel[ch] * pos;
2137   }
2138   i_hsv_to_rgbf(out);
2139 }
2140
2141 /*
2142 =item hue_down_cinterp(put, pos, seg)
2143
2144 Calculates the fountain color based on scaling a HSV value.  The hue
2145 decreases as the fill parameter increases.
2146
2147 =cut
2148 */
2149 static void
2150 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2151   int ch;
2152   for (ch = 0; ch < MAXCHANNELS; ++ch) {
2153     out->channel[ch] = seg->c[0].channel[ch] * (1 - pos) 
2154       + seg->c[1].channel[ch] * pos;
2155   }
2156   i_hsv_to_rgbf(out);
2157 }
2158
2159 /*
2160 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2161
2162 Simple grid-based super-sampling.
2163
2164 =cut
2165 */
2166 static int
2167 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2168   i_fcolor *work = state->ssample_data;
2169   int dx, dy;
2170   int grid = state->parm;
2171   double base = -0.5 + 0.5 / grid;
2172   double step = 1.0 / grid;
2173   int ch, i;
2174   int samp_count = 0;
2175
2176   for (dx = 0; dx < grid; ++dx) {
2177     for (dy = 0; dy < grid; ++dy) {
2178       if (fount_getat(work+samp_count, x + base + step * dx, 
2179                       y + base + step * dy, state)) {
2180         ++samp_count;
2181       }
2182     }
2183   }
2184   for (ch = 0; ch < MAXCHANNELS; ++ch) {
2185     out->channel[ch] = 0;
2186     for (i = 0; i < samp_count; ++i) {
2187       out->channel[ch] += work[i].channel[ch];
2188     }
2189     /* we divide by 4 rather than samp_count since if there's only one valid
2190        sample it should be mostly transparent */
2191     out->channel[ch] /= grid * grid;
2192   }
2193   return samp_count;
2194 }
2195
2196 /*
2197 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2198
2199 Random super-sampling.
2200
2201 =cut
2202 */
2203 static int
2204 random_ssample(i_fcolor *out, double x, double y, 
2205                struct fount_state *state) {
2206   i_fcolor *work = state->ssample_data;
2207   int i, ch;
2208   int maxsamples = state->parm;
2209   double rand_scale = 1.0 / RAND_MAX;
2210   int samp_count = 0;
2211   for (i = 0; i < maxsamples; ++i) {
2212     if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale, 
2213                     y - 0.5 + rand() * rand_scale, state)) {
2214       ++samp_count;
2215     }
2216   }
2217   for (ch = 0; ch < MAXCHANNELS; ++ch) {
2218     out->channel[ch] = 0;
2219     for (i = 0; i < samp_count; ++i) {
2220       out->channel[ch] += work[i].channel[ch];
2221     }
2222     /* we divide by maxsamples rather than samp_count since if there's
2223        only one valid sample it should be mostly transparent */
2224     out->channel[ch] /= maxsamples;
2225   }
2226   return samp_count;
2227 }
2228
2229 /*
2230 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2231
2232 Super-sampling around the circumference of a circle.
2233
2234 I considered saving the sin()/cos() values and transforming step-size
2235 around the circle, but that's inaccurate, though it may not matter
2236 much.
2237
2238 =cut
2239  */
2240 static int
2241 circle_ssample(i_fcolor *out, double x, double y, 
2242                struct fount_state *state) {
2243   i_fcolor *work = state->ssample_data;
2244   int i, ch;
2245   int maxsamples = state->parm;
2246   double angle = 2 * PI / maxsamples;
2247   double radius = 0.3; /* semi-random */
2248   int samp_count = 0;
2249   for (i = 0; i < maxsamples; ++i) {
2250     if (fount_getat(work+samp_count, x + radius * cos(angle * i), 
2251                     y + radius * sin(angle * i), state)) {
2252       ++samp_count;
2253     }
2254   }
2255   for (ch = 0; ch < MAXCHANNELS; ++ch) {
2256     out->channel[ch] = 0;
2257     for (i = 0; i < samp_count; ++i) {
2258       out->channel[ch] += work[i].channel[ch];
2259     }
2260     /* we divide by maxsamples rather than samp_count since if there's
2261        only one valid sample it should be mostly transparent */
2262     out->channel[ch] /= maxsamples;
2263   }
2264   return samp_count;
2265 }
2266
2267 /*
2268 =item fount_r_none(v)
2269
2270 Implements no repeats.  Simply clamps the fill value.
2271
2272 =cut
2273 */
2274 static double
2275 fount_r_none(double v) {
2276   return v < 0 ? 0 : v > 1 ? 1 : v;
2277 }
2278
2279 /*
2280 =item fount_r_sawtooth(v)
2281
2282 Implements sawtooth repeats.  Clamps negative values and uses fmod()
2283 on others.
2284
2285 =cut
2286 */
2287 static double
2288 fount_r_sawtooth(double v) {
2289   return v < 0 ? 0 : fmod(v, 1.0);
2290 }
2291
2292 /*
2293 =item fount_r_triangle(v)
2294
2295 Implements triangle repeats.  Clamps negative values, uses fmod to get
2296 a range 0 through 2 and then adjusts values > 1.
2297
2298 =cut
2299 */
2300 static double
2301 fount_r_triangle(double v) {
2302   if (v < 0)
2303     return 0;
2304   else {
2305     v = fmod(v, 2.0);
2306     return v > 1.0 ? 2.0 - v : v;
2307   }
2308 }
2309
2310 /*
2311 =item fount_r_saw_both(v)
2312
2313 Implements sawtooth repeats in the both postive and negative directions.
2314
2315 Adjusts the value to be postive and then just uses fmod().
2316
2317 =cut
2318 */
2319 static double
2320 fount_r_saw_both(double v) {
2321   if (v < 0)
2322     v += 1+(int)(-v);
2323   return fmod(v, 1.0);
2324 }
2325
2326 /*
2327 =item fount_r_tri_both(v)
2328
2329 Implements triangle repeats in the both postive and negative directions.
2330
2331 Uses fmod on the absolute value, and then adjusts values > 1.
2332
2333 =cut
2334 */
2335 static double
2336 fount_r_tri_both(double v) {
2337   v = fmod(fabs(v), 2.0);
2338   return v > 1.0 ? 2.0 - v : v;
2339 }
2340
2341 /*
2342 =item fill_fountf(fill, x, y, width, channels, data)
2343
2344 The fill function for fountain fills.
2345
2346 =cut
2347 */
2348 static void
2349 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels, 
2350             i_fcolor *data) {
2351   i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2352   
2353   while (width--) {
2354     i_fcolor c;
2355     int got_one;
2356     
2357     if (f->state.ssfunc)
2358       got_one = f->state.ssfunc(&c, x, y, &f->state);
2359     else
2360       got_one = fount_getat(&c, x, y, &f->state);
2361     
2362     *data++ = c;
2363     
2364     ++x;
2365   }
2366 }
2367
2368 /*
2369 =item fount_fill_destroy(fill)
2370
2371 =cut
2372 */
2373 static void
2374 fount_fill_destroy(i_fill_t *fill) {
2375   i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2376   fount_finish_state(&f->state);
2377 }
2378
2379 /*
2380 =back
2381
2382 =head1 AUTHOR
2383
2384 Arnar M. Hrafnkelsson <addi@umich.edu>
2385
2386 Tony Cook <tony@develop-help.com> (i_fountain())
2387
2388 =head1 SEE ALSO
2389
2390 Imager(3)
2391
2392 =cut
2393 */