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) {
112 i_color *row, *entry;
114 mm_log((1,"i_hardinvert(im %p)\n", im));
116 /* always rooms to allocate a single line of i_color */
117 row = mymalloc(sizeof(i_color) * im->xsize); /* checked 17feb2005 tonyc */
119 for(y = 0; y < im->ysize; y++) {
120 i_glin(im, 0, im->xsize, y, row);
122 for(x = 0; x < im->xsize; x++) {
123 for(ch = 0; ch < im->channels; ch++) {
124 entry->channel[ch] = 255 - entry->channel[ch];
128 i_plin(im, 0, im->xsize, y, row);
136 =item i_noise(im, amount, type)
138 Inverts the pixel values by the amount specified.
141 amount - deviation in pixel values
142 type - noise individual for each channel if true
148 /* random() is non-ASCII, even if it is better than rand() */
149 #define random() rand()
153 i_noise(i_img *im, float amount, unsigned char type) {
157 float damount = amount * 2;
161 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
163 if(amount < 0) return;
165 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
166 i_gpix(im, x, y, &rcolor);
169 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
172 for(ch = 0; ch < im->channels; ch++) {
173 new_color = (int) rcolor.channel[ch];
176 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
178 new_color += color_inc;
184 if(new_color > 255) {
188 rcolor.channel[ch] = (unsigned char) new_color;
191 i_ppix(im, x, y, &rcolor);
197 =item i_noise(im, amount, type)
199 Inverts the pixel values by the amount specified.
202 amount - deviation in pixel values
203 type - noise individual for each channel if true
210 =item i_applyimage(im, add_im, mode)
212 Apply's an image to another image
215 add_im - image that is applied to target
216 mode - what method is used in applying:
236 void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
240 mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
242 mx = (add_im->xsize <= im->xsize) ? add_im->xsize : add_im->xsize;
243 my = (add_im->ysize <= im->ysize) ? add_im->ysize : add_im->ysize;
245 for(x = 0; x < mx; x++) {
246 for(y = 0; y < my; y++) {
253 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
255 Makes a bumpmap on image im using the bump image as the elevation map.
258 bump - image that contains the elevation info
259 channel - to take the elevation information from
260 light_x - x coordinate of light source
261 light_y - y coordinate of light source
262 st - length of shadow
268 i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
271 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
276 unsigned char px1, px2, py1, py2;
280 mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light_x %d, light_y %d, st %d)\n",
281 im, bump, channel, light_x, light_y, st));
284 if(channel >= bump->channels) {
285 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
289 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
290 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
292 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
294 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
295 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
297 aL = sqrt((aX * aX) + (aY * aY));
299 for(y = 1; y < my - 1; y++) {
300 for(x = 1; x < mx - 1; x++) {
301 i_gpix(bump, x + st, y, &x1_color);
302 i_gpix(bump, x, y + st, &y1_color);
303 i_gpix(bump, x - st, y, &x2_color);
304 i_gpix(bump, x, y - st, &y2_color);
306 i_gpix(im, x, y, &dst_color);
308 px1 = x1_color.channel[channel];
309 py1 = y1_color.channel[channel];
310 px2 = x2_color.channel[channel];
311 py2 = y2_color.channel[channel];
319 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
321 tX = abs(x - light_x) / aL;
322 tY = abs(y - light_y) / aL;
324 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
329 for(ch = 0; ch < im->channels; ch++)
330 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
332 i_ppix(&new_im, x, y, &dst_color);
336 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
338 i_img_exorcise(&new_im);
351 dotp(fvec *a, fvec *b) {
352 return a->x*b->x+a->y*b->y+a->z*b->z;
358 double d = sqrt(dotp(a,a));
372 I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
374 Here, the variables are:
376 * Ia - ambient colour
377 * Ip - intensity of the point light source
378 * cd - diffuse coefficient
379 * Scol - surface colour
380 * cs - specular coefficient
381 * n - objects shinyness
383 * L - lighting vector
384 * R - reflection vector
387 static void fvec_dump(fvec *x) {
388 printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
392 /* XXX: Should these return a code for success? */
398 =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
400 Makes a bumpmap on image im using the bump image as the elevation map.
403 bump - image that contains the elevation info
404 channel - to take the elevation information from
405 tx - shift in x direction of where to start applying bumpmap
406 ty - shift in y direction of where to start applying bumpmap
407 Lx - x position/direction of light
408 Ly - y position/direction of light
409 Lz - z position/direction of light
411 cd - diffuse coefficient
412 cs - specular coefficient
413 n - surface shinyness
418 if z<0 then the L is taken to be the direction the light is shining in. Otherwise
419 the L is taken to be the position of the Light, Relative to the image.
426 i_bumpmap_complex(i_img *im,
446 float cdc[MAXCHANNELS];
447 float csc[MAXCHANNELS];
449 i_color x1_color, y1_color, x2_color, y2_color;
451 i_color Scol; /* Surface colour */
453 fvec L; /* Light vector */
454 fvec N; /* surface normal */
455 fvec R; /* Reflection vector */
456 fvec V; /* Vision vector */
458 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",
459 im, bump, channel, tx, ty, Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
461 if (channel >= bump->channels) {
462 mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
466 for(ch=0; ch<im->channels; ch++) {
467 cdc[ch] = (float)Il->channel[ch]*cd/255.f;
468 csc[ch] = (float)Is->channel[ch]*cs/255.f;
480 if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
485 } else { /* Light is the position of the light source */
493 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
495 for(y = 0; y < im->ysize; y++) {
496 for(x = 0; x < im->xsize; x++) {
498 double dx = 0, dy = 0;
500 /* Calculate surface normal */
501 if (mx<x && x<Mx && my<y && y<My) {
502 i_gpix(bump, x + 1, y, &x1_color);
503 i_gpix(bump, x - 1, y, &x2_color);
504 i_gpix(bump, x, y + 1, &y1_color);
505 i_gpix(bump, x, y - 1, &y2_color);
506 dx = x2_color.channel[channel] - x1_color.channel[channel];
507 dy = y2_color.channel[channel] - y1_color.channel[channel];
517 /* Calculate Light vector if needed */
526 R.x = -L.x + 2*dp1*N.x;
527 R.y = -L.y + 2*dp1*N.y;
528 R.z = -L.z + 2*dp1*N.z;
532 dp1 = dp1<0 ?0 : dp1;
533 dp2 = pow(dp2<0 ?0 : dp2,n);
535 i_gpix(im, x, y, &Scol);
537 for(ch = 0; ch < im->channels; ch++)
539 saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
541 i_ppix(&new_im, x, y, &Scol);
545 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
546 i_img_exorcise(&new_im);
551 =item i_postlevels(im, levels)
553 Quantizes Images to fewer levels.
556 levels - number of levels
562 i_postlevels(i_img *im, int levels) {
570 rv = (int) ((float)(256 / levels));
573 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
574 i_gpix(im, x, y, &rcolor);
576 for(ch = 0; ch < im->channels; ch++) {
577 pv = (((float)rcolor.channel[ch] / 255)) * av;
578 pv = (int) ((int)pv * rv);
581 else if(pv > 255) pv = 255;
583 rcolor.channel[ch] = (unsigned char) pv;
585 i_ppix(im, x, y, &rcolor);
591 =item i_mosaic(im, size)
593 Makes an image looks like a mosaic with tilesize of size
602 i_mosaic(i_img *im, int size) {
610 sqrsize = size * size;
612 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
613 for(z = 0; z < 256; z++) col[z] = 0;
615 for(lx = 0; lx < size; lx++) {
616 for(ly = 0; ly < size; ly++) {
617 i_gpix(im, (x + lx), (y + ly), &rcolor);
619 for(ch = 0; ch < im->channels; ch++) {
620 col[ch] += rcolor.channel[ch];
625 for(ch = 0; ch < im->channels; ch++)
626 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
629 for(lx = 0; lx < size; lx++)
630 for(ly = 0; ly < size; ly++)
631 i_ppix(im, (x + lx), (y + ly), &rcolor);
638 =item i_watermark(im, wmark, tx, ty, pixdiff)
640 Applies a watermark to the target image
643 wmark - watermark image
644 tx - x coordinate of where watermark should be applied
645 ty - y coordinate of where watermark should be applied
646 pixdiff - the magnitude of the watermark, controls how visible it is
652 i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
656 int mx = wmark->xsize;
657 int my = wmark->ysize;
659 for(vx=0;vx<mx;vx++) for(vy=0;vy<my;vy++) {
661 i_gpix(im, tx+vx, ty+vy,&val );
662 i_gpix(wmark, vx, vy, &wval);
664 for(ch=0;ch<im->channels;ch++)
665 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
667 i_ppix(im,tx+vx,ty+vy,&val);
673 =item i_autolevels(im, lsat, usat, skew)
675 Scales and translates each color such that it fills the range completely.
676 Skew is not implemented yet - purpose is to control the color skew that can
677 occur when changing the contrast.
680 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
681 usat - fraction of pixels that will be truncated at the higher end of the spectrum
688 i_autolevels(i_img *im, float lsat, float usat, float skew) {
690 int i, x, y, rhist[256], ghist[256], bhist[256];
691 int rsum, rmin, rmax;
692 int gsum, gmin, gmax;
693 int bsum, bmin, bmax;
694 int rcl, rcu, gcl, gcu, bcl, bcu;
696 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
699 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
700 /* create histogram for each channel */
701 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
702 i_gpix(im, x, y, &val);
703 rhist[val.channel[0]]++;
704 ghist[val.channel[1]]++;
705 bhist[val.channel[2]]++;
714 rmin = gmin = bmin = 0;
715 rmax = gmax = bmax = 255;
717 rcu = rcl = gcu = gcl = bcu = bcl = 0;
719 for(i=0; i<256; i++) {
720 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
721 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
723 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
724 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
726 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
727 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
730 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
731 i_gpix(im, x, y, &val);
732 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
733 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
734 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
735 i_ppix(im, x, y, &val);
742 Pseudo noise utility function used to generate perlin noise. (internal)
752 Noise(int x, int y) {
755 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
759 =item SmoothedNoise1(x,y)
761 Pseudo noise utility function used to generate perlin noise. (internal)
771 SmoothedNoise1(float x, float y) {
772 float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
773 float sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
774 float center = Noise(x, y) / 4;
775 return corners + sides + center;
780 =item G_Interpolate(a, b, x)
782 Utility function used to generate perlin noise. (internal)
788 float C_Interpolate(float a, float b, float x) {
789 /* float ft = x * 3.1415927; */
791 float f = (1 - cos(ft)) * .5;
792 return a*(1-f) + b*f;
797 =item InterpolatedNoise(x, y)
799 Utility function used to generate perlin noise. (internal)
806 InterpolatedNoise(float x, float y) {
809 float fractional_X = x - integer_X;
811 float fractional_Y = y - integer_Y;
813 float v1 = SmoothedNoise1(integer_X, integer_Y);
814 float v2 = SmoothedNoise1(integer_X + 1, integer_Y);
815 float v3 = SmoothedNoise1(integer_X, integer_Y + 1);
816 float v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
818 float i1 = C_Interpolate(v1 , v2 , fractional_X);
819 float i2 = C_Interpolate(v3 , v4 , fractional_X);
821 return C_Interpolate(i1 , i2 , fractional_Y);
827 =item PerlinNoise_2D(x, y)
829 Utility function used to generate perlin noise. (internal)
836 PerlinNoise_2D(float x, float y) {
840 int Number_Of_Octaves=6;
841 int n = Number_Of_Octaves - 1;
846 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
854 =item i_radnoise(im, xo, yo, rscale, ascale)
856 Perlin-like radial noise.
859 xo - x coordinate of center
860 yo - y coordinate of center
861 rscale - radial scale
862 ascale - angular scale
868 i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
875 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
876 xc = (float)x-xo+0.5;
877 yc = (float)y-yo+0.5;
878 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
879 a = (PI+atan2(yc,xc))*ascale;
880 v = saturate(128+100*(PerlinNoise_2D(a,r)));
881 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
882 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
883 i_ppix(im, x, y, &val);
889 =item i_turbnoise(im, xo, yo, scale)
891 Perlin-like 2d noise noise.
894 xo - x coordinate translation
895 yo - y coordinate translation
896 scale - scale of noise
902 i_turbnoise(i_img *im, float xo, float yo, float scale) {
907 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
908 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
909 v = saturate(120*(1.0+sin(xo+(float)x/scale+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))));
910 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
911 i_ppix(im, x, y, &val);
918 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
920 Gradient generating function.
923 num - number of points given
924 xo - array of x coordinates
925 yo - array of y coordinates
926 ival - array of i_color objects
927 dmeasure - distance measure to be used.
929 1 = Euclidean squared
930 2 = Manhattan distance
937 i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
941 int channels = im->channels;
942 int xsize = im->xsize;
943 int ysize = im->ysize;
948 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
950 for(p = 0; p<num; p++) {
951 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
955 /* on the systems I have sizeof(float) == sizeof(int) and thus
956 this would be same size as the arrays xo and yo point at, but this
957 may not be true for other systems
959 since the arrays here are caller controlled, I assume that on
960 overflow is a programming error rather than an end-user error, so
961 calling exit() is justified.
963 bytes = sizeof(float) * num;
964 if (bytes / num != sizeof(float)) {
965 fprintf(stderr, "integer overflow calculating memory allocation");
968 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
970 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
973 for(p = 0; p<num; p++) {
977 case 0: /* euclidean */
978 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
980 case 1: /* euclidean squared */
981 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
983 case 2: /* euclidean squared */
984 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
987 i_fatal(3,"i_gradgen: Unknown distance measure\n");
992 csd = 1/((num-1)*cs);
994 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
996 for(ch = 0; ch<channels; ch++) {
998 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
999 val.channel[ch] = saturate(tres);
1001 i_ppix(im, x, y, &val);
1008 i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
1011 int xsize = im->xsize;
1012 int ysize = im->ysize;
1014 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
1016 for(p = 0; p<num; p++) {
1017 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
1021 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1030 case 0: /* euclidean */
1031 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1033 case 1: /* euclidean squared */
1034 mindist = xd*xd + yd*yd; /* euclidean distance */
1036 case 2: /* euclidean squared */
1037 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1040 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1043 for(p = 1; p<num; p++) {
1047 case 0: /* euclidean */
1048 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1050 case 1: /* euclidean squared */
1051 curdist = xd*xd + yd*yd; /* euclidean distance */
1053 case 2: /* euclidean squared */
1054 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1057 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1059 if (curdist < mindist) {
1064 i_ppix(im, x, y, &ival[midx]);
1069 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1071 This wasn't document - quoth Addi:
1073 An arty type of filter
1075 FIXME: check IRC logs for actual text.
1083 i_img *im - image to render on.
1087 int num - number of points/colors in xo, yo, oval
1091 int *xo - array of I<num> x positions
1095 int *yo - array of I<num> y positions
1099 i_color *oval - array of I<num> colors
1101 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1102 color something like oval[i], at least closer to that color than other
1107 int dmeasure - how we measure the distance from some point P(x,y) to
1116 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1120 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1124 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1128 An invalid value causes an error exit (the program is aborted).
1136 i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
1142 int xsize = im->xsize;
1143 int ysize = im->ysize;
1145 int ival_bytes, tval_bytes;
1147 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));
1152 i_push_error(0, "no points supplied to nearest_color filter");
1156 if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1157 i_push_error(0, "distance measure invalid");
1161 tval_bytes = sizeof(float)*num*im->channels;
1162 if (tval_bytes / num != sizeof(float) * im->channels) {
1163 i_push_error(0, "integer overflow calculating memory allocation");
1166 ival_bytes = sizeof(i_color) * num;
1167 if (ival_bytes / sizeof(i_color) != num) {
1168 i_push_error(0, "integer overflow calculating memory allocation");
1171 tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1172 ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1173 cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1175 for(p = 0; p<num; p++) {
1176 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1181 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1190 case 0: /* euclidean */
1191 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1193 case 1: /* euclidean squared */
1194 mindist = xd*xd + yd*yd; /* euclidean distance */
1196 case 2: /* manhatten distance */
1197 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1200 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1203 for(p = 1; p<num; p++) {
1207 case 0: /* euclidean */
1208 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1210 case 1: /* euclidean squared */
1211 curdist = xd*xd + yd*yd; /* euclidean distance */
1213 case 2: /* euclidean squared */
1214 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1217 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1219 if (curdist < mindist) {
1226 i_gpix(im, x, y, &val);
1227 c2 = 1.0/(float)(cmatch[midx]);
1230 for(ch = 0; ch<im->channels; ch++)
1231 tval[midx*im->channels + ch] =
1232 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1236 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++)
1237 ival[p].channel[ch] = tval[p*im->channels + ch];
1239 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1245 =item i_unsharp_mask(im, stddev, scale)
1247 Perform an usharp mask, which is defined as subtracting the blurred
1248 image from double the original.
1254 i_unsharp_mask(i_img *im, double stddev, double scale) {
1260 /* it really shouldn't ever be more than 1.0, but maybe ... */
1265 i_gaussian(copy, stddev);
1266 if (im->bits == i_8_bits) {
1267 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1268 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1270 for (y = 0; y < im->ysize; ++y) {
1271 i_glin(copy, 0, copy->xsize, y, blur);
1272 i_glin(im, 0, im->xsize, y, out);
1273 for (x = 0; x < im->xsize; ++x) {
1274 for (ch = 0; ch < im->channels; ++ch) {
1275 /*int temp = out[x].channel[ch] +
1276 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1277 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1280 else if (temp > 255)
1282 out[x].channel[ch] = temp;
1285 i_plin(im, 0, im->xsize, y, out);
1292 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1293 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1295 for (y = 0; y < im->ysize; ++y) {
1296 i_glinf(copy, 0, copy->xsize, y, blur);
1297 i_glinf(im, 0, im->xsize, y, out);
1298 for (x = 0; x < im->xsize; ++x) {
1299 for (ch = 0; ch < im->channels; ++ch) {
1300 double temp = out[x].channel[ch] +
1301 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1304 else if (temp > 1.0)
1306 out[x].channel[ch] = temp;
1309 i_plinf(im, 0, im->xsize, y, out);
1315 i_img_destroy(copy);
1319 =item i_diff_image(im1, im2, mindist)
1321 Creates a new image that is transparent, except where the pixel in im2
1322 is different from im1, where it is the pixel from im2.
1324 The samples must differ by at least mindiff to be considered different.
1330 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1332 int outchans, diffchans;
1336 if (im1->channels != im2->channels) {
1337 i_push_error(0, "different number of channels");
1341 outchans = diffchans = im1->channels;
1342 if (outchans == 1 || outchans == 3)
1345 xsize = i_min(im1->xsize, im2->xsize);
1346 ysize = i_min(im1->ysize, im2->ysize);
1348 out = i_sametype_chans(im1, xsize, ysize, outchans);
1350 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1351 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1352 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1355 int imindist = (int)mindist;
1357 for (ch = 0; ch < MAXCHANNELS; ++ch)
1358 empty.channel[ch] = 0;
1360 for (y = 0; y < ysize; ++y) {
1361 i_glin(im1, 0, xsize, y, line1);
1362 i_glin(im2, 0, xsize, y, line2);
1363 if (outchans != diffchans) {
1364 /* give the output an alpha channel since it doesn't have one */
1365 for (x = 0; x < xsize; ++x)
1366 line2[x].channel[diffchans] = 255;
1368 for (x = 0; x < xsize; ++x) {
1370 for (ch = 0; ch < diffchans; ++ch) {
1371 if (line1[x].channel[ch] != line2[x].channel[ch]
1372 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1380 i_plin(out, 0, xsize, y, line2);
1386 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1387 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1390 double dist = mindist / 255.0;
1392 for (ch = 0; ch < MAXCHANNELS; ++ch)
1393 empty.channel[ch] = 0;
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;
1403 for (x = 0; x < xsize; ++x) {
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) {
1415 i_plinf(out, 0, xsize, y, line2);
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);
1433 typedef double (*fount_func)(double, double, struct fount_state *);
1434 static fount_func fount_funcs[] =
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[] =
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[] =
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[] =
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[] =
1501 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1504 Keep state information used by each type of fountain fill
1506 struct fount_state {
1507 /* precalculated for the equation of the line perpendicular to the line AB */
1518 fount_repeat rpfunc;
1519 fount_ssample ssfunc;
1521 i_fountain_seg *segs;
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);
1532 fount_finish_state(struct fount_state *state);
1534 #define EPSILON (1e-6)
1537 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1539 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1541 I<type> controls how the reference points are used:
1547 linear, where A is 0 and B is 1.
1551 linear in both directions from A.
1555 circular, where A is the centre of the fill, and B is a point
1558 =item i_ft_radial_square
1560 where A is the centre of the fill and B is the centre of
1561 one side of the square.
1563 =item i_ft_revolution
1565 where A is the centre of the fill and B defines the 0/1.0
1570 similar to i_ft_revolution, except that the revolution goes in both
1575 I<repeat> can be one of:
1581 values < 0 are treated as zero, values > 1 are treated as 1.
1585 negative values are treated as 0, positive values are modulo 1.0
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.
1594 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1599 Like i_fr_triangle, except that negative values are handled as their
1604 If combine is non-zero then non-opaque values are combined with the
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:
1614 No super-sampling is done.
1618 A square grid of points withing the pixel are sampled.
1622 Random points within the pixel are sampled.
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
1632 I<ssample_param> is intended to be roughly the number of points
1633 sampled within the pixel.
1635 I<count> and I<segs> define the segments of the fill.
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;
1648 i_fcolor *line = NULL;
1649 i_fcolor *work = NULL;
1651 i_fountain_seg *my_segs;
1652 i_fill_combine_f combine_func = NULL;
1653 i_fill_combinef_f combinef_func = NULL;
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");
1665 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1667 i_get_combine(combine, &combine_func, &combinef_func);
1669 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1671 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1672 super_sample, ssample_param, count, segs);
1673 my_segs = state.segs;
1675 for (y = 0; y < im->ysize; ++y) {
1676 i_glinf(im, 0, im->xsize, y, line);
1677 for (x = 0; x < im->xsize; ++x) {
1680 if (super_sample == i_fts_none)
1681 got_one = fount_getat(&c, x, y, &state);
1683 got_one = state.ssfunc(&c, x, y, &state);
1692 combinef_func(line, work, im->channels, im->xsize);
1693 i_plinf(im, 0, im->xsize, y, line);
1695 fount_finish_state(&state);
1696 if (work) myfree(work);
1704 struct fount_state state;
1705 } i_fill_fountain_t;
1708 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
1711 fount_fill_destroy(i_fill_t *fill);
1714 =item i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1717 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1718 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1721 Creates a new general fill which fills with a fountain fill.
1727 i_new_fill_fount(double xa, double ya, double xb, double yb,
1728 i_fountain_type type, i_fountain_repeat repeat,
1729 int combine, int super_sample, double ssample_param,
1730 int count, i_fountain_seg *segs) {
1731 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1733 fill->base.fill_with_color = NULL;
1734 fill->base.fill_with_fcolor = fill_fountf;
1735 fill->base.destroy = fount_fill_destroy;
1737 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1739 fill->base.combine = NULL;
1740 fill->base.combinef = NULL;
1742 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1743 super_sample, ssample_param, count, segs);
1751 =head1 INTERNAL FUNCTIONS
1755 =item fount_init_state(...)
1757 Used by both the fountain fill filter and the fountain fill.
1763 fount_init_state(struct fount_state *state, double xa, double ya,
1764 double xb, double yb, i_fountain_type type,
1765 i_fountain_repeat repeat, int combine, int super_sample,
1766 double ssample_param, int count, i_fountain_seg *segs) {
1769 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1770 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1772 memset(state, 0, sizeof(*state));
1773 /* we keep a local copy that we can adjust for speed */
1774 for (i = 0; i < count; ++i) {
1775 i_fountain_seg *seg = my_segs + i;
1778 if (seg->type < 0 || seg->type >= i_fst_end)
1779 seg->type = i_fst_linear;
1780 if (seg->color < 0 || seg->color >= i_fc_end)
1781 seg->color = i_fc_direct;
1782 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1783 /* so we don't have to translate to HSV on each request, do it here */
1784 for (j = 0; j < 2; ++j) {
1785 i_rgb_to_hsvf(seg->c+j);
1787 if (seg->color == i_fc_hue_up) {
1788 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1789 seg->c[1].channel[0] += 1.0;
1792 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1793 seg->c[0].channel[0] += 1.0;
1796 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1797 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1798 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1799 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1800 seg->c[1].channel[3], seg->type, seg->color);*/
1804 /* initialize each engine */
1805 /* these are so common ... */
1806 state->lA = xb - xa;
1807 state->lB = yb - ya;
1808 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1813 type = i_ft_linear; /* make the invalid value valid */
1816 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1818 state->mult = 1/linear_fount_f(xb, yb, state);
1822 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1823 + (double)(yb-ya)*(yb-ya));
1826 case i_ft_radial_square:
1827 state->cos = state->lA / state->AB;
1828 state->sin = state->lB / state->AB;
1829 state->mult = 1.0 / state->AB;
1832 case i_ft_revolution:
1833 state->theta = atan2(yb-ya, xb-xa);
1834 state->mult = 1.0 / (PI * 2);
1838 state->theta = atan2(yb-ya, xb-xa);
1839 state->mult = 1.0 / PI;
1842 state->ffunc = fount_funcs[type];
1843 if (super_sample < 0
1844 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1847 state->ssample_data = NULL;
1848 switch (super_sample) {
1850 ssample_param = floor(0.5 + sqrt(ssample_param));
1851 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1852 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1853 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1856 super_sample = i_fts_none;
1862 ssample_param = floor(0.5+ssample_param);
1863 bytes = sizeof(i_fcolor) * ssample_param;
1864 if (bytes / sizeof(i_fcolor) == ssample_param) {
1865 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1868 super_sample = i_fts_none;
1872 state->parm = ssample_param;
1873 state->ssfunc = fount_ssamples[super_sample];
1874 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1876 state->rpfunc = fount_repeats[repeat];
1877 state->segs = my_segs;
1878 state->count = count;
1882 fount_finish_state(struct fount_state *state) {
1883 if (state->ssample_data)
1884 myfree(state->ssample_data);
1885 myfree(state->segs);
1890 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1892 Evaluates the fountain fill at the given point.
1894 This is called by both the non-super-sampling and super-sampling code.
1896 You might think that it would make sense to sample the fill parameter
1897 instead, and combine those, but this breaks badly.
1903 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1904 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1908 while (i < state->count
1909 && (v < state->segs[i].start || v > state->segs[i].end)) {
1912 if (i < state->count) {
1913 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1914 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1922 =item linear_fount_f(x, y, state)
1924 Calculate the fill parameter for a linear fountain fill.
1926 Uses the point to line distance function, with some precalculation
1927 done in i_fountain().
1932 linear_fount_f(double x, double y, struct fount_state *state) {
1933 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1937 =item bilinear_fount_f(x, y, state)
1939 Calculate the fill parameter for a bi-linear fountain fill.
1944 bilinear_fount_f(double x, double y, struct fount_state *state) {
1945 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1949 =item radial_fount_f(x, y, state)
1951 Calculate the fill parameter for a radial fountain fill.
1953 Simply uses the distance function.
1958 radial_fount_f(double x, double y, struct fount_state *state) {
1959 return sqrt((double)(state->xa-x)*(state->xa-x)
1960 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1964 =item square_fount_f(x, y, state)
1966 Calculate the fill parameter for a square fountain fill.
1968 Works by rotating the reference co-ordinate around the centre of the
1974 square_fount_f(double x, double y, struct fount_state *state) {
1975 int xc, yc; /* centred on A */
1976 double xt, yt; /* rotated by theta */
1979 xt = fabs(xc * state->cos + yc * state->sin);
1980 yt = fabs(-xc * state->sin + yc * state->cos);
1981 return (xt > yt ? xt : yt) * state->mult;
1985 =item revolution_fount_f(x, y, state)
1987 Calculates the fill parameter for the revolution fountain fill.
1992 revolution_fount_f(double x, double y, struct fount_state *state) {
1993 double angle = atan2(y - state->ya, x - state->xa);
1995 angle -= state->theta;
1997 angle = fmod(angle+ PI * 4, PI*2);
2000 return angle * state->mult;
2004 =item conical_fount_f(x, y, state)
2006 Calculates the fill parameter for the conical fountain fill.
2011 conical_fount_f(double x, double y, struct fount_state *state) {
2012 double angle = atan2(y - state->ya, x - state->xa);
2014 angle -= state->theta;
2017 else if (angle > PI)
2020 return fabs(angle) * state->mult;
2024 =item linear_interp(pos, seg)
2026 Calculates linear interpolation on the fill parameter. Breaks the
2027 segment into 2 regions based in the I<middle> value.
2032 linear_interp(double pos, i_fountain_seg *seg) {
2033 if (pos < seg->middle) {
2034 double len = seg->middle - seg->start;
2038 return (pos - seg->start) / len / 2;
2041 double len = seg->end - seg->middle;
2045 return 0.5 + (pos - seg->middle) / len / 2;
2050 =item sine_interp(pos, seg)
2052 Calculates sine function interpolation on the fill parameter.
2057 sine_interp(double pos, i_fountain_seg *seg) {
2058 /* I wonder if there's a simple way to smooth the transition for this */
2059 double work = linear_interp(pos, seg);
2061 return (1-cos(work * PI))/2;
2065 =item sphereup_interp(pos, seg)
2067 Calculates spherical interpolation on the fill parameter, with the cusp
2073 sphereup_interp(double pos, i_fountain_seg *seg) {
2074 double work = linear_interp(pos, seg);
2076 return sqrt(1.0 - (1-work) * (1-work));
2080 =item spheredown_interp(pos, seg)
2082 Calculates spherical interpolation on the fill parameter, with the cusp
2088 spheredown_interp(double pos, i_fountain_seg *seg) {
2089 double work = linear_interp(pos, seg);
2091 return 1-sqrt(1.0 - work * work);
2095 =item direct_cinterp(out, pos, seg)
2097 Calculates the fountain color based on direct scaling of the channels
2098 of the color channels.
2103 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2105 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2106 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2107 + seg->c[1].channel[ch] * pos;
2112 =item hue_up_cinterp(put, pos, seg)
2114 Calculates the fountain color based on scaling a HSV value. The hue
2115 increases as the fill parameter increases.
2120 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2122 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2123 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2124 + seg->c[1].channel[ch] * pos;
2130 =item hue_down_cinterp(put, pos, seg)
2132 Calculates the fountain color based on scaling a HSV value. The hue
2133 decreases as the fill parameter increases.
2138 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2140 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2141 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2142 + seg->c[1].channel[ch] * pos;
2148 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2150 Simple grid-based super-sampling.
2155 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2156 i_fcolor *work = state->ssample_data;
2158 int grid = state->parm;
2159 double base = -0.5 + 0.5 / grid;
2160 double step = 1.0 / grid;
2164 for (dx = 0; dx < grid; ++dx) {
2165 for (dy = 0; dy < grid; ++dy) {
2166 if (fount_getat(work+samp_count, x + base + step * dx,
2167 y + base + step * dy, state)) {
2172 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2173 out->channel[ch] = 0;
2174 for (i = 0; i < samp_count; ++i) {
2175 out->channel[ch] += work[i].channel[ch];
2177 /* we divide by 4 rather than samp_count since if there's only one valid
2178 sample it should be mostly transparent */
2179 out->channel[ch] /= grid * grid;
2185 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2187 Random super-sampling.
2192 random_ssample(i_fcolor *out, double x, double y,
2193 struct fount_state *state) {
2194 i_fcolor *work = state->ssample_data;
2196 int maxsamples = state->parm;
2197 double rand_scale = 1.0 / RAND_MAX;
2199 for (i = 0; i < maxsamples; ++i) {
2200 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2201 y - 0.5 + rand() * rand_scale, state)) {
2205 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2206 out->channel[ch] = 0;
2207 for (i = 0; i < samp_count; ++i) {
2208 out->channel[ch] += work[i].channel[ch];
2210 /* we divide by maxsamples rather than samp_count since if there's
2211 only one valid sample it should be mostly transparent */
2212 out->channel[ch] /= maxsamples;
2218 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2220 Super-sampling around the circumference of a circle.
2222 I considered saving the sin()/cos() values and transforming step-size
2223 around the circle, but that's inaccurate, though it may not matter
2229 circle_ssample(i_fcolor *out, double x, double y,
2230 struct fount_state *state) {
2231 i_fcolor *work = state->ssample_data;
2233 int maxsamples = state->parm;
2234 double angle = 2 * PI / maxsamples;
2235 double radius = 0.3; /* semi-random */
2237 for (i = 0; i < maxsamples; ++i) {
2238 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2239 y + radius * sin(angle * i), state)) {
2243 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2244 out->channel[ch] = 0;
2245 for (i = 0; i < samp_count; ++i) {
2246 out->channel[ch] += work[i].channel[ch];
2248 /* we divide by maxsamples rather than samp_count since if there's
2249 only one valid sample it should be mostly transparent */
2250 out->channel[ch] /= maxsamples;
2256 =item fount_r_none(v)
2258 Implements no repeats. Simply clamps the fill value.
2263 fount_r_none(double v) {
2264 return v < 0 ? 0 : v > 1 ? 1 : v;
2268 =item fount_r_sawtooth(v)
2270 Implements sawtooth repeats. Clamps negative values and uses fmod()
2276 fount_r_sawtooth(double v) {
2277 return v < 0 ? 0 : fmod(v, 1.0);
2281 =item fount_r_triangle(v)
2283 Implements triangle repeats. Clamps negative values, uses fmod to get
2284 a range 0 through 2 and then adjusts values > 1.
2289 fount_r_triangle(double v) {
2294 return v > 1.0 ? 2.0 - v : v;
2299 =item fount_r_saw_both(v)
2301 Implements sawtooth repeats in the both postive and negative directions.
2303 Adjusts the value to be postive and then just uses fmod().
2308 fount_r_saw_both(double v) {
2311 return fmod(v, 1.0);
2315 =item fount_r_tri_both(v)
2317 Implements triangle repeats in the both postive and negative directions.
2319 Uses fmod on the absolute value, and then adjusts values > 1.
2324 fount_r_tri_both(double v) {
2325 v = fmod(fabs(v), 2.0);
2326 return v > 1.0 ? 2.0 - v : v;
2330 =item fill_fountf(fill, x, y, width, channels, data)
2332 The fill function for fountain fills.
2337 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
2339 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2345 if (f->state.ssfunc)
2346 got_one = f->state.ssfunc(&c, x, y, &f->state);
2348 got_one = fount_getat(&c, x, y, &f->state);
2357 =item fount_fill_destroy(fill)
2362 fount_fill_destroy(i_fill_t *fill) {
2363 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2364 fount_finish_state(&f->state);
2372 Arnar M. Hrafnkelsson <addi@umich.edu>
2374 Tony Cook <tony@develop-help.com> (i_fountain())