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