10 filters.c - implements filters that operate on images
17 i_unsharp_mask(im, 2.0, 1.0);
22 filters.c implements basic filters for Imager. These filters
23 should be accessible from the filter interface as defined in
26 =head1 FUNCTION REFERENCE
28 Some of these functions are internal.
41 Clamps the input value between 0 and 255. (internal)
51 if (in>255) { return 255; }
52 else if (in>0) return in;
59 =item i_contrast(im, intensity)
61 Scales the pixel values by the amount specified.
64 intensity - scalefactor
70 i_contrast(i_img *im, float intensity) {
73 unsigned int new_color;
76 mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
78 if(intensity < 0) return;
80 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
81 i_gpix(im, x, y, &rcolor);
83 for(ch = 0; ch < im->channels; ch++) {
84 new_color = (unsigned int) rcolor.channel[ch];
85 new_color *= intensity;
90 rcolor.channel[ch] = (unsigned char) new_color;
92 i_ppix(im, x, y, &rcolor);
98 =item i_hardinvert(im)
100 Inverts the pixel values of the input image.
108 i_hardinvert(i_img *im) {
114 mm_log((1,"i_hardinvert(im %p)\n", im));
116 for(y = 0; y < im->ysize; y++) {
117 for(x = 0; x < im->xsize; x++) {
118 i_gpix(im, x, y, &rcolor);
120 for(ch = 0; ch < im->channels; ch++) {
121 rcolor.channel[ch] = 255 - rcolor.channel[ch];
124 i_ppix(im, x, y, &rcolor);
132 =item i_noise(im, amount, type)
134 Inverts the pixel values by the amount specified.
137 amount - deviation in pixel values
138 type - noise individual for each channel if true
144 /* random() is non-ASCII, even if it is better than rand() */
145 #define random() rand()
149 i_noise(i_img *im, float amount, unsigned char type) {
153 float damount = amount * 2;
157 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
159 if(amount < 0) return;
161 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
162 i_gpix(im, x, y, &rcolor);
165 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
168 for(ch = 0; ch < im->channels; ch++) {
169 new_color = (int) rcolor.channel[ch];
172 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
174 new_color += color_inc;
180 if(new_color > 255) {
184 rcolor.channel[ch] = (unsigned char) new_color;
187 i_ppix(im, x, y, &rcolor);
193 =item i_noise(im, amount, type)
195 Inverts the pixel values by the amount specified.
198 amount - deviation in pixel values
199 type - noise individual for each channel if true
206 =item i_applyimage(im, add_im, mode)
208 Apply's an image to another image
211 add_im - image that is applied to target
212 mode - what method is used in applying:
232 void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
236 mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
238 mx = (add_im->xsize <= im->xsize) ? add_im->xsize : add_im->xsize;
239 my = (add_im->ysize <= im->ysize) ? add_im->ysize : add_im->ysize;
241 for(x = 0; x < mx; x++) {
242 for(y = 0; y < my; y++) {
249 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
251 Makes a bumpmap on image im using the bump image as the elevation map.
254 bump - image that contains the elevation info
255 channel - to take the elevation information from
256 light_x - x coordinate of light source
257 light_y - y coordinate of light source
258 st - length of shadow
264 i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
267 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
272 unsigned char px1, px2, py1, py2;
276 mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light_x %d, light_y %d, st %d)\n",
277 im, bump, channel, light_x, light_y, st));
280 if(channel >= bump->channels) {
281 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
285 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
286 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
288 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
290 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
291 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
293 aL = sqrt((aX * aX) + (aY * aY));
295 for(y = 1; y < my - 1; y++) {
296 for(x = 1; x < mx - 1; x++) {
297 i_gpix(bump, x + st, y, &x1_color);
298 i_gpix(bump, x, y + st, &y1_color);
299 i_gpix(bump, x - st, y, &x2_color);
300 i_gpix(bump, x, y - st, &y2_color);
302 i_gpix(im, x, y, &dst_color);
304 px1 = x1_color.channel[channel];
305 py1 = y1_color.channel[channel];
306 px2 = x2_color.channel[channel];
307 py2 = y2_color.channel[channel];
315 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
317 tX = abs(x - light_x) / aL;
318 tY = abs(y - light_y) / aL;
320 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
325 for(ch = 0; ch < im->channels; ch++)
326 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
328 i_ppix(&new_im, x, y, &dst_color);
332 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
334 i_img_exorcise(&new_im);
347 dotp(fvec *a, fvec *b) {
348 return a->x*b->x+a->y*b->y+a->z*b->z;
354 double d = sqrt(dotp(a,a));
368 I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
370 Here, the variables are:
372 * Ia - ambient colour
373 * Ip - intensity of the point light source
374 * cd - diffuse coefficient
375 * Scol - surface colour
376 * cs - specular coefficient
377 * n - objects shinyness
379 * L - lighting vector
380 * R - reflection vector
383 static void fvec_dump(fvec *x) {
384 printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
388 /* XXX: Should these return a code for success? */
394 =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
396 Makes a bumpmap on image im using the bump image as the elevation map.
399 bump - image that contains the elevation info
400 channel - to take the elevation information from
401 tx - shift in x direction of where to start applying bumpmap
402 ty - shift in y direction of where to start applying bumpmap
403 Lx - x position/direction of light
404 Ly - y position/direction of light
405 Lz - z position/direction of light
407 cd - diffuse coefficient
408 cs - specular coefficient
409 n - surface shinyness
414 if z<0 then the L is taken to be the direction the light is shining in. Otherwise
415 the L is taken to be the position of the Light, Relative to the image.
422 i_bumpmap_complex(i_img *im,
442 float cdc[MAXCHANNELS];
443 float csc[MAXCHANNELS];
445 i_color x1_color, y1_color, x2_color, y2_color;
447 i_color Scol; /* Surface colour */
449 fvec L; /* Light vector */
450 fvec N; /* surface normal */
451 fvec R; /* Reflection vector */
452 fvec V; /* Vision vector */
454 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",
455 im, bump, channel, tx, ty, Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
457 if (channel >= bump->channels) {
458 mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
462 for(ch=0; ch<im->channels; ch++) {
463 cdc[ch] = (float)Il->channel[ch]*cd/255.f;
464 csc[ch] = (float)Is->channel[ch]*cs/255.f;
476 if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
481 } else { /* Light is the position of the light source */
489 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
491 for(y = 0; y < im->ysize; y++) {
492 for(x = 0; x < im->xsize; x++) {
494 double dx = 0, dy = 0;
496 /* Calculate surface normal */
497 if (mx<x && x<Mx && my<y && y<My) {
498 i_gpix(bump, x + 1, y, &x1_color);
499 i_gpix(bump, x - 1, y, &x2_color);
500 i_gpix(bump, x, y + 1, &y1_color);
501 i_gpix(bump, x, y - 1, &y2_color);
502 dx = x2_color.channel[channel] - x1_color.channel[channel];
503 dy = y2_color.channel[channel] - y1_color.channel[channel];
513 /* Calculate Light vector if needed */
522 R.x = -L.x + 2*dp1*N.x;
523 R.y = -L.y + 2*dp1*N.y;
524 R.z = -L.z + 2*dp1*N.z;
528 dp1 = dp1<0 ?0 : dp1;
529 dp2 = pow(dp2<0 ?0 : dp2,n);
531 i_gpix(im, x, y, &Scol);
533 for(ch = 0; ch < im->channels; ch++)
535 saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
537 i_ppix(&new_im, x, y, &Scol);
541 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
542 i_img_exorcise(&new_im);
547 =item i_postlevels(im, levels)
549 Quantizes Images to fewer levels.
552 levels - number of levels
558 i_postlevels(i_img *im, int levels) {
566 rv = (int) ((float)(256 / levels));
569 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
570 i_gpix(im, x, y, &rcolor);
572 for(ch = 0; ch < im->channels; ch++) {
573 pv = (((float)rcolor.channel[ch] / 255)) * av;
574 pv = (int) ((int)pv * rv);
577 else if(pv > 255) pv = 255;
579 rcolor.channel[ch] = (unsigned char) pv;
581 i_ppix(im, x, y, &rcolor);
587 =item i_mosaic(im, size)
589 Makes an image looks like a mosaic with tilesize of size
598 i_mosaic(i_img *im, int size) {
606 sqrsize = size * size;
608 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
609 for(z = 0; z < 256; z++) col[z] = 0;
611 for(lx = 0; lx < size; lx++) {
612 for(ly = 0; ly < size; ly++) {
613 i_gpix(im, (x + lx), (y + ly), &rcolor);
615 for(ch = 0; ch < im->channels; ch++) {
616 col[ch] += rcolor.channel[ch];
621 for(ch = 0; ch < im->channels; ch++)
622 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
625 for(lx = 0; lx < size; lx++)
626 for(ly = 0; ly < size; ly++)
627 i_ppix(im, (x + lx), (y + ly), &rcolor);
634 =item i_watermark(im, wmark, tx, ty, pixdiff)
636 Applies a watermark to the target image
639 wmark - watermark image
640 tx - x coordinate of where watermark should be applied
641 ty - y coordinate of where watermark should be applied
642 pixdiff - the magnitude of the watermark, controls how visible it is
648 i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
652 int mx = wmark->xsize;
653 int my = wmark->ysize;
655 for(vx=0;vx<mx;vx++) for(vy=0;vy<my;vy++) {
657 i_gpix(im, tx+vx, ty+vy,&val );
658 i_gpix(wmark, vx, vy, &wval);
660 for(ch=0;ch<im->channels;ch++)
661 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
663 i_ppix(im,tx+vx,ty+vy,&val);
669 =item i_autolevels(im, lsat, usat, skew)
671 Scales and translates each color such that it fills the range completely.
672 Skew is not implemented yet - purpose is to control the color skew that can
673 occur when changing the contrast.
676 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
677 usat - fraction of pixels that will be truncated at the higher end of the spectrum
684 i_autolevels(i_img *im, float lsat, float usat, float skew) {
686 int i, x, y, rhist[256], ghist[256], bhist[256];
687 int rsum, rmin, rmax;
688 int gsum, gmin, gmax;
689 int bsum, bmin, bmax;
690 int rcl, rcu, gcl, gcu, bcl, bcu;
692 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
695 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
696 /* create histogram for each channel */
697 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
698 i_gpix(im, x, y, &val);
699 rhist[val.channel[0]]++;
700 ghist[val.channel[1]]++;
701 bhist[val.channel[2]]++;
710 rmin = gmin = bmin = 0;
711 rmax = gmax = bmax = 255;
713 rcu = rcl = gcu = gcl = bcu = bcl = 0;
715 for(i=0; i<256; i++) {
716 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
717 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
719 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
720 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
722 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
723 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
726 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
727 i_gpix(im, x, y, &val);
728 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
729 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
730 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
731 i_ppix(im, x, y, &val);
738 Pseudo noise utility function used to generate perlin noise. (internal)
748 Noise(int x, int y) {
751 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
755 =item SmoothedNoise1(x,y)
757 Pseudo noise utility function used to generate perlin noise. (internal)
767 SmoothedNoise1(float x, float y) {
768 float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
769 float sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
770 float center = Noise(x, y) / 4;
771 return corners + sides + center;
776 =item G_Interpolate(a, b, x)
778 Utility function used to generate perlin noise. (internal)
784 float C_Interpolate(float a, float b, float x) {
785 /* float ft = x * 3.1415927; */
787 float f = (1 - cos(ft)) * .5;
788 return a*(1-f) + b*f;
793 =item InterpolatedNoise(x, y)
795 Utility function used to generate perlin noise. (internal)
802 InterpolatedNoise(float x, float y) {
805 float fractional_X = x - integer_X;
807 float fractional_Y = y - integer_Y;
809 float v1 = SmoothedNoise1(integer_X, integer_Y);
810 float v2 = SmoothedNoise1(integer_X + 1, integer_Y);
811 float v3 = SmoothedNoise1(integer_X, integer_Y + 1);
812 float v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
814 float i1 = C_Interpolate(v1 , v2 , fractional_X);
815 float i2 = C_Interpolate(v3 , v4 , fractional_X);
817 return C_Interpolate(i1 , i2 , fractional_Y);
823 =item PerlinNoise_2D(x, y)
825 Utility function used to generate perlin noise. (internal)
832 PerlinNoise_2D(float x, float y) {
836 int Number_Of_Octaves=6;
837 int n = Number_Of_Octaves - 1;
842 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
850 =item i_radnoise(im, xo, yo, rscale, ascale)
852 Perlin-like radial noise.
855 xo - x coordinate of center
856 yo - y coordinate of center
857 rscale - radial scale
858 ascale - angular scale
864 i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
871 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
872 xc = (float)x-xo+0.5;
873 yc = (float)y-yo+0.5;
874 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
875 a = (PI+atan2(yc,xc))*ascale;
876 v = saturate(128+100*(PerlinNoise_2D(a,r)));
877 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
878 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
879 i_ppix(im, x, y, &val);
885 =item i_turbnoise(im, xo, yo, scale)
887 Perlin-like 2d noise noise.
890 xo - x coordinate translation
891 yo - y coordinate translation
892 scale - scale of noise
898 i_turbnoise(i_img *im, float xo, float yo, float scale) {
903 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
904 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
905 v = saturate(120*(1.0+sin(xo+(float)x/scale+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))));
906 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
907 i_ppix(im, x, y, &val);
914 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
916 Gradient generating function.
919 num - number of points given
920 xo - array of x coordinates
921 yo - array of y coordinates
922 ival - array of i_color objects
923 dmeasure - distance measure to be used.
925 1 = Euclidean squared
926 2 = Manhattan distance
933 i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
937 int channels = im->channels;
938 int xsize = im->xsize;
939 int ysize = im->ysize;
944 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
946 for(p = 0; p<num; p++) {
947 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
951 /* on the systems I have sizeof(float) == sizeof(int) and thus
952 this would be same size as the arrays xo and yo point at, but this
953 may not be true for other systems
955 since the arrays here are caller controlled, I assume that on
956 overflow is a programming error rather than an end-user error, so
957 calling exit() is justified.
959 bytes = sizeof(float) * num;
960 if (bytes / num != sizeof(float)) {
961 fprintf(stderr, "integer overflow calculating memory allocation");
964 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
966 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
969 for(p = 0; p<num; p++) {
973 case 0: /* euclidean */
974 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
976 case 1: /* euclidean squared */
977 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
979 case 2: /* euclidean squared */
980 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
983 m_fatal(3,"i_gradgen: Unknown distance measure\n");
988 csd = 1/((num-1)*cs);
990 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
992 for(ch = 0; ch<channels; ch++) {
994 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
995 val.channel[ch] = saturate(tres);
997 i_ppix(im, x, y, &val);
1004 i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
1007 int xsize = im->xsize;
1008 int ysize = im->ysize;
1010 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
1012 for(p = 0; p<num; p++) {
1013 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
1017 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1026 case 0: /* euclidean */
1027 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1029 case 1: /* euclidean squared */
1030 mindist = xd*xd + yd*yd; /* euclidean distance */
1032 case 2: /* euclidean squared */
1033 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1036 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1039 for(p = 1; p<num; p++) {
1043 case 0: /* euclidean */
1044 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1046 case 1: /* euclidean squared */
1047 curdist = xd*xd + yd*yd; /* euclidean distance */
1049 case 2: /* euclidean squared */
1050 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1053 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1055 if (curdist < mindist) {
1060 i_ppix(im, x, y, &ival[midx]);
1065 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1067 This wasn't document - quoth Addi:
1069 An arty type of filter
1071 FIXME: check IRC logs for actual text.
1079 i_img *im - image to render on.
1083 int num - number of points/colors in xo, yo, oval
1087 int *xo - array of I<num> x positions
1091 int *yo - array of I<num> y positions
1095 i_color *oval - array of I<num> colors
1097 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1098 color something like oval[i], at least closer to that color than other
1103 int dmeasure - how we measure the distance from some point P(x,y) to
1112 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1116 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1120 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1124 An invalid value causes an error exit (the program is aborted).
1131 i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
1137 int xsize = im->xsize;
1138 int ysize = im->ysize;
1141 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));
1143 tval = mymalloc( sizeof(float)*num*im->channels );
1144 ival = mymalloc( sizeof(i_color)*num );
1145 cmatch = mymalloc( sizeof(int)*num );
1147 for(p = 0; p<num; p++) {
1148 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1153 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1162 case 0: /* euclidean */
1163 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1165 case 1: /* euclidean squared */
1166 mindist = xd*xd + yd*yd; /* euclidean distance */
1168 case 2: /* euclidean squared */
1169 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1172 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1175 for(p = 1; p<num; p++) {
1179 case 0: /* euclidean */
1180 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1182 case 1: /* euclidean squared */
1183 curdist = xd*xd + yd*yd; /* euclidean distance */
1185 case 2: /* euclidean squared */
1186 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1189 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1191 if (curdist < mindist) {
1198 i_gpix(im, x, y, &val);
1199 c2 = 1.0/(float)(cmatch[midx]);
1202 for(ch = 0; ch<im->channels; ch++)
1203 tval[midx*im->channels + ch] =
1204 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1208 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++)
1209 ival[p].channel[ch] = tval[p*im->channels + ch];
1211 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1215 =item i_unsharp_mask(im, stddev, scale)
1217 Perform an usharp mask, which is defined as subtracting the blurred
1218 image from double the original.
1222 void i_unsharp_mask(i_img *im, double stddev, double scale) {
1228 /* it really shouldn't ever be more than 1.0, but maybe ... */
1233 i_gaussian(©, stddev);
1234 if (im->bits == i_8_bits) {
1235 i_color *blur = mymalloc(im->xsize * sizeof(i_color) * 2);
1236 i_color *out = blur + im->xsize;
1238 for (y = 0; y < im->ysize; ++y) {
1239 i_glin(©, 0, copy.xsize, y, blur);
1240 i_glin(im, 0, im->xsize, y, out);
1241 for (x = 0; x < im->xsize; ++x) {
1242 for (ch = 0; ch < im->channels; ++ch) {
1243 /*int temp = out[x].channel[ch] +
1244 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1245 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1248 else if (temp > 255)
1250 out[x].channel[ch] = temp;
1253 i_plin(im, 0, im->xsize, y, out);
1259 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor) * 2);
1260 i_fcolor *out = blur + im->xsize;
1262 for (y = 0; y < im->ysize; ++y) {
1263 i_glinf(©, 0, copy.xsize, y, blur);
1264 i_glinf(im, 0, im->xsize, y, out);
1265 for (x = 0; x < im->xsize; ++x) {
1266 for (ch = 0; ch < im->channels; ++ch) {
1267 double temp = out[x].channel[ch] +
1268 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1271 else if (temp > 1.0)
1273 out[x].channel[ch] = temp;
1276 i_plinf(im, 0, im->xsize, y, out);
1281 i_img_exorcise(©);
1285 =item i_diff_image(im1, im2, mindiff)
1287 Creates a new image that is transparent, except where the pixel in im2
1288 is different from im1, where it is the pixel from im2.
1290 The samples must differ by at least mindiff to be considered different.
1296 i_diff_image(i_img *im1, i_img *im2, int mindiff) {
1298 int outchans, diffchans;
1302 if (im1->channels != im2->channels) {
1303 i_push_error(0, "different number of channels");
1307 outchans = diffchans = im1->channels;
1308 if (outchans == 1 || outchans == 3)
1311 xsize = i_min(im1->xsize, im2->xsize);
1312 ysize = i_min(im1->ysize, im2->ysize);
1314 out = i_sametype_chans(im1, xsize, ysize, outchans);
1316 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1317 i_color *line1 = mymalloc(2 * xsize * sizeof(*line1));
1318 i_color *line2 = line1 + xsize;
1322 for (ch = 0; ch < MAXCHANNELS; ++ch)
1323 empty.channel[ch] = 0;
1325 for (y = 0; y < ysize; ++y) {
1326 i_glin(im1, 0, xsize, y, line1);
1327 i_glin(im2, 0, xsize, y, line2);
1328 if (outchans != diffchans) {
1329 /* give the output an alpha channel since it doesn't have one */
1330 for (x = 0; x < xsize; ++x)
1331 line2[x].channel[diffchans] = 255;
1333 for (x = 0; x < xsize; ++x) {
1335 for (ch = 0; ch < diffchans; ++ch) {
1336 if (line1[x].channel[ch] != line2[x].channel[ch]
1337 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > mindiff) {
1345 i_plin(out, 0, xsize, y, line2);
1350 i_fcolor *line1 = mymalloc(2 * xsize * sizeof(*line1));
1351 i_fcolor *line2 = line1 + xsize;
1354 double dist = mindiff / 255;
1356 for (ch = 0; ch < MAXCHANNELS; ++ch)
1357 empty.channel[ch] = 0;
1359 for (y = 0; y < ysize; ++y) {
1360 i_glinf(im1, 0, xsize, y, line1);
1361 i_glinf(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] = 1.0;
1367 for (x = 0; x < xsize; ++x) {
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]) > dist) {
1379 i_plinf(out, 0, xsize, y, line2);
1388 static double linear_fount_f(double x, double y, struct fount_state *state);
1389 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1390 static double radial_fount_f(double x, double y, struct fount_state *state);
1391 static double square_fount_f(double x, double y, struct fount_state *state);
1392 static double revolution_fount_f(double x, double y,
1393 struct fount_state *state);
1394 static double conical_fount_f(double x, double y, struct fount_state *state);
1396 typedef double (*fount_func)(double, double, struct fount_state *);
1397 static fount_func fount_funcs[] =
1407 static double linear_interp(double pos, i_fountain_seg *seg);
1408 static double sine_interp(double pos, i_fountain_seg *seg);
1409 static double sphereup_interp(double pos, i_fountain_seg *seg);
1410 static double spheredown_interp(double pos, i_fountain_seg *seg);
1411 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1412 static fount_interp fount_interps[] =
1421 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1422 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1423 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1424 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1425 static fount_cinterp fount_cinterps[] =
1432 typedef double (*fount_repeat)(double v);
1433 static double fount_r_none(double v);
1434 static double fount_r_sawtooth(double v);
1435 static double fount_r_triangle(double v);
1436 static double fount_r_saw_both(double v);
1437 static double fount_r_tri_both(double v);
1438 static fount_repeat fount_repeats[] =
1447 static int simple_ssample(i_fcolor *out, double x, double y,
1448 struct fount_state *state);
1449 static int random_ssample(i_fcolor *out, double x, double y,
1450 struct fount_state *state);
1451 static int circle_ssample(i_fcolor *out, double x, double y,
1452 struct fount_state *state);
1453 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1454 struct fount_state *state);
1455 static fount_ssample fount_ssamples[] =
1464 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1467 Keep state information used by each type of fountain fill
1469 struct fount_state {
1470 /* precalculated for the equation of the line perpendicular to the line AB */
1481 fount_repeat rpfunc;
1482 fount_ssample ssfunc;
1484 i_fountain_seg *segs;
1489 fount_init_state(struct fount_state *state, double xa, double ya,
1490 double xb, double yb, i_fountain_type type,
1491 i_fountain_repeat repeat, int combine, int super_sample,
1492 double ssample_param, int count, i_fountain_seg *segs);
1495 fount_finish_state(struct fount_state *state);
1497 #define EPSILON (1e-6)
1500 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1502 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1504 I<type> controls how the reference points are used:
1510 linear, where A is 0 and B is 1.
1514 linear in both directions from A.
1518 circular, where A is the centre of the fill, and B is a point
1521 =item i_ft_radial_square
1523 where A is the centre of the fill and B is the centre of
1524 one side of the square.
1526 =item i_ft_revolution
1528 where A is the centre of the fill and B defines the 0/1.0
1533 similar to i_ft_revolution, except that the revolution goes in both
1538 I<repeat> can be one of:
1544 values < 0 are treated as zero, values > 1 are treated as 1.
1548 negative values are treated as 0, positive values are modulo 1.0
1552 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1553 mod 1.0), otherwise the same as for sawtooth.
1557 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1562 Like i_fr_triangle, except that negative values are handled as their
1567 If combine is non-zero then non-opaque values are combined with the
1570 I<super_sample> controls super sampling, if any. At some point I'll
1571 probably add a adaptive super-sampler. Current possible values are:
1577 No super-sampling is done.
1581 A square grid of points withing the pixel are sampled.
1585 Random points within the pixel are sampled.
1589 Points on the radius of a circle are sampled. This produces fairly
1590 good results, but is fairly slow since sin() and cos() are evaluated
1595 I<ssample_param> is intended to be roughly the number of points
1596 sampled within the pixel.
1598 I<count> and I<segs> define the segments of the fill.
1605 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1606 i_fountain_type type, i_fountain_repeat repeat,
1607 int combine, int super_sample, double ssample_param,
1608 int count, i_fountain_seg *segs) {
1609 struct fount_state state;
1611 i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize);
1612 i_fcolor *work = NULL;
1614 i_fountain_seg *my_segs;
1615 i_fill_combine_f combine_func = NULL;
1616 i_fill_combinef_f combinef_func = NULL;
1618 i_get_combine(combine, &combine_func, &combinef_func);
1620 work = mymalloc(sizeof(i_fcolor) * im->xsize);
1622 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1623 super_sample, ssample_param, count, segs);
1624 my_segs = state.segs;
1626 for (y = 0; y < im->ysize; ++y) {
1627 i_glinf(im, 0, im->xsize, y, line);
1628 for (x = 0; x < im->xsize; ++x) {
1631 if (super_sample == i_fts_none)
1632 got_one = fount_getat(&c, x, y, &state);
1634 got_one = state.ssfunc(&c, x, y, &state);
1643 combinef_func(line, work, im->channels, im->xsize);
1644 i_plinf(im, 0, im->xsize, y, line);
1646 fount_finish_state(&state);
1647 if (work) myfree(work);
1653 struct fount_state state;
1654 } i_fill_fountain_t;
1657 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
1660 fount_fill_destroy(i_fill_t *fill);
1663 =item i_new_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1665 Creates a new general fill which fills with a fountain fill.
1671 i_new_fill_fount(double xa, double ya, double xb, double yb,
1672 i_fountain_type type, i_fountain_repeat repeat,
1673 int combine, int super_sample, double ssample_param,
1674 int count, i_fountain_seg *segs) {
1675 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1677 fill->base.fill_with_color = NULL;
1678 fill->base.fill_with_fcolor = fill_fountf;
1679 fill->base.destroy = fount_fill_destroy;
1681 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1683 fill->base.combine = NULL;
1684 fill->base.combinef = NULL;
1686 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1687 super_sample, ssample_param, count, segs);
1695 =head1 INTERNAL FUNCTIONS
1699 =item fount_init_state(...)
1701 Used by both the fountain fill filter and the fountain fill.
1707 fount_init_state(struct fount_state *state, double xa, double ya,
1708 double xb, double yb, i_fountain_type type,
1709 i_fountain_repeat repeat, int combine, int super_sample,
1710 double ssample_param, int count, i_fountain_seg *segs) {
1712 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count);
1713 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1715 memset(state, 0, sizeof(*state));
1716 /* we keep a local copy that we can adjust for speed */
1717 for (i = 0; i < count; ++i) {
1718 i_fountain_seg *seg = my_segs + i;
1721 if (seg->type < 0 || seg->type >= i_fst_end)
1722 seg->type = i_fst_linear;
1723 if (seg->color < 0 || seg->color >= i_fc_end)
1724 seg->color = i_fc_direct;
1725 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1726 /* so we don't have to translate to HSV on each request, do it here */
1727 for (j = 0; j < 2; ++j) {
1728 i_rgb_to_hsvf(seg->c+j);
1730 if (seg->color == i_fc_hue_up) {
1731 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1732 seg->c[1].channel[0] += 1.0;
1735 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1736 seg->c[0].channel[0] += 1.0;
1739 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1740 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1741 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1742 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1743 seg->c[1].channel[3], seg->type, seg->color);*/
1747 /* initialize each engine */
1748 /* these are so common ... */
1749 state->lA = xb - xa;
1750 state->lB = yb - ya;
1751 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1756 type = i_ft_linear; /* make the invalid value valid */
1759 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1761 state->mult = 1/linear_fount_f(xb, yb, state);
1765 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1766 + (double)(yb-ya)*(yb-ya));
1769 case i_ft_radial_square:
1770 state->cos = state->lA / state->AB;
1771 state->sin = state->lB / state->AB;
1772 state->mult = 1.0 / state->AB;
1775 case i_ft_revolution:
1776 state->theta = atan2(yb-ya, xb-xa);
1777 state->mult = 1.0 / (PI * 2);
1781 state->theta = atan2(yb-ya, xb-xa);
1782 state->mult = 1.0 / PI;
1785 state->ffunc = fount_funcs[type];
1786 if (super_sample < 0
1787 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1790 state->ssample_data = NULL;
1791 switch (super_sample) {
1793 ssample_param = floor(0.5 + sqrt(ssample_param));
1794 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param);
1799 ssample_param = floor(0.5+ssample_param);
1800 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1803 state->parm = ssample_param;
1804 state->ssfunc = fount_ssamples[super_sample];
1805 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1807 state->rpfunc = fount_repeats[repeat];
1808 state->segs = my_segs;
1809 state->count = count;
1813 fount_finish_state(struct fount_state *state) {
1814 if (state->ssample_data)
1815 myfree(state->ssample_data);
1816 myfree(state->segs);
1821 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1823 Evaluates the fountain fill at the given point.
1825 This is called by both the non-super-sampling and super-sampling code.
1827 You might think that it would make sense to sample the fill parameter
1828 instead, and combine those, but this breaks badly.
1834 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1835 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1839 while (i < state->count
1840 && (v < state->segs[i].start || v > state->segs[i].end)) {
1843 if (i < state->count) {
1844 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1845 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1853 =item linear_fount_f(x, y, state)
1855 Calculate the fill parameter for a linear fountain fill.
1857 Uses the point to line distance function, with some precalculation
1858 done in i_fountain().
1863 linear_fount_f(double x, double y, struct fount_state *state) {
1864 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1868 =item bilinear_fount_f(x, y, state)
1870 Calculate the fill parameter for a bi-linear fountain fill.
1875 bilinear_fount_f(double x, double y, struct fount_state *state) {
1876 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1880 =item radial_fount_f(x, y, state)
1882 Calculate the fill parameter for a radial fountain fill.
1884 Simply uses the distance function.
1889 radial_fount_f(double x, double y, struct fount_state *state) {
1890 return sqrt((double)(state->xa-x)*(state->xa-x)
1891 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1895 =item square_fount_f(x, y, state)
1897 Calculate the fill parameter for a square fountain fill.
1899 Works by rotating the reference co-ordinate around the centre of the
1905 square_fount_f(double x, double y, struct fount_state *state) {
1906 int xc, yc; /* centred on A */
1907 double xt, yt; /* rotated by theta */
1910 xt = fabs(xc * state->cos + yc * state->sin);
1911 yt = fabs(-xc * state->sin + yc * state->cos);
1912 return (xt > yt ? xt : yt) * state->mult;
1916 =item revolution_fount_f(x, y, state)
1918 Calculates the fill parameter for the revolution fountain fill.
1923 revolution_fount_f(double x, double y, struct fount_state *state) {
1924 double angle = atan2(y - state->ya, x - state->xa);
1926 angle -= state->theta;
1928 angle = fmod(angle+ PI * 4, PI*2);
1931 return angle * state->mult;
1935 =item conical_fount_f(x, y, state)
1937 Calculates the fill parameter for the conical fountain fill.
1942 conical_fount_f(double x, double y, struct fount_state *state) {
1943 double angle = atan2(y - state->ya, x - state->xa);
1945 angle -= state->theta;
1948 else if (angle > PI)
1951 return fabs(angle) * state->mult;
1955 =item linear_interp(pos, seg)
1957 Calculates linear interpolation on the fill parameter. Breaks the
1958 segment into 2 regions based in the I<middle> value.
1963 linear_interp(double pos, i_fountain_seg *seg) {
1964 if (pos < seg->middle) {
1965 double len = seg->middle - seg->start;
1969 return (pos - seg->start) / len / 2;
1972 double len = seg->end - seg->middle;
1976 return 0.5 + (pos - seg->middle) / len / 2;
1981 =item sine_interp(pos, seg)
1983 Calculates sine function interpolation on the fill parameter.
1988 sine_interp(double pos, i_fountain_seg *seg) {
1989 /* I wonder if there's a simple way to smooth the transition for this */
1990 double work = linear_interp(pos, seg);
1992 return (1-cos(work * PI))/2;
1996 =item sphereup_interp(pos, seg)
1998 Calculates spherical interpolation on the fill parameter, with the cusp
2004 sphereup_interp(double pos, i_fountain_seg *seg) {
2005 double work = linear_interp(pos, seg);
2007 return sqrt(1.0 - (1-work) * (1-work));
2011 =item spheredown_interp(pos, seg)
2013 Calculates spherical interpolation on the fill parameter, with the cusp
2019 spheredown_interp(double pos, i_fountain_seg *seg) {
2020 double work = linear_interp(pos, seg);
2022 return 1-sqrt(1.0 - work * work);
2026 =item direct_cinterp(out, pos, seg)
2028 Calculates the fountain color based on direct scaling of the channels
2029 of the color channels.
2034 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2036 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2037 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2038 + seg->c[1].channel[ch] * pos;
2043 =item hue_up_cinterp(put, pos, seg)
2045 Calculates the fountain color based on scaling a HSV value. The hue
2046 increases as the fill parameter increases.
2051 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2053 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2054 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2055 + seg->c[1].channel[ch] * pos;
2061 =item hue_down_cinterp(put, pos, seg)
2063 Calculates the fountain color based on scaling a HSV value. The hue
2064 decreases as the fill parameter increases.
2069 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2071 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2072 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2073 + seg->c[1].channel[ch] * pos;
2079 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2081 Simple grid-based super-sampling.
2086 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2087 i_fcolor *work = state->ssample_data;
2089 int grid = state->parm;
2090 double base = -0.5 + 0.5 / grid;
2091 double step = 1.0 / grid;
2095 for (dx = 0; dx < grid; ++dx) {
2096 for (dy = 0; dy < grid; ++dy) {
2097 if (fount_getat(work+samp_count, x + base + step * dx,
2098 y + base + step * dy, state)) {
2103 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2104 out->channel[ch] = 0;
2105 for (i = 0; i < samp_count; ++i) {
2106 out->channel[ch] += work[i].channel[ch];
2108 /* we divide by 4 rather than samp_count since if there's only one valid
2109 sample it should be mostly transparent */
2110 out->channel[ch] /= grid * grid;
2116 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2118 Random super-sampling.
2123 random_ssample(i_fcolor *out, double x, double y,
2124 struct fount_state *state) {
2125 i_fcolor *work = state->ssample_data;
2127 int maxsamples = state->parm;
2128 double rand_scale = 1.0 / RAND_MAX;
2130 for (i = 0; i < maxsamples; ++i) {
2131 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2132 y - 0.5 + rand() * rand_scale, state)) {
2136 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2137 out->channel[ch] = 0;
2138 for (i = 0; i < samp_count; ++i) {
2139 out->channel[ch] += work[i].channel[ch];
2141 /* we divide by maxsamples rather than samp_count since if there's
2142 only one valid sample it should be mostly transparent */
2143 out->channel[ch] /= maxsamples;
2149 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2151 Super-sampling around the circumference of a circle.
2153 I considered saving the sin()/cos() values and transforming step-size
2154 around the circle, but that's inaccurate, though it may not matter
2160 circle_ssample(i_fcolor *out, double x, double y,
2161 struct fount_state *state) {
2162 i_fcolor *work = state->ssample_data;
2164 int maxsamples = state->parm;
2165 double angle = 2 * PI / maxsamples;
2166 double radius = 0.3; /* semi-random */
2168 for (i = 0; i < maxsamples; ++i) {
2169 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2170 y + radius * sin(angle * i), state)) {
2174 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2175 out->channel[ch] = 0;
2176 for (i = 0; i < samp_count; ++i) {
2177 out->channel[ch] += work[i].channel[ch];
2179 /* we divide by maxsamples rather than samp_count since if there's
2180 only one valid sample it should be mostly transparent */
2181 out->channel[ch] /= maxsamples;
2187 =item fount_r_none(v)
2189 Implements no repeats. Simply clamps the fill value.
2194 fount_r_none(double v) {
2195 return v < 0 ? 0 : v > 1 ? 1 : v;
2199 =item fount_r_sawtooth(v)
2201 Implements sawtooth repeats. Clamps negative values and uses fmod()
2207 fount_r_sawtooth(double v) {
2208 return v < 0 ? 0 : fmod(v, 1.0);
2212 =item fount_r_triangle(v)
2214 Implements triangle repeats. Clamps negative values, uses fmod to get
2215 a range 0 through 2 and then adjusts values > 1.
2220 fount_r_triangle(double v) {
2225 return v > 1.0 ? 2.0 - v : v;
2230 =item fount_r_saw_both(v)
2232 Implements sawtooth repeats in the both postive and negative directions.
2234 Adjusts the value to be postive and then just uses fmod().
2239 fount_r_saw_both(double v) {
2242 return fmod(v, 1.0);
2246 =item fount_r_tri_both(v)
2248 Implements triangle repeats in the both postive and negative directions.
2250 Uses fmod on the absolute value, and then adjusts values > 1.
2255 fount_r_tri_both(double v) {
2256 v = fmod(fabs(v), 2.0);
2257 return v > 1.0 ? 2.0 - v : v;
2261 =item fill_fountf(fill, x, y, width, channels, data)
2263 The fill function for fountain fills.
2268 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
2270 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2276 if (f->state.ssfunc)
2277 got_one = f->state.ssfunc(&c, x, y, &f->state);
2279 got_one = fount_getat(&c, x, y, &f->state);
2288 =item fount_fill_destroy(fill)
2293 fount_fill_destroy(i_fill_t *fill) {
2294 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2295 fount_finish_state(&f->state);
2303 Arnar M. Hrafnkelsson <addi@umich.edu>
2305 Tony Cook <tony@develop-help.com> (i_fountain())