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