10 filters.im - 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) {
111 int color_channels = i_img_color_channels(im);
113 mm_log((1,"i_hardinvert(im %p)\n", im));
116 IM_COLOR *row, *entry;
118 /* always rooms to allocate a single line of i_color */
119 row = mymalloc(sizeof(IM_COLOR) * im->xsize); /* checked 17feb2005 tonyc */
121 for(y = 0; y < im->ysize; y++) {
122 IM_GLIN(im, 0, im->xsize, y, row);
124 for(x = 0; x < im->xsize; x++) {
125 for(ch = 0; ch < color_channels; ch++) {
126 entry->channel[ch] = IM_SAMPLE_MAX - entry->channel[ch];
130 IM_PLIN(im, 0, im->xsize, y, row);
139 =item i_noise(im, amount, type)
141 Inverts the pixel values by the amount specified.
144 amount - deviation in pixel values
145 type - noise individual for each channel if true
151 /* random() is non-ASCII, even if it is better than rand() */
152 #define random() rand()
156 i_noise(i_img *im, float amount, unsigned char type) {
160 float damount = amount * 2;
164 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
166 if(amount < 0) return;
168 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
169 i_gpix(im, x, y, &rcolor);
172 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
175 for(ch = 0; ch < im->channels; ch++) {
176 new_color = (int) rcolor.channel[ch];
179 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
181 new_color += color_inc;
187 if(new_color > 255) {
191 rcolor.channel[ch] = (unsigned char) new_color;
194 i_ppix(im, x, y, &rcolor);
200 =item i_noise(im, amount, type)
202 Inverts the pixel values by the amount specified.
205 amount - deviation in pixel values
206 type - noise individual for each channel if true
213 =item i_applyimage(im, add_im, mode)
215 Apply's an image to another image
218 add_im - image that is applied to target
219 mode - what method is used in applying:
239 void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
243 mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
245 mx = (add_im->xsize <= im->xsize) ? add_im->xsize : add_im->xsize;
246 my = (add_im->ysize <= im->ysize) ? add_im->ysize : add_im->ysize;
248 for(x = 0; x < mx; x++) {
249 for(y = 0; y < my; y++) {
256 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
258 Makes a bumpmap on image im using the bump image as the elevation map.
261 bump - image that contains the elevation info
262 channel - to take the elevation information from
263 light_x - x coordinate of light source
264 light_y - y coordinate of light source
265 st - length of shadow
271 i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
274 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
279 unsigned char px1, px2, py1, py2;
283 mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light_x %d, light_y %d, st %d)\n",
284 im, bump, channel, light_x, light_y, st));
287 if(channel >= bump->channels) {
288 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
292 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
293 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
295 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
297 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
298 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
300 aL = sqrt((aX * aX) + (aY * aY));
302 for(y = 1; y < my - 1; y++) {
303 for(x = 1; x < mx - 1; x++) {
304 i_gpix(bump, x + st, y, &x1_color);
305 i_gpix(bump, x, y + st, &y1_color);
306 i_gpix(bump, x - st, y, &x2_color);
307 i_gpix(bump, x, y - st, &y2_color);
309 i_gpix(im, x, y, &dst_color);
311 px1 = x1_color.channel[channel];
312 py1 = y1_color.channel[channel];
313 px2 = x2_color.channel[channel];
314 py2 = y2_color.channel[channel];
322 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
324 tX = abs(x - light_x) / aL;
325 tY = abs(y - light_y) / aL;
327 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
332 for(ch = 0; ch < im->channels; ch++)
333 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
335 i_ppix(&new_im, x, y, &dst_color);
339 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
341 i_img_exorcise(&new_im);
354 dotp(fvec *a, fvec *b) {
355 return a->x*b->x+a->y*b->y+a->z*b->z;
361 double d = sqrt(dotp(a,a));
375 I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
377 Here, the variables are:
379 * Ia - ambient colour
380 * Ip - intensity of the point light source
381 * cd - diffuse coefficient
382 * Scol - surface colour
383 * cs - specular coefficient
384 * n - objects shinyness
386 * L - lighting vector
387 * R - reflection vector
390 static void fvec_dump(fvec *x) {
391 printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
395 /* XXX: Should these return a code for success? */
401 =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
403 Makes a bumpmap on image im using the bump image as the elevation map.
406 bump - image that contains the elevation info
407 channel - to take the elevation information from
408 tx - shift in x direction of where to start applying bumpmap
409 ty - shift in y direction of where to start applying bumpmap
410 Lx - x position/direction of light
411 Ly - y position/direction of light
412 Lz - z position/direction of light
414 cd - diffuse coefficient
415 cs - specular coefficient
416 n - surface shinyness
421 if z<0 then the L is taken to be the direction the light is shining in. Otherwise
422 the L is taken to be the position of the Light, Relative to the image.
429 i_bumpmap_complex(i_img *im,
449 float cdc[MAXCHANNELS];
450 float csc[MAXCHANNELS];
452 i_color x1_color, y1_color, x2_color, y2_color;
454 i_color Scol; /* Surface colour */
456 fvec L; /* Light vector */
457 fvec N; /* surface normal */
458 fvec R; /* Reflection vector */
459 fvec V; /* Vision vector */
461 mm_log((1, "i_bumpmap_complex(im %p, bump %p, channel %d, tx %d, ty %d, Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n",
462 im, bump, channel, tx, ty, Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
464 if (channel >= bump->channels) {
465 mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
469 for(ch=0; ch<im->channels; ch++) {
470 cdc[ch] = (float)Il->channel[ch]*cd/255.f;
471 csc[ch] = (float)Is->channel[ch]*cs/255.f;
483 if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
488 } else { /* Light is the position of the light source */
496 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
498 for(y = 0; y < im->ysize; y++) {
499 for(x = 0; x < im->xsize; x++) {
501 double dx = 0, dy = 0;
503 /* Calculate surface normal */
504 if (mx<x && x<Mx && my<y && y<My) {
505 i_gpix(bump, x + 1, y, &x1_color);
506 i_gpix(bump, x - 1, y, &x2_color);
507 i_gpix(bump, x, y + 1, &y1_color);
508 i_gpix(bump, x, y - 1, &y2_color);
509 dx = x2_color.channel[channel] - x1_color.channel[channel];
510 dy = y2_color.channel[channel] - y1_color.channel[channel];
520 /* Calculate Light vector if needed */
529 R.x = -L.x + 2*dp1*N.x;
530 R.y = -L.y + 2*dp1*N.y;
531 R.z = -L.z + 2*dp1*N.z;
535 dp1 = dp1<0 ?0 : dp1;
536 dp2 = pow(dp2<0 ?0 : dp2,n);
538 i_gpix(im, x, y, &Scol);
540 for(ch = 0; ch < im->channels; ch++)
542 saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
544 i_ppix(&new_im, x, y, &Scol);
548 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
549 i_img_exorcise(&new_im);
554 =item i_postlevels(im, levels)
556 Quantizes Images to fewer levels.
559 levels - number of levels
565 i_postlevels(i_img *im, int levels) {
573 rv = (int) ((float)(256 / levels));
576 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
577 i_gpix(im, x, y, &rcolor);
579 for(ch = 0; ch < im->channels; ch++) {
580 pv = (((float)rcolor.channel[ch] / 255)) * av;
581 pv = (int) ((int)pv * rv);
584 else if(pv > 255) pv = 255;
586 rcolor.channel[ch] = (unsigned char) pv;
588 i_ppix(im, x, y, &rcolor);
594 =item i_mosaic(im, size)
596 Makes an image looks like a mosaic with tilesize of size
605 i_mosaic(i_img *im, int size) {
613 sqrsize = size * size;
615 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
616 for(z = 0; z < 256; z++) col[z] = 0;
618 for(lx = 0; lx < size; lx++) {
619 for(ly = 0; ly < size; ly++) {
620 i_gpix(im, (x + lx), (y + ly), &rcolor);
622 for(ch = 0; ch < im->channels; ch++) {
623 col[ch] += rcolor.channel[ch];
628 for(ch = 0; ch < im->channels; ch++)
629 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
632 for(lx = 0; lx < size; lx++)
633 for(ly = 0; ly < size; ly++)
634 i_ppix(im, (x + lx), (y + ly), &rcolor);
641 =item i_watermark(im, wmark, tx, ty, pixdiff)
643 Applies a watermark to the target image
646 wmark - watermark image
647 tx - x coordinate of where watermark should be applied
648 ty - y coordinate of where watermark should be applied
649 pixdiff - the magnitude of the watermark, controls how visible it is
655 i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
659 int mx = wmark->xsize;
660 int my = wmark->ysize;
662 for(vx=0;vx<mx;vx++) for(vy=0;vy<my;vy++) {
664 i_gpix(im, tx+vx, ty+vy,&val );
665 i_gpix(wmark, vx, vy, &wval);
667 for(ch=0;ch<im->channels;ch++)
668 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
670 i_ppix(im,tx+vx,ty+vy,&val);
676 =item i_autolevels(im, lsat, usat, skew)
678 Scales and translates each color such that it fills the range completely.
679 Skew is not implemented yet - purpose is to control the color skew that can
680 occur when changing the contrast.
683 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
684 usat - fraction of pixels that will be truncated at the higher end of the spectrum
691 i_autolevels(i_img *im, float lsat, float usat, float skew) {
693 int i, x, y, rhist[256], ghist[256], bhist[256];
694 int rsum, rmin, rmax;
695 int gsum, gmin, gmax;
696 int bsum, bmin, bmax;
697 int rcl, rcu, gcl, gcu, bcl, bcu;
699 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
702 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
703 /* create histogram for each channel */
704 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
705 i_gpix(im, x, y, &val);
706 rhist[val.channel[0]]++;
707 ghist[val.channel[1]]++;
708 bhist[val.channel[2]]++;
717 rmin = gmin = bmin = 0;
718 rmax = gmax = bmax = 255;
720 rcu = rcl = gcu = gcl = bcu = bcl = 0;
722 for(i=0; i<256; i++) {
723 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
724 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
726 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
727 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
729 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
730 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
733 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
734 i_gpix(im, x, y, &val);
735 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
736 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
737 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
738 i_ppix(im, x, y, &val);
745 Pseudo noise utility function used to generate perlin noise. (internal)
755 Noise(int x, int y) {
758 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
762 =item SmoothedNoise1(x,y)
764 Pseudo noise utility function used to generate perlin noise. (internal)
774 SmoothedNoise1(float x, float y) {
775 float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
776 float sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
777 float center = Noise(x, y) / 4;
778 return corners + sides + center;
783 =item G_Interpolate(a, b, x)
785 Utility function used to generate perlin noise. (internal)
791 float C_Interpolate(float a, float b, float x) {
792 /* float ft = x * 3.1415927; */
794 float f = (1 - cos(ft)) * .5;
795 return a*(1-f) + b*f;
800 =item InterpolatedNoise(x, y)
802 Utility function used to generate perlin noise. (internal)
809 InterpolatedNoise(float x, float y) {
812 float fractional_X = x - integer_X;
814 float fractional_Y = y - integer_Y;
816 float v1 = SmoothedNoise1(integer_X, integer_Y);
817 float v2 = SmoothedNoise1(integer_X + 1, integer_Y);
818 float v3 = SmoothedNoise1(integer_X, integer_Y + 1);
819 float v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
821 float i1 = C_Interpolate(v1 , v2 , fractional_X);
822 float i2 = C_Interpolate(v3 , v4 , fractional_X);
824 return C_Interpolate(i1 , i2 , fractional_Y);
830 =item PerlinNoise_2D(x, y)
832 Utility function used to generate perlin noise. (internal)
839 PerlinNoise_2D(float x, float y) {
843 int Number_Of_Octaves=6;
844 int n = Number_Of_Octaves - 1;
849 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
857 =item i_radnoise(im, xo, yo, rscale, ascale)
859 Perlin-like radial noise.
862 xo - x coordinate of center
863 yo - y coordinate of center
864 rscale - radial scale
865 ascale - angular scale
871 i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
878 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
879 xc = (float)x-xo+0.5;
880 yc = (float)y-yo+0.5;
881 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
882 a = (PI+atan2(yc,xc))*ascale;
883 v = saturate(128+100*(PerlinNoise_2D(a,r)));
884 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
885 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
886 i_ppix(im, x, y, &val);
892 =item i_turbnoise(im, xo, yo, scale)
894 Perlin-like 2d noise noise.
897 xo - x coordinate translation
898 yo - y coordinate translation
899 scale - scale of noise
905 i_turbnoise(i_img *im, float xo, float yo, float scale) {
910 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
911 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
912 v = saturate(120*(1.0+sin(xo+(float)x/scale+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))));
913 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
914 i_ppix(im, x, y, &val);
921 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
923 Gradient generating function.
926 num - number of points given
927 xo - array of x coordinates
928 yo - array of y coordinates
929 ival - array of i_color objects
930 dmeasure - distance measure to be used.
932 1 = Euclidean squared
933 2 = Manhattan distance
940 i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
944 int channels = im->channels;
945 int xsize = im->xsize;
946 int ysize = im->ysize;
951 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
953 for(p = 0; p<num; p++) {
954 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
958 /* on the systems I have sizeof(float) == sizeof(int) and thus
959 this would be same size as the arrays xo and yo point at, but this
960 may not be true for other systems
962 since the arrays here are caller controlled, I assume that on
963 overflow is a programming error rather than an end-user error, so
964 calling exit() is justified.
966 bytes = sizeof(float) * num;
967 if (bytes / num != sizeof(float)) {
968 fprintf(stderr, "integer overflow calculating memory allocation");
971 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
973 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
976 for(p = 0; p<num; p++) {
980 case 0: /* euclidean */
981 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
983 case 1: /* euclidean squared */
984 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
986 case 2: /* euclidean squared */
987 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
990 i_fatal(3,"i_gradgen: Unknown distance measure\n");
995 csd = 1/((num-1)*cs);
997 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
999 for(ch = 0; ch<channels; ch++) {
1001 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
1002 val.channel[ch] = saturate(tres);
1004 i_ppix(im, x, y, &val);
1011 i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
1014 int xsize = im->xsize;
1015 int ysize = im->ysize;
1017 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
1019 for(p = 0; p<num; p++) {
1020 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
1024 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1033 case 0: /* euclidean */
1034 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1036 case 1: /* euclidean squared */
1037 mindist = xd*xd + yd*yd; /* euclidean distance */
1039 case 2: /* euclidean squared */
1040 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1043 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1046 for(p = 1; p<num; p++) {
1050 case 0: /* euclidean */
1051 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1053 case 1: /* euclidean squared */
1054 curdist = xd*xd + yd*yd; /* euclidean distance */
1056 case 2: /* euclidean squared */
1057 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1060 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1062 if (curdist < mindist) {
1067 i_ppix(im, x, y, &ival[midx]);
1072 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1074 This wasn't document - quoth Addi:
1076 An arty type of filter
1078 FIXME: check IRC logs for actual text.
1086 i_img *im - image to render on.
1090 int num - number of points/colors in xo, yo, oval
1094 int *xo - array of I<num> x positions
1098 int *yo - array of I<num> y positions
1102 i_color *oval - array of I<num> colors
1104 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1105 color something like oval[i], at least closer to that color than other
1110 int dmeasure - how we measure the distance from some point P(x,y) to
1119 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1123 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1127 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1131 An invalid value causes an error exit (the program is aborted).
1139 i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
1145 int xsize = im->xsize;
1146 int ysize = im->ysize;
1148 int ival_bytes, tval_bytes;
1150 mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
1155 i_push_error(0, "no points supplied to nearest_color filter");
1159 if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1160 i_push_error(0, "distance measure invalid");
1164 tval_bytes = sizeof(float)*num*im->channels;
1165 if (tval_bytes / num != sizeof(float) * im->channels) {
1166 i_push_error(0, "integer overflow calculating memory allocation");
1169 ival_bytes = sizeof(i_color) * num;
1170 if (ival_bytes / sizeof(i_color) != num) {
1171 i_push_error(0, "integer overflow calculating memory allocation");
1174 tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1175 ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1176 cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1178 for(p = 0; p<num; p++) {
1179 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1184 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1193 case 0: /* euclidean */
1194 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1196 case 1: /* euclidean squared */
1197 mindist = xd*xd + yd*yd; /* euclidean distance */
1199 case 2: /* manhatten distance */
1200 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1203 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1206 for(p = 1; p<num; p++) {
1210 case 0: /* euclidean */
1211 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1213 case 1: /* euclidean squared */
1214 curdist = xd*xd + yd*yd; /* euclidean distance */
1216 case 2: /* euclidean squared */
1217 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1220 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1222 if (curdist < mindist) {
1229 i_gpix(im, x, y, &val);
1230 c2 = 1.0/(float)(cmatch[midx]);
1233 for(ch = 0; ch<im->channels; ch++)
1234 tval[midx*im->channels + ch] =
1235 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1239 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++)
1240 ival[p].channel[ch] = tval[p*im->channels + ch];
1242 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1248 =item i_unsharp_mask(im, stddev, scale)
1250 Perform an usharp mask, which is defined as subtracting the blurred
1251 image from double the original.
1257 i_unsharp_mask(i_img *im, double stddev, double scale) {
1263 /* it really shouldn't ever be more than 1.0, but maybe ... */
1268 i_gaussian(copy, stddev);
1269 if (im->bits == i_8_bits) {
1270 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1271 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1273 for (y = 0; y < im->ysize; ++y) {
1274 i_glin(copy, 0, copy->xsize, y, blur);
1275 i_glin(im, 0, im->xsize, y, out);
1276 for (x = 0; x < im->xsize; ++x) {
1277 for (ch = 0; ch < im->channels; ++ch) {
1278 /*int temp = out[x].channel[ch] +
1279 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1280 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1283 else if (temp > 255)
1285 out[x].channel[ch] = temp;
1288 i_plin(im, 0, im->xsize, y, out);
1295 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1296 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1298 for (y = 0; y < im->ysize; ++y) {
1299 i_glinf(copy, 0, copy->xsize, y, blur);
1300 i_glinf(im, 0, im->xsize, y, out);
1301 for (x = 0; x < im->xsize; ++x) {
1302 for (ch = 0; ch < im->channels; ++ch) {
1303 double temp = out[x].channel[ch] +
1304 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1307 else if (temp > 1.0)
1309 out[x].channel[ch] = temp;
1312 i_plinf(im, 0, im->xsize, y, out);
1318 i_img_destroy(copy);
1322 =item i_diff_image(im1, im2, mindist)
1324 Creates a new image that is transparent, except where the pixel in im2
1325 is different from im1, where it is the pixel from im2.
1327 The samples must differ by at least mindiff to be considered different.
1333 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1335 int outchans, diffchans;
1339 if (im1->channels != im2->channels) {
1340 i_push_error(0, "different number of channels");
1344 outchans = diffchans = im1->channels;
1345 if (outchans == 1 || outchans == 3)
1348 xsize = i_min(im1->xsize, im2->xsize);
1349 ysize = i_min(im1->ysize, im2->ysize);
1351 out = i_sametype_chans(im1, xsize, ysize, outchans);
1353 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1354 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1355 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1358 int imindist = (int)mindist;
1360 for (ch = 0; ch < MAXCHANNELS; ++ch)
1361 empty.channel[ch] = 0;
1363 for (y = 0; y < ysize; ++y) {
1364 i_glin(im1, 0, xsize, y, line1);
1365 i_glin(im2, 0, xsize, y, line2);
1366 if (outchans != diffchans) {
1367 /* give the output an alpha channel since it doesn't have one */
1368 for (x = 0; x < xsize; ++x)
1369 line2[x].channel[diffchans] = 255;
1371 for (x = 0; x < xsize; ++x) {
1373 for (ch = 0; ch < diffchans; ++ch) {
1374 if (line1[x].channel[ch] != line2[x].channel[ch]
1375 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1383 i_plin(out, 0, xsize, y, line2);
1389 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1390 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1393 double dist = mindist / 255.0;
1395 for (ch = 0; ch < MAXCHANNELS; ++ch)
1396 empty.channel[ch] = 0;
1398 for (y = 0; y < ysize; ++y) {
1399 i_glinf(im1, 0, xsize, y, line1);
1400 i_glinf(im2, 0, xsize, y, line2);
1401 if (outchans != diffchans) {
1402 /* give the output an alpha channel since it doesn't have one */
1403 for (x = 0; x < xsize; ++x)
1404 line2[x].channel[diffchans] = 1.0;
1406 for (x = 0; x < xsize; ++x) {
1408 for (ch = 0; ch < diffchans; ++ch) {
1409 if (line1[x].channel[ch] != line2[x].channel[ch]
1410 && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1418 i_plinf(out, 0, xsize, y, line2);
1428 static double linear_fount_f(double x, double y, struct fount_state *state);
1429 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1430 static double radial_fount_f(double x, double y, struct fount_state *state);
1431 static double square_fount_f(double x, double y, struct fount_state *state);
1432 static double revolution_fount_f(double x, double y,
1433 struct fount_state *state);
1434 static double conical_fount_f(double x, double y, struct fount_state *state);
1436 typedef double (*fount_func)(double, double, struct fount_state *);
1437 static fount_func fount_funcs[] =
1447 static double linear_interp(double pos, i_fountain_seg *seg);
1448 static double sine_interp(double pos, i_fountain_seg *seg);
1449 static double sphereup_interp(double pos, i_fountain_seg *seg);
1450 static double spheredown_interp(double pos, i_fountain_seg *seg);
1451 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1452 static fount_interp fount_interps[] =
1461 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1462 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1463 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1464 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1465 static fount_cinterp fount_cinterps[] =
1472 typedef double (*fount_repeat)(double v);
1473 static double fount_r_none(double v);
1474 static double fount_r_sawtooth(double v);
1475 static double fount_r_triangle(double v);
1476 static double fount_r_saw_both(double v);
1477 static double fount_r_tri_both(double v);
1478 static fount_repeat fount_repeats[] =
1487 static int simple_ssample(i_fcolor *out, double x, double y,
1488 struct fount_state *state);
1489 static int random_ssample(i_fcolor *out, double x, double y,
1490 struct fount_state *state);
1491 static int circle_ssample(i_fcolor *out, double x, double y,
1492 struct fount_state *state);
1493 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1494 struct fount_state *state);
1495 static fount_ssample fount_ssamples[] =
1504 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1507 Keep state information used by each type of fountain fill
1509 struct fount_state {
1510 /* precalculated for the equation of the line perpendicular to the line AB */
1521 fount_repeat rpfunc;
1522 fount_ssample ssfunc;
1524 i_fountain_seg *segs;
1529 fount_init_state(struct fount_state *state, double xa, double ya,
1530 double xb, double yb, i_fountain_type type,
1531 i_fountain_repeat repeat, int combine, int super_sample,
1532 double ssample_param, int count, i_fountain_seg *segs);
1535 fount_finish_state(struct fount_state *state);
1537 #define EPSILON (1e-6)
1540 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1542 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1544 I<type> controls how the reference points are used:
1550 linear, where A is 0 and B is 1.
1554 linear in both directions from A.
1558 circular, where A is the centre of the fill, and B is a point
1561 =item i_ft_radial_square
1563 where A is the centre of the fill and B is the centre of
1564 one side of the square.
1566 =item i_ft_revolution
1568 where A is the centre of the fill and B defines the 0/1.0
1573 similar to i_ft_revolution, except that the revolution goes in both
1578 I<repeat> can be one of:
1584 values < 0 are treated as zero, values > 1 are treated as 1.
1588 negative values are treated as 0, positive values are modulo 1.0
1592 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1593 mod 1.0), otherwise the same as for sawtooth.
1597 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1602 Like i_fr_triangle, except that negative values are handled as their
1607 If combine is non-zero then non-opaque values are combined with the
1610 I<super_sample> controls super sampling, if any. At some point I'll
1611 probably add a adaptive super-sampler. Current possible values are:
1617 No super-sampling is done.
1621 A square grid of points withing the pixel are sampled.
1625 Random points within the pixel are sampled.
1629 Points on the radius of a circle are sampled. This produces fairly
1630 good results, but is fairly slow since sin() and cos() are evaluated
1635 I<ssample_param> is intended to be roughly the number of points
1636 sampled within the pixel.
1638 I<count> and I<segs> define the segments of the fill.
1645 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1646 i_fountain_type type, i_fountain_repeat repeat,
1647 int combine, int super_sample, double ssample_param,
1648 int count, i_fountain_seg *segs) {
1649 struct fount_state state;
1651 i_fcolor *line = NULL;
1652 i_fcolor *work = NULL;
1654 i_fountain_seg *my_segs;
1655 i_fill_combine_f combine_func = NULL;
1656 i_fill_combinef_f combinef_func = NULL;
1660 /* i_fountain() allocates floating colors even for 8-bit images,
1661 so we need to do this check */
1662 line_bytes = sizeof(i_fcolor) * im->xsize;
1663 if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1664 i_push_error(0, "integer overflow calculating memory allocation");
1668 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1670 i_get_combine(combine, &combine_func, &combinef_func);
1672 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1674 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1675 super_sample, ssample_param, count, segs);
1676 my_segs = state.segs;
1678 for (y = 0; y < im->ysize; ++y) {
1679 i_glinf(im, 0, im->xsize, y, line);
1680 for (x = 0; x < im->xsize; ++x) {
1683 if (super_sample == i_fts_none)
1684 got_one = fount_getat(&c, x, y, &state);
1686 got_one = state.ssfunc(&c, x, y, &state);
1695 combinef_func(line, work, im->channels, im->xsize);
1696 i_plinf(im, 0, im->xsize, y, line);
1698 fount_finish_state(&state);
1699 if (work) myfree(work);
1707 struct fount_state state;
1708 } i_fill_fountain_t;
1711 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
1714 fount_fill_destroy(i_fill_t *fill);
1716 static i_fill_fountain_t
1728 =item i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1731 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1732 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1735 Creates a new general fill which fills with a fountain fill.
1741 i_new_fill_fount(double xa, double ya, double xb, double yb,
1742 i_fountain_type type, i_fountain_repeat repeat,
1743 int combine, int super_sample, double ssample_param,
1744 int count, i_fountain_seg *segs) {
1745 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1747 *fill = fount_fill_proto;
1749 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1751 fill->base.combine = NULL;
1752 fill->base.combinef = NULL;
1754 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1755 super_sample, ssample_param, count, segs);
1763 =head1 INTERNAL FUNCTIONS
1767 =item fount_init_state(...)
1769 Used by both the fountain fill filter and the fountain fill.
1775 fount_init_state(struct fount_state *state, double xa, double ya,
1776 double xb, double yb, i_fountain_type type,
1777 i_fountain_repeat repeat, int combine, int super_sample,
1778 double ssample_param, int count, i_fountain_seg *segs) {
1781 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1782 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1784 memset(state, 0, sizeof(*state));
1785 /* we keep a local copy that we can adjust for speed */
1786 for (i = 0; i < count; ++i) {
1787 i_fountain_seg *seg = my_segs + i;
1790 if (seg->type < 0 || seg->type >= i_fst_end)
1791 seg->type = i_fst_linear;
1792 if (seg->color < 0 || seg->color >= i_fc_end)
1793 seg->color = i_fc_direct;
1794 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1795 /* so we don't have to translate to HSV on each request, do it here */
1796 for (j = 0; j < 2; ++j) {
1797 i_rgb_to_hsvf(seg->c+j);
1799 if (seg->color == i_fc_hue_up) {
1800 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1801 seg->c[1].channel[0] += 1.0;
1804 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1805 seg->c[0].channel[0] += 1.0;
1808 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1809 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1810 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1811 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1812 seg->c[1].channel[3], seg->type, seg->color);*/
1816 /* initialize each engine */
1817 /* these are so common ... */
1818 state->lA = xb - xa;
1819 state->lB = yb - ya;
1820 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1825 type = i_ft_linear; /* make the invalid value valid */
1828 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1830 state->mult = 1/linear_fount_f(xb, yb, state);
1834 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1835 + (double)(yb-ya)*(yb-ya));
1838 case i_ft_radial_square:
1839 state->cos = state->lA / state->AB;
1840 state->sin = state->lB / state->AB;
1841 state->mult = 1.0 / state->AB;
1844 case i_ft_revolution:
1845 state->theta = atan2(yb-ya, xb-xa);
1846 state->mult = 1.0 / (PI * 2);
1850 state->theta = atan2(yb-ya, xb-xa);
1851 state->mult = 1.0 / PI;
1854 state->ffunc = fount_funcs[type];
1855 if (super_sample < 0
1856 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1859 state->ssample_data = NULL;
1860 switch (super_sample) {
1862 ssample_param = floor(0.5 + sqrt(ssample_param));
1863 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1864 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1865 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1868 super_sample = i_fts_none;
1874 ssample_param = floor(0.5+ssample_param);
1875 bytes = sizeof(i_fcolor) * ssample_param;
1876 if (bytes / sizeof(i_fcolor) == ssample_param) {
1877 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1880 super_sample = i_fts_none;
1884 state->parm = ssample_param;
1885 state->ssfunc = fount_ssamples[super_sample];
1886 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1888 state->rpfunc = fount_repeats[repeat];
1889 state->segs = my_segs;
1890 state->count = count;
1894 fount_finish_state(struct fount_state *state) {
1895 if (state->ssample_data)
1896 myfree(state->ssample_data);
1897 myfree(state->segs);
1902 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1904 Evaluates the fountain fill at the given point.
1906 This is called by both the non-super-sampling and super-sampling code.
1908 You might think that it would make sense to sample the fill parameter
1909 instead, and combine those, but this breaks badly.
1915 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1916 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1920 while (i < state->count
1921 && (v < state->segs[i].start || v > state->segs[i].end)) {
1924 if (i < state->count) {
1925 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1926 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1934 =item linear_fount_f(x, y, state)
1936 Calculate the fill parameter for a linear fountain fill.
1938 Uses the point to line distance function, with some precalculation
1939 done in i_fountain().
1944 linear_fount_f(double x, double y, struct fount_state *state) {
1945 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1949 =item bilinear_fount_f(x, y, state)
1951 Calculate the fill parameter for a bi-linear fountain fill.
1956 bilinear_fount_f(double x, double y, struct fount_state *state) {
1957 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1961 =item radial_fount_f(x, y, state)
1963 Calculate the fill parameter for a radial fountain fill.
1965 Simply uses the distance function.
1970 radial_fount_f(double x, double y, struct fount_state *state) {
1971 return sqrt((double)(state->xa-x)*(state->xa-x)
1972 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1976 =item square_fount_f(x, y, state)
1978 Calculate the fill parameter for a square fountain fill.
1980 Works by rotating the reference co-ordinate around the centre of the
1986 square_fount_f(double x, double y, struct fount_state *state) {
1987 int xc, yc; /* centred on A */
1988 double xt, yt; /* rotated by theta */
1991 xt = fabs(xc * state->cos + yc * state->sin);
1992 yt = fabs(-xc * state->sin + yc * state->cos);
1993 return (xt > yt ? xt : yt) * state->mult;
1997 =item revolution_fount_f(x, y, state)
1999 Calculates the fill parameter for the revolution fountain fill.
2004 revolution_fount_f(double x, double y, struct fount_state *state) {
2005 double angle = atan2(y - state->ya, x - state->xa);
2007 angle -= state->theta;
2009 angle = fmod(angle+ PI * 4, PI*2);
2012 return angle * state->mult;
2016 =item conical_fount_f(x, y, state)
2018 Calculates the fill parameter for the conical fountain fill.
2023 conical_fount_f(double x, double y, struct fount_state *state) {
2024 double angle = atan2(y - state->ya, x - state->xa);
2026 angle -= state->theta;
2029 else if (angle > PI)
2032 return fabs(angle) * state->mult;
2036 =item linear_interp(pos, seg)
2038 Calculates linear interpolation on the fill parameter. Breaks the
2039 segment into 2 regions based in the I<middle> value.
2044 linear_interp(double pos, i_fountain_seg *seg) {
2045 if (pos < seg->middle) {
2046 double len = seg->middle - seg->start;
2050 return (pos - seg->start) / len / 2;
2053 double len = seg->end - seg->middle;
2057 return 0.5 + (pos - seg->middle) / len / 2;
2062 =item sine_interp(pos, seg)
2064 Calculates sine function interpolation on the fill parameter.
2069 sine_interp(double pos, i_fountain_seg *seg) {
2070 /* I wonder if there's a simple way to smooth the transition for this */
2071 double work = linear_interp(pos, seg);
2073 return (1-cos(work * PI))/2;
2077 =item sphereup_interp(pos, seg)
2079 Calculates spherical interpolation on the fill parameter, with the cusp
2085 sphereup_interp(double pos, i_fountain_seg *seg) {
2086 double work = linear_interp(pos, seg);
2088 return sqrt(1.0 - (1-work) * (1-work));
2092 =item spheredown_interp(pos, seg)
2094 Calculates spherical interpolation on the fill parameter, with the cusp
2100 spheredown_interp(double pos, i_fountain_seg *seg) {
2101 double work = linear_interp(pos, seg);
2103 return 1-sqrt(1.0 - work * work);
2107 =item direct_cinterp(out, pos, seg)
2109 Calculates the fountain color based on direct scaling of the channels
2110 of the color channels.
2115 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2117 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2118 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2119 + seg->c[1].channel[ch] * pos;
2124 =item hue_up_cinterp(put, pos, seg)
2126 Calculates the fountain color based on scaling a HSV value. The hue
2127 increases as the fill parameter increases.
2132 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2134 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2135 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2136 + seg->c[1].channel[ch] * pos;
2142 =item hue_down_cinterp(put, pos, seg)
2144 Calculates the fountain color based on scaling a HSV value. The hue
2145 decreases as the fill parameter increases.
2150 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2152 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2153 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2154 + seg->c[1].channel[ch] * pos;
2160 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2162 Simple grid-based super-sampling.
2167 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2168 i_fcolor *work = state->ssample_data;
2170 int grid = state->parm;
2171 double base = -0.5 + 0.5 / grid;
2172 double step = 1.0 / grid;
2176 for (dx = 0; dx < grid; ++dx) {
2177 for (dy = 0; dy < grid; ++dy) {
2178 if (fount_getat(work+samp_count, x + base + step * dx,
2179 y + base + step * dy, state)) {
2184 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2185 out->channel[ch] = 0;
2186 for (i = 0; i < samp_count; ++i) {
2187 out->channel[ch] += work[i].channel[ch];
2189 /* we divide by 4 rather than samp_count since if there's only one valid
2190 sample it should be mostly transparent */
2191 out->channel[ch] /= grid * grid;
2197 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2199 Random super-sampling.
2204 random_ssample(i_fcolor *out, double x, double y,
2205 struct fount_state *state) {
2206 i_fcolor *work = state->ssample_data;
2208 int maxsamples = state->parm;
2209 double rand_scale = 1.0 / RAND_MAX;
2211 for (i = 0; i < maxsamples; ++i) {
2212 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2213 y - 0.5 + rand() * rand_scale, state)) {
2217 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2218 out->channel[ch] = 0;
2219 for (i = 0; i < samp_count; ++i) {
2220 out->channel[ch] += work[i].channel[ch];
2222 /* we divide by maxsamples rather than samp_count since if there's
2223 only one valid sample it should be mostly transparent */
2224 out->channel[ch] /= maxsamples;
2230 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2232 Super-sampling around the circumference of a circle.
2234 I considered saving the sin()/cos() values and transforming step-size
2235 around the circle, but that's inaccurate, though it may not matter
2241 circle_ssample(i_fcolor *out, double x, double y,
2242 struct fount_state *state) {
2243 i_fcolor *work = state->ssample_data;
2245 int maxsamples = state->parm;
2246 double angle = 2 * PI / maxsamples;
2247 double radius = 0.3; /* semi-random */
2249 for (i = 0; i < maxsamples; ++i) {
2250 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2251 y + radius * sin(angle * i), state)) {
2255 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2256 out->channel[ch] = 0;
2257 for (i = 0; i < samp_count; ++i) {
2258 out->channel[ch] += work[i].channel[ch];
2260 /* we divide by maxsamples rather than samp_count since if there's
2261 only one valid sample it should be mostly transparent */
2262 out->channel[ch] /= maxsamples;
2268 =item fount_r_none(v)
2270 Implements no repeats. Simply clamps the fill value.
2275 fount_r_none(double v) {
2276 return v < 0 ? 0 : v > 1 ? 1 : v;
2280 =item fount_r_sawtooth(v)
2282 Implements sawtooth repeats. Clamps negative values and uses fmod()
2288 fount_r_sawtooth(double v) {
2289 return v < 0 ? 0 : fmod(v, 1.0);
2293 =item fount_r_triangle(v)
2295 Implements triangle repeats. Clamps negative values, uses fmod to get
2296 a range 0 through 2 and then adjusts values > 1.
2301 fount_r_triangle(double v) {
2306 return v > 1.0 ? 2.0 - v : v;
2311 =item fount_r_saw_both(v)
2313 Implements sawtooth repeats in the both postive and negative directions.
2315 Adjusts the value to be postive and then just uses fmod().
2320 fount_r_saw_both(double v) {
2323 return fmod(v, 1.0);
2327 =item fount_r_tri_both(v)
2329 Implements triangle repeats in the both postive and negative directions.
2331 Uses fmod on the absolute value, and then adjusts values > 1.
2336 fount_r_tri_both(double v) {
2337 v = fmod(fabs(v), 2.0);
2338 return v > 1.0 ? 2.0 - v : v;
2342 =item fill_fountf(fill, x, y, width, channels, data)
2344 The fill function for fountain fills.
2349 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
2351 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2357 if (f->state.ssfunc)
2358 got_one = f->state.ssfunc(&c, x, y, &f->state);
2360 got_one = fount_getat(&c, x, y, &f->state);
2369 =item fount_fill_destroy(fill)
2374 fount_fill_destroy(i_fill_t *fill) {
2375 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2376 fount_finish_state(&f->state);
2384 Arnar M. Hrafnkelsson <addi@umich.edu>
2386 Tony Cook <tony@develop-help.com> (i_fountain())