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