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